dplyr - 像rowmeans一样使用mutate()

Tom*_*tas 26 r dplyr

我无法在任何地方找到答案.

我想计算基于行的平均值的数据帧的新变量.

例如:

data <- data.frame(id=c(101,102,103), a=c(1,2,3), b=c(2,2,2), c=c(3,3,3))
Run Code Online (Sandbox Code Playgroud)

我想使用mutate来创建变量d,它是a,b和c的意思.我希望能够通过选择d = mean(a,b,c)的方式来实现这一点,并且我还需要使用变量范围(例如dplyr)d = mean(a:c).

而且当然

mutate(data, c=mean(a,b)) 
Run Code Online (Sandbox Code Playgroud)

要么

mutate(data, c=rowMeans(a,b)) 
Run Code Online (Sandbox Code Playgroud)

不起作用.

你能给我一些小费吗?

问候

Mat*_*rde 28

您正在寻找

data %>% 
    rowwise() %>% 
    mutate(c=mean(c(a,b)))

#      id     a     b     c
#   (dbl) (dbl) (dbl) (dbl)
# 1   101     1     2   1.5
# 2   102     2     2   2.0
# 3   103     3     2   2.5
Run Code Online (Sandbox Code Playgroud)

要么

library(purrr)
data %>% 
    rowwise() %>% 
    mutate(c=lift_vd(mean)(a,b))
Run Code Online (Sandbox Code Playgroud)

  • 啊.一点也不差.不幸的是,'rowwise`的文档很糟糕("`rowwise`在某些情况下做了一些事情.这是一个不能概括的单个特例的不必要的例子.")所以我最终从不使用它.:-( (4认同)

Kon*_*lph 13

dplyr非常适合对这类数据进行操作,因为它假设数据格式整洁,并且 - 对于有问题的问题 - 您的数据是不整洁的.

你当然可以先整理一下:

tidy_data = tidyr::gather(data, name, value, -id)
Run Code Online (Sandbox Code Playgroud)

看起来像这样:

   id name value
1 101    a     1
2 102    a     2
3 103    a     3
4 101    b     2
5 102    b     2
6 103    b     2
    …
Run Code Online (Sandbox Code Playgroud)

然后:

tidy_data %>% group_by(id) %>% summarize(mean = mean(value))
Run Code Online (Sandbox Code Playgroud)
    name  mean
  (fctr) (dbl)
1      a     2
2      b     2
3      c     3
Run Code Online (Sandbox Code Playgroud)

当然,这会丢弃原始数据.您可以使用mutate而不是summarize避免这种情况.最后,您可以再次整理数据:

tidy_data %>%
    group_by(id) %>%
    mutate(mean = mean(value)) %>%
    tidyr::spread(name, value)
Run Code Online (Sandbox Code Playgroud)
     id     mean     a     b     c
  (dbl)    (dbl) (dbl) (dbl) (dbl)
1   101 2.000000     1     2     3
2   102 2.333333     2     2     3
3   103 2.666667     3     2     3
Run Code Online (Sandbox Code Playgroud)

或者,您可以汇总,然后将结果与原始表合并:

tidy_data %>%
    group_by(id) %>%
    summarize(mean = mean(value)) %>%
    inner_join(data, by = 'id')
Run Code Online (Sandbox Code Playgroud)

在任何一种情况下结果都是相同的.我在概念上更喜欢第二种变体.


bjw*_*bjw 9

我认为建议使用data.frame或切片的答案.是最好的,但可以做得更简单,更像这样:

data %>% mutate(c = rowMeans(select(., a,b)))
Run Code Online (Sandbox Code Playgroud)

或者,如果您想避免.,则有两个输入到您的管道的惩罚:

data %>% mutate(c = rowMeans(select(data, a,b)))
Run Code Online (Sandbox Code Playgroud)


Fra*_*ank 5

我认为这是 dplyr 式的方式。首先,我创建一个函数:

my_rowmeans = function(...) Reduce(`+`, list(...))/length(list(...))
Run Code Online (Sandbox Code Playgroud)

然后,它可以在 mutate 中使用:

data %>% mutate(rms = my_rowmeans(a, b))

#    id a b c rms
# 1 101 1 2 3 1.5
# 2 102 2 2 3 2.0
# 3 103 3 2 3 2.5

# or

data %>% mutate(rms = my_rowmeans(a, b, c))

#    id a b c      rms
# 1 101 1 2 3 2.000000
# 2 102 2 2 3 2.333333
# 3 103 3 2 3 2.666667
Run Code Online (Sandbox Code Playgroud)

为了处理 的可能性NAs,必须对该函数进行丑化:

my_rowmeans = function(..., na.rm=TRUE){
  x = 
    if (na.rm) lapply(list(...), function(x) replace(x, is.na(x), as(0, class(x)))) 
    else       list(...)

  d = Reduce(function(x,y) x+!is.na(y), list(...), init=0)

  Reduce(`+`, x)/d
} 

# alternately...

my_rowmeans2 = function(..., na.rm=TRUE) rowMeans(cbind(...), na.rm=na.rm)

# new example

data$b[2] <- NA  
data %>% mutate(rms = my_rowmeans(a,b,na.rm=FALSE))

   id a  b c rms
1 101 1  2 3 1.5
2 102 2 NA 3  NA
3 103 3  2 3 2.5

data %>% mutate(rms = my_rowmeans(a,b))

   id a  b c rms
1 101 1  2 3 1.5
2 102 2 NA 3 2.0
3 103 3  2 3 2.5
Run Code Online (Sandbox Code Playgroud)

的缺点my_rowmeans2是它强制为矩阵。不过,我不确定这是否总是比Reduce方法慢。


j_5*_*der 5

很少代码的另一个简单可能性是:

data %>%
    mutate(c= rowMeans(data.frame(a,b)))

 #     id a b   c
 #  1 101 1 2 1.5
 #  2 102 2 2 2.0
 #  3 103 3 2 2.5
Run Code Online (Sandbox Code Playgroud)

由于rowMeans需要类似矩阵或data.frame的内容,因此可以使用data.frame(var1, var2, ...)代替c(var1, var2, ...)。如果您的数据中包含NA,则需要告诉R怎么做,例如删除它们:rowMeans(data.frame(a,b), na.rm=TRUE)


JWi*_*man 5

还有另外两种方法,如果您具有要汇总的列的数字位置或矢量名称,则很有用:

data %>% mutate(d = rowMeans(.[, 2:4]))
Run Code Online (Sandbox Code Playgroud)

要么

data %>% mutate(d = rowMeans(.[, c("a","b","c")]))
Run Code Online (Sandbox Code Playgroud)

  • 这是最好的解决方案,但通过在管道输入的数据帧上使用 select 可以变得更简单。已添加答案。 (2认同)