dplyr - 像rowmeans一样使用mutate()

问题描述 投票:18回答:5

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

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

例如:

data <- data.frame(id=c(101,102,103), a=c(1,2,3), b=c(2,2,2), c=c(3,3,3))

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

而且当然

mutate(data, c=mean(a,b)) 

要么

mutate(data, c=rowMeans(a,b)) 

不起作用。

你能给我一些小费吗?

问候

r dplyr
5个回答
23
投票

您正在寻找

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

要么

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

10
投票

dplyr非常适合对这种数据进行操作,因为它采用tidy data格式,并且 - 对于有问题的问题 - 您的数据是不整洁的。

你当然可以先整理一下:

tidy_data = tidyr::gather(data, name, value, -id)

看起来像这样:

   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
    …

然后:

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

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

tidy_data %>%
    group_by(id) %>%
    mutate(mean = mean(value)) %>%
    tidyr::spread(name, value)
     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

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

tidy_data %>%
    group_by(id) %>%
    summarize(mean = mean(value)) %>%
    inner_join(data, by = 'id')

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


4
投票

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

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

由于rowMeans需要类似矩阵或data.frame的东西,你可以使用data.frame(var1, var2, ...)而不是c(var1, var2, ...)。如果您的数据中有NA,则需要告诉R要做什么,例如删除它们:rowMeans(data.frame(a,b), na.rm=TRUE)


3
投票

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

my_rowmeans = function(...) Reduce(`+`, list(...))/length(list(...))

然后,它可以在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

为了处理NAs的可能性,该函数必须被uglified:

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

my_rowmeans2的缺点是它强迫矩阵。但我不确定这总是比Reduce方法慢。


3
投票

还有另外两种方法,如果你有要汇总的列的数字位置或矢量名称,这将非常有用:

data %>% mutate(d = rowMeans(.[, 2:4]))

要么

data %>% mutate(d = rowMeans(.[, c("a","b","c")]))
© www.soinside.com 2019 - 2024. All rights reserved.