【问题标题】:Collapse rows in a data frame using R使用 R 折叠数据框中的行
【发布时间】:2012-10-04 18:45:52
【问题描述】:

我在 R 中有一个数据框定义如下:

数据框:

col 1 col 2 col 3 col4
200    AIG   8.5   12   
800   AIG   8.1    20.1   
500   A1B   20   50.5   
800 A1B   12   30   
120   A2M    1.6   8.5   

dat <- structure(list(col1 = c(200, 800, 500, 800, 120), col2 = structure(c(3L, 
    3L, 1L, 1L, 2L), .Label = c("A1B", "A2M", "AIG"), class = "factor"), 
        col3 = c(8.5, 8.1, 20, 12, 1.6), col4 = c(12, 20.1, 50.5, 
        30, 8.5)), .Names = c("col1", "col2", "col3", "col4"), row.names = c(NA, 
    -5L), class = "data.frame")

然后我想按 id 折叠行(在这种情况下,唯一 id 是 A1G、A1B、A2M)。
Col 1,我想通过添加具有相同 ID 的行来折叠它。
Col 2,我想将它折叠到每个唯一的 id
Col 3,我想将它折叠如下,取 col1*col3,将它们相加,然后除以 col1 的总和。
即A1G的新行值应该是(8.5*20+8.1*80)/(80+20)。也就是第 3 列的加权平均值,由 col1 的值加权。
Col 4,我想取最大值。

生成的数据框应如下所示:

第 1 列 第 2 列第 3 列第 4 列
800+200=1000 AIG   (8.5*200+8.1*800)/1000=8.18   max(12,20.1)=20.1   
800+500=1300    AIB   (20*800+12*500)/1300=16.9   max(50.5, 30)= 50.5   
120   A2M   1.6   8.5   

有什么建议吗?

【问题讨论】:

标签: r dataframe


【解决方案1】:

这是一个 data.table 解决方案,可以很好地扩展大数据(速度和内存效率)

library(data.table)
DT <- data.table(dat, key="col2")
DT[, list(col1=sum(col1), 
          col3=sum(col1 * col3) / sum(col1), 
          col4=max(col4)), by=col2]
#   col2 col1     col3 col4
#1:  A1B 1300 15.07692 50.5
#2:  A2M  120  1.60000  8.5
#3:  AIG 1000  8.18000 20.1

【讨论】:

  • 这是最快最简单的解决方案。我尝试了一个大文件,它比 plyr 或基本包快得多
  • 是的,data.table 围绕plyr 运行,甚至是基础 R。参见timings vignette。它还使用更少的内存。
  • 如果在第二个data.table命令中使用了by参数,真的需要设置key吗?
【解决方案2】:

base 中的一个解决方案:

dat2<-do.call(rbind,
  by(dat,dat$col2, function(x) 
    with (x,
     data.frame(
       col1 = sum(col1),
       col3 = sum(col1 * col3) / sum(col1),
       col4 = max(col4)
     )
    )
  )
)
dat2$col2<-rownames(dat2)

#     col1     col3 col4 col2
# A1B 1300 15.07692 50.5  A1B
# A2M  120  1.60000  8.5  A2M
# AIG 1000  8.18000 20.1  AIG

【讨论】:

  • 比我的基本解决方案 +1 好得多
【解决方案3】:

使用plyr 包:

library(plyr)
ddply(df, "col2", summarize, col1 = sum(col1),
                             col3 = sum(col1 * col3) / sum(col1),
                             col4 = max(col4))
#   col2 col1     col3 col4
# 1  A1B 1300 15.07692 50.5
# 2  A2M  120  1.60000  8.5
# 3  AIG 1000  8.18000 20.1

【讨论】:

    【解决方案4】:

    基本解决方案,但我喜欢 data.table 解决方案:

    dat[, 2] <- factor(dat[, 2], levels=unique(dat[, 2])) #in case not already ordered
    L1 <- split(dat, dat$col2)                            #split into list by col2
    
    funny <- function(x){                                 #function to calculate stuff
        x <- data.frame(x)
        c(col1=sum(x[,1]), col2=as.character(x[1, 2]), 
            col3=sum((x[, 3]*x[, 1]))/sum(x[, 1]),
            col4=max(x[,4]))
    }
    
    #apply function and wrap it up into dataframe
    dat2 <- data.frame(do.call(rbind, lapply(L1, funny)), row.names=NULL) 
    dat2[, -2] <- apply(dat2[, -2], 2, as.numeric)       #reapply classes    
    dat2
    
    #> dat2
    #  col1 col2     col3 col4
    #1 1000  AIG  8.18000 20.1
    #2 1300  A1B 15.07692 50.5
    #3  120  A2M  1.60000  8.5
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-13
      • 1970-01-01
      • 2017-09-16
      • 2019-01-20
      • 2016-07-07
      • 2020-07-08
      • 1970-01-01
      • 2013-06-20
      相关资源
      最近更新 更多