dplyr:汇总未知数量的列?

dplyr:汇总未知数量的列?,r,dplyr,R,Dplyr,我希望能够总结一个分组的数据帧,在这个数据帧中,我并不总是知道会出现哪些变量,但我确实知道如何总结每个变量(如果存在) 假设我有这样一个数据帧: df <- data.frame(id = c(rep('a', 5), rep('b', 8), rep('c', 4)), var1 = round(runif(17) * 10, 3), var2 = sample(c(1:4), 17, replace = TRUE),

我希望能够总结一个分组的数据帧,在这个数据帧中,我并不总是知道会出现哪些变量,但我确实知道如何总结每个变量(如果存在)

假设我有这样一个数据帧:

df <- data.frame(id = c(rep('a', 5), rep('b', 8), rep('c', 4)),
                 var1 = round(runif(17) * 10, 3),
                 var2 = sample(c(1:4), 17, replace = TRUE),
                 var4 = sample(1:1000, 17))
> df

   id  var1 var2 var4
1   a 5.930    4  360
2   a 7.265    2  713
3   a 3.704    3  117
4   a 5.149    2  782
5   a 3.777    2  640
6   b 4.183    2  802
7   b 0.107    2  638
8   b 5.323    4  327
9   b 4.322    2  631
10  b 0.937    3  921
11  b 5.558    2  570
12  b 5.902    4  363
13  b 0.671    3  432
14  c 0.475    1  845
15  c 1.562    3  620
16  c 4.464    2  997
17  c 1.714    2  714
但是,由于var3不存在,我得到一个错误:medianvar3中的错误:找不到对象“var3”

凭直觉,我会尝试以下方法:

result <- df %>% group_by(id) %>%
  summarize(if('var1' %in% names(df)) var1 = mean(var1) else NULL,
            if('var2' %in% names(df)) var2 = median(var2) else NULL,
            if('var3' %in% names(df)) var3 = median(var3) else NULL,
            if('var4' %in% names(df)) var4 = max(var4) else NULL)
但很明显,这是行不通的,或者我的直觉有点不对劲


有人对我如何使用dplyr干净地完成这项任务有什么建议吗?正如您可能猜到的,df实际上是一个包含许多列的大型数据帧,而var3是可能缺少的任何列之一。

这不是确切的解决方案,但如果您不想像@joran建议的那样预先创建所有可能的列,这可能是一个解决方法。它将首先创建您指定的所有列,但其中一些列仅为NA。之后,您可以使用apply删除列。但是请注意,当在dplyr链中使用namesdd时,它只识别输入data.frame中的列名,而不是在同一操作中创建的列名

dd <- dd %>% 
  group_by(id) %>%
  summarize(var1 = ifelse("var1" %in% names(dd), mean(var1), NA),
            var2 = ifelse("var2" %in% names(dd), max(var2), NA))  

dd <- dd[,apply(dd, 2, function(x) ifelse(all(is.na(x)), FALSE, TRUE))]

另一种可能的解决方法是使用summary_each函数,但我认为这取决于您是否想要,例如,所有列的平均值、中位数和最大值。

这并不完全是解决方案,但如果您不想像@joran建议的那样预先创建所有可能的列,这可能是一种解决方法。它将首先创建您指定的所有列,但其中一些列仅为NA。之后,您可以使用apply删除列。但是请注意,当在dplyr链中使用namesdd时,它只识别输入data.frame中的列名,而不是在同一操作中创建的列名

dd <- dd %>% 
  group_by(id) %>%
  summarize(var1 = ifelse("var1" %in% names(dd), mean(var1), NA),
            var2 = ifelse("var2" %in% names(dd), max(var2), NA))  

dd <- dd[,apply(dd, 2, function(x) ifelse(all(is.na(x)), FALSE, TRUE))]

另一种可能的解决方法是使用Summary_each函数,但我认为这取决于您是否需要,例如,所有列的平均值、中值和最大值。

我认为您可以通过以下几个步骤完成:

使用melt从宽转换为长 使用dplyr进行总结 使用dcast从长到宽转换 例如:

tmp <- melt(df, id.vars="id")

tmp <- tmp %>%
  group_by(id, variable) %>%
  summarise(mean = mean(value), median = median(value), max = max(value))

tmp <- melt(tmp, id.vars=c("id", "variable"), variable.name="stat")

tmp <- dcast(tmp, id ~ stat + variable)

我必须添加一个额外的步骤,因为您需要不同变量的平均值、中值和最大值。

我认为您可以通过几个步骤来完成:

使用melt从宽转换为长 使用dplyr进行总结 使用dcast从长到宽转换 例如:

tmp <- melt(df, id.vars="id")

tmp <- tmp %>%
  group_by(id, variable) %>%
  summarise(mean = mean(value), median = median(value), max = max(value))

tmp <- melt(tmp, id.vars=c("id", "variable"), variable.name="stat")

tmp <- dcast(tmp, id ~ stat + variable)

我必须添加一个额外的步骤,因为您需要不同变量的平均值、中值和最大值。

如果是我,我可能会提前修改数据框,以包含我可能拥有的最大列集,并且其中一些列可能完全是NA。我想您可以通过一些条件求值和解析来修改一些内容,但joran的建议似乎更为可行。我的第一种方法可能是融合数据,然后使用dplyr获取每个组可能需要的所有统计数据,然后再重铸,然后在处理之前查看实际拥有的列further@joran,我喜欢你的解决方案。我最终使用了@初学者的解决方案,可能需要在所有ifelse中额外键入一些内容,但我只需要一次列出所有变量。它看起来更整洁,也更容易维护。我可以在一个地方添加/减去一列的摘要。如果是我,我可能会提前修改数据框,以包含我可能拥有的最大列集,有些专栏可能都是NA。我想你可以通过一些条件求值和解析来破解一些东西,但joran的建议似乎更可行。我的第一种方法可能是融合数据,然后使用dplyr获得每个小组可能需要的所有统计数据,然后再重新进行计算,然后,您可以在处理之前检查实际拥有的列further@joran,我喜欢你的解决方案。我最终使用了@初学者的解决方案,可能需要在所有ifelse中额外键入一些内容,但我只需要一次列出所有变量。它看起来更整洁,也更容易维护。我可以在一个地方添加/删除专栏的摘要。我很欣赏这个建议,这似乎是另一个不错的方法。我接受了@初学者的解决方案,因为它不涉及加载另一个包。我很感激这个建议,这似乎是另一个体面的方法。我接受了@初学者的解决方案,因为它不涉及加载另一个包。我不知道每个包的摘要-谢谢你的提示!我相信这会在某个时候派上用场。我最终使用了你的建议,但稍微修改了一下,所以我不必使用apply。我只是补充说:dfcols这是一个很好的简化,我没有想到。我不知道每个人的总结-谢谢你的提示!我相信这会在某个时候派上用场。我最终使用了你的建议,但稍微修改了一下,所以我不必使用apply。我只是加了一句:dfcols
这是一个很好的简化,我没有想到。