【问题标题】:R: Aggregate column of values to multiple new columns, each based on index columnR:将值列聚合到多个新列,每个新列都基于索引列
【发布时间】:2018-10-09 23:13:09
【问题描述】:

假设我有数据:

data.frame(Plot = rep(1:2,3),Index = rep(1:3, each = 2), Val = c(1:6)*10)

  Plot Index Val
1    1     1  10
2    2     1  20
3    1     2  30
4    2     2  40
5    1     3  50
6    2     3  60

我想创建新列组合/聚合所有Val,这些Index 共享给定Plot 的公共Index。我想为每个Index 执行此操作。

  Plot Val1 Val2 Val3
1    1   10   30   50
2    2   20   40   60

我希望任何剩余的列(例如,在这个简化示例中只是 Plot)保留在我的最终 data.frame 中。

我的尝试

我知道我可以使用aggregate()merge() 逐步执行此操作,但是有没有办法使用单个(或最少)调用来执行此操作?

  • 任何方法都很棒,但我总是希望看到一种优雅的基本 R 方法(如果存在)...

更新:

我正在寻找一种在涉及其他列时也能正常工作的解决方案:

dat2 = data.frame(Plot = rep(1:2,each = 8),Year = rep(rep(2010:2011, each = 4),2), 
                  Index = rep(rep(1:2,2),4), Val = rep(c(1:4)*10,4))

   Plot Year Index Val
1     1 2010     1  10
2     1 2010     2  20
3     1 2010     1  30
4     1 2010     2  40
5     1 2011     1  10
6     1 2011     2  20
7     1 2011     1  30
8     1 2011     2  40
9     2 2010     1  10
10    2 2010     2  20
11    2 2010     1  30
12    2 2010     2  40
13    2 2011     1  10
14    2 2011     2  20
15    2 2011     1  30
16    2 2011     2  40

#Resulting in (if aggregating by sum, for example):

  Plot Year Val1 Val2 
1    1 2010   40   60 
2    1 2011   40   60 
3    2 2010   40   60 
4    2 2011   40   60 

此外,理想情况下,新列可以基于 Index 值命名。

  • 因此,如果我的索引改为 A:C,我的新列将是 ValAValBValC

【问题讨论】:

  • as.data.frame.matrix(xtabs(Val~Plot+Index,dat))
  • do.call(data.frame,aggregate(Val~Plot,dat,I))
  • reshape2::dcast(dat,Plot~Index)
  • tidyr::spread(dat,Index,Val)
  • 谢谢@Onyambu。您的 as.data.frame.matrix 按预期工作(不包括 Plot 列,这很好,因为我可以很容易地将其添加回来)。但是,您的 do.call 方法无法按预期使用扩展的示例数据集(例如,使用额外的索引列)

标签: r recursion merge aggregate


【解决方案1】:

您似乎想要一个基本的 R 解决方案:然后您可以执行以下操作:

m = aggregate(Val~.,dat2,sum)
reshape(m,v.names = "Val",idvar = c("Plot","Year"),timevar = "Index",direction = "wide")
  Plot Year Val.1 Val.2
1    1 2010    40    60
2    2 2010    40    60
3    1 2011    40    60
4    2 2011    40    60

但你可以使用其他功能:

do.call(data.frame,aggregate(Val~Plot+Year,m,I))
  Plot Year Val.1 Val.2
1    1 2010    40    60
2    2 2010    40    60
3    1 2011    40    60
4    2 2011    40    60

或者使用reshape2库,你可以解决这个问题:

library(reshape2)
dcast(dat2,Plot+Year~Index,sum,value.var = "Val")
  Plot Year  1  2
1    1 2010 40 60
2    1 2011 40 60
3    2 2010 40 60
4    2 2011 40 60

【讨论】:

  • 这正是我想要的! +1!
  • 为什么需要base R?
  • aggregate(Val~Plot+Year,aggregate(Val~.,dat2,sum),I)
【解决方案2】:

可以考虑使用gatherunitespread 函数来获得OP 提到的所需结果。

library(tidyverse)
df <- data.frame(Plot = rep(1:2,3),Index = rep(1:3, each = 2), Val = c(1:6)*10)


df %>% gather(key, value, -Plot, -Index) %>%
  unite("key", c(key,Index), sep="") %>%
  spread(key, value)

#   Plot Val1 Val2 Val3
# 1    1   10   30   50
# 2    2   20   40   60

注意:还有其他简短的选项(正如@Onyambu 正确指出的那样),但是再次根据 OP 的愿望列的名称需要更改。

spread(df, Index, Val)
#   Plot  1  2  3
# 1    1 10 30 50
# 2    2 20 40 60

aggregate(Val~Plot,df,I)
#   Plot Val.1 Val.2 Val.3
# 1    1    10    30    50
# 2    2    20    40    60

更新:基于 OP 的第二个数据帧。

dat2 = data.frame(Plot = rep(1:2,each = 8),Year = rep(rep(2010:2011, each = 4),2), 
                  Index = rep(rep(1:2,2),4), Val = rep(c(1:4)*10,4))


library(tidyverse)
library(reshape2)

dat2 %>% gather(key, value, -Plot, -Index, -Year) %>%
  unite("key", c(key,Index), sep="") %>%
  dcast(Plot+Year~key, value.var = "value")

#   Plot Year Val1 Val2
# 1    1 2010    2    2
# 2    1 2011    2    2
# 3    2 2010    2    2
# 4    2 2011    2    2

【讨论】:

  • 很高兴它帮助了你。为了完整起见,我已经更新了您的第二个数据集的答案。
猜你喜欢
  • 2018-02-21
  • 2015-05-17
  • 2018-04-03
  • 2022-12-08
  • 1970-01-01
  • 1970-01-01
  • 2022-08-11
  • 1970-01-01
  • 2018-12-08
相关资源
最近更新 更多