基于分组对多列中的DataFrame和平均行进行分组,忽略零

时间:2014-09-09 21:12:56

标签: r dplyr

我的数据框data如下所示:

Week  Group   Cost   Revenue
Wk1   A       104    148
Wk1   A       0      159
Wk1   A       92     151
Wk1   A       113    144
Wk1   B       331    500
WK1   B       325    524
Wk1   B       363    488
Wk1   B       0      497
Wk2   A       132    0
.
.
.

这是我用来从无序的csv文件到达的R代码:

library(dplyr)
d <- read.csv(...)
data <- tbl_df(d)
data <- arrange(data, Group, Week)

我需要根据数据框所属的组和周来平均数据框的“成本”和“收入”列中的值。

例如,我想要第1周A组的平均收入和成本。

结果值看起来像(我不确定格式,只显示我应该得到的值):

Week  Group   Avg Cost   Avg Revenue
Wk1   A       103        150.5
Wk1   B       339.6      502.25
.
.
.

问题: 如何按照组和他们的周对我的列进行平均,以便获得上述所需的结果?我想使用dplyr包来执行此操作。

的问题:
我的一些行有零。我不想平均零(所以不是(104 + 0 + 92 + 113)/4而是忽略它们(104 + 92 + 113)/3)。我不能简单filter()出零的行,因为我的Cost或Revenue列中只有一个零而不是两者都有。

我知道我可以使用summarize()mean()进行平均,但不知道如何按照我需要的方式对手段进行分组,并在计算中忽略零。

谢谢!

3 个答案:

答案 0 :(得分:4)

我以为我会添加 dplyr 答案。

首先,您可以在summarise内执行此操作,使用提取函数(Cost)分别从Revenue[删除任何0值。

require(dplyr)

dat %>% group_by(Week, Group) %>%
    summarise(Cost = mean(Cost[Cost > 0]), Revenue = mean(Revenue[Revenue > 0]))

就打字效率而言,summarise_each是另一个有用的选项,在这种情况下你想在多个列上使用相同的功能。在您使用.时,您可以利用mean编码从每个数字变量中删除任何0值。

dat %>% group_by(Week, Group) %>%
    summarise_each(funs(mean(.[. > 0])))

答案 1 :(得分:1)

您可以使用data.table包。它实际上是100倍更快,更直观。

您可以使用fread函数将csv文件读取到data.tables。但这只是一个例子

DT = data.table(Week = c("wk1","wk2"),  Group = c("A","B","C","D"),   Cost = sample(1:49,30,replace=F),   Revenue = sample(1:49,10,replace=F))
#    Week Group Cost Revenue
# 1:  wk1     A   33      37
# 2:  wk2     B   17      28
# 3:  wk1     C   13       6
# 4:  wk2     D   39      25
# 5:  wk1     A   15       3
# 6:  wk2     B   34       8
# 7:  wk1     C    2      12
# 8:  wk2     D    9      11
# 9:  wk1     A   48      18
#10:  wk2     B   25      29
#11:  wk1     C   46      37
#12:  wk2     D   11      28
#13:  wk1     A   22       6
#14:  wk2     B    6      25
#15:  wk1     C   26       3
#16:  wk2     D   40       8
#17:  wk1     A   27      12
#18:  wk2     B   23      11
#19:  wk1     C   43      18
#20:  wk2     D   24      29
#21:  wk1     A   21      37
#22:  wk2     B   29      28
#23:  wk1     C   31       6
#24:  wk2     D    8      25
#25:  wk1     A   36       3
#26:  wk2     B    5       8
#27:  wk1     C    1      12
#28:  wk2     D   19      11
#29:  wk1     A    4      18
#30:  wk2     B   44      29
#    Week Group Cost Revenue

在以下行中,您应该定义哪些列用于分组;在这里我使用c("Week", "Group")

DT[,list(Avg_Cost = mean(Cost),Avg_Revenue = mean(Revenue)),by = c("Week", "Group")]

enter image description here

查看数据表包手册以获取更多信息:http://cran.r-project.org/web/packages/data.table/index.html

要在mean功能中忽略零,您可以将其替换为nzmean。请参阅此帖:How can I calculate the means of rows while excluding the zero values from rows in data frame

nzmean <- function(x) {
   zvals <- x==0
   if (all(zvals)) 0 else mean(x[!zvals])
}

所以答案是:

DT[,list(Avg_Cost = nzmean(Cost),Avg_Revenue = nzmean(Revenue)),by = c("Week", "Group")]

答案 2 :(得分:0)

没有任何额外包裹的解决方案:

# Define a non-zero means function
nzmean <- function(x) {
  zvals <- x==0
  if (all(zvals)) 0 else mean(x[!zvals])
}

然后使用tapply,考虑名为df

的data.frame
tapply(df$Cost,list(df$Week,df$Group),nzmean )