R:使用dplyr进行逐行计算

时间:2017-12-13 16:22:20

标签: r dataframe dplyr

我有一个矢量:

vec <- c(44,0,13,18,32,13,25,42,13,24)

我想按如下方式计算fT:

fT <- ifelse(vec >= 10 & vec <= 20, min(vec) - max(vec), 
         ifelse(vec > 20 & vec <= 50, max(vec) - min(vec),0))

我想为数据帧的每一行扩展此计算,即 我有一个数据帧,我想计算每一行的fT。

示例数据:

dat <- data.frame(replicate(10,sample(0:50,1000,rep=TRUE)))

这意味着我将拥有另一个数据帧,该数据帧将具有dat中每个值的fT值。

要计算每行的fT,我想到了dplyr

dat%>%
  rowwise()%>%
   mutate(fT = ifelse(dat[,1:10] >= 10 & dat[,1:10] <= 30, min(dat[,1:10]) - max(dat[,1:10]), 
                  ifelse(dat[,1:10] > 30 & dat[,1:10] <= 50, max(dat[,1:10]) - min(dat[,1:10]),0)))

我被困在这个阶段。我不知道如何按列索引,以便dat的每一行都有一个 fT

2 个答案:

答案 0 :(得分:4)

如果您想要fT总和,可以使用apply执行此操作:

dat$fT = apply(dat, 1, function(x) sum(ifelse(x >= 10 & x <= 20, min(x) - max(x), 
                                              ifelse(x > 20 & x <= 50, max(x) - min(x),0))))

<强>结果:

  X1 X2 X3 X4 X5 X6 X7 X8 X9 X10  fT
1 14 13  8 10 15 12 22 47 29  40 -39
2 40 30  7 48 42 50 20 30 24  44 301
3 20  8  7 19 30 36 18  4 37  12 -33
4 45 43 26 31 41 33 26 43 11  28 272
5 47 43 25  9 14 12  3  1 38  46 138
6  2 24 31 33  7  4 36 41 42   0 252

注意:

1中的

apply指定行边距。这会循环输入行dat,并为每行输出一个fT的总和。

修改

如果您确实需要fT的值(而不是总和),您仍然可以使用apply,但请使用matrix包装输出并指定ncol=10和{ {1}}。这意味着您需要一个包含10列的输出矩阵(就像byrow=TRUE一样)并使用dat的输出逐行填充矩阵:

apply

<强>结果:

new_dat = matrix(apply(dat, 1, 
                       function(x) ifelse(x >= 10 & x <= 20, min(x) - max(x), 
                                          ifelse(x > 20 & x <= 50, max(x) - min(x),0))),
                 ncol = 10, byrow = TRUE)

如果您更喜欢坚持> head(new_dat) [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [1,] -39 -39 0 -39 -39 -39 39 39 39 39 [2,] 43 43 0 43 43 43 -43 43 43 43 [3,] -33 0 0 -33 33 33 -33 0 33 -33 [4,] 34 34 34 34 34 34 34 34 -34 34 [5,] 46 46 46 0 -46 -46 0 0 46 46 [6,] 0 42 42 42 0 0 42 42 42 0 ,则可以先dplyr transpose dat {&#34;列&#34;},然后{{1}回复:

map

<强>结果:

transpose

注意:

在Base R中使用library(dplyr) library(purrr) dat %>% transpose() %>% map_dfr(~ ifelse(. >= 10 & . <= 20, min(.) - max(.), ifelse(. > 20 & . <= 50, max(.) - min(.),0))) %>% transpose() 代替> head(new_dat2) V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 1 -39 -39 0 -39 -39 -39 39 39 39 39 2 43 43 0 43 43 43 -43 43 43 43 3 -33 0 0 -33 33 33 -33 0 33 -33 4 34 34 34 34 34 34 34 34 -34 34 5 46 46 46 0 -46 -46 0 0 46 46 6 0 42 42 42 0 0 42 42 42 0 的好处是,您可以在转置而不是矩阵后获得data.frame。

数据:

transpose

答案 1 :(得分:0)

以下是pmax/pmin的一个选项,效率很高

m1 <- (do.call(pmax, dat) - do.call(pmin, dat))[row(dat)] 
out <-  (-1*m1 *(dat >=10 & dat <=20)) +   (m1*(dat > 20 & dat <=50))
all.equal(new_dat, out, check.attributes = FALSE)   
#[1] TRUE

基准

set.seed(24)
dat <- data.frame(replicate(500,sample(0:50,15000,rep=TRUE)))

system.time({
new_dat = matrix(apply(dat, 1, 
                       function(x) ifelse(x >= 10 & x <= 20, min(x) - max(x), 
                                          ifelse(x > 20 & x <= 50, max(x) - min(x),0))),
                 ncol =  ncol(dat), byrow = TRUE)
  })
#user  system elapsed 
#   2.67    0.10    2.77 
system.time({
   m1 <- (do.call(pmax, dat) - do.call(pmin, dat))[row(dat)] 
   out <-  (-1*m1 *(dat >=10 & dat <=20)) +   (m1*(dat > 20 & dat <=50))
 })
#  user  system elapsed 
#   0.48    0.11    0.60 


#all.equal(new_dat, out, check.attributes = FALSE)   
#[1] TRUE