我在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的行来折叠它。
第2栏,我想把它折叠成每个唯一的身份
第3栏,我想将它折叠如下,取col1 * col3,添加它们,然后将它们除以col1的总和。
即,A1G新行值应为(8.5 * 20 + 8.1 * 80)/(80 + 20)。 Aka第3列的加权平均值由col1的值加权。
第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
有什么建议吗?
答案 0 :(得分:20)
这是一个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
答案 1 :(得分:10)
基地解决方案:
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
答案 2 :(得分:6)
使用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
答案 3 :(得分:1)
基础解决方案,但我喜欢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