我有一个数据表" the.data",其中第一列表示测量仪器,其余的是不同的测量数据。
instrument <- c(1,2,3,4,5,1,2,3,4,5)
hour <- c(1,1,1,1,1,2,2,2,2,2)
da <- c(12,14,11,14,10,19,15,16,13,11)
db <- c(21,23,22,29,28,26,24,27,26,22)
the.data <- data.frame(instrument,hour,da,db)
我也定义了一组乐器,例如第1组(g1)指的是乐器1和2.
g1 <- c(1,2)
g2 <- c(4,3,1)
g3 <- c(1,5,2)
g4 <- c(2,4)
g5 <- c(5,3,1,2,6)
groups <- c("g1","g2","g3","g4","g5")
我需要找出每个组的总和在每个数据类型及其总和的最大值。
g1小时1:总和(da)= 12 + 14 = 26 g1小时2:总和(da)= 19 + 15 = 34
因此,对于g1和da,答案是小时2和值34。
我在for循环中使用for循环执行了此操作,但这需要很长时间(几小时后我就中断了)。问题是.data大约有100.000行,并且大约有5000个组,每组有2-50个仪器。
有什么好方法可以做到这一点?
真诚地感谢Stack-overflow的所有贡献者。
更新:现在示例中只有五个组。
/克里斯
答案 0 :(得分:4)
group
循环必须保留,或者最好由lapply()
之类的东西替换。但是,hour
循环可以完全替换为重新格式化为instrument x hour
矩阵,然后只进行矢量化代数。例如:
library(reshape2)
groups = list(g1, g3)
the.data.a = dcast(the.data[,1:3], instrument ~ hour)
> sapply(groups, function(x) data.frame(max = max(colSums(the.data.a[x, -1])),
ind = which.max(colSums(the.data.a[x, -1]))))
[,1] [,2]
max 34 45
ind 2 2
答案 1 :(得分:3)
以下是John Colby's answer的略微修改版本,其中包含一些示例数据。
set.seed(21)
instrument <- sample(100, 1e5, TRUE)
hour <- sample(24, 1e5, TRUE)
da <- trunc(runif(1e5)*10)
db <- trunc(runif(1e5)*10)
the.data <- data.frame(instrument,hour,da,db)
groups <- replicate(5000, sample(100, sample(50,1)))
names(groups) <- paste("g",1:length(groups),sep="")
library(reshape2)
system.time({
the.data.a <- dcast(the.data[,1:3], instrument ~ hour, sum)
out <- t(sapply(groups, function(i) {
byHour <- colSums(the.data.a[i,-1])
c(max(byHour), which.max(byHour))
}))
colnames(out) <- c("max.hour","max.sum")
})
# Using da as value column: use value.var to override.
# user system elapsed
# 3.80 0.00 3.81
答案 2 :(得分:2)
以下是使用哈德利的plyr
和reshape2
的方法。首先,我们将向the.data
添加一些布尔值,具体取决于该工具是否在该组中。然后我们将其融合为长格式,将我们不需要的行子集化,然后通过ddply
或data.table
的操作进行分组。
#add boolean columns
the.data <- transform(the.data,
g1 = instrument %in% g1,
g2 = instrument %in% g2,
g3 = instrument %in% g3,
g4 = instrument %in% g4,
g5 = instrument %in% g5
)
#load library
library(reshape2)
#melt into long format
the.data.m <- melt(the.data, id.vars = 1:4)
#subset out data that that has FALSE for the groupings
the.data.m <- subset(the.data.m, value == TRUE)
#load plyr and data.table
library(plyr)
library(data.table)
#plyr way
ddply(the.data.m, c("variable", "hour"), summarize, out = sum(da))
#data.table way
dt <- data.table(the.data.m)
dt[, list(out = sum(da)), by = "variable, hour"]
做一些基准测试,看看哪个更快:
library(rbenchmark)
f1 <- function() ddply(the.data.m, c("variable", "hour"), summarize, out = sum(da))
f2 <- function() dt[, list(out = sum(da)), by = "variable, hour"]
> benchmark(f1(), f2(), replications=1000, order="elapsed", columns = c("test", "elapsed", "relative"))
test elapsed relative
2 f2() 3.44 1.000000
1 f1() 6.82 1.982558
因此,对于此示例,data.table大约快2倍。您的里程可能会有所不同。
只是为了表明它正在给出正确的价值观:
> dt[, list(out = sum(da)), by = "variable, hour"]
variable hour out
[1,] g1 1 26
[2,] g1 2 34
[3,] g2 1 25
[4,] g2 2 29
...
答案 3 :(得分:2)
您没有提供代码(或以编程方式生成组,这似乎需要组计数为5000)但是可能更有效地使用R :
groups <- list(g1,g2,g3,g4,g5)
gmax <- list()
# The "da" results
for( gitem in seq_along(groups) ) {
gmax[[gitem]] <- with( subset(the.data , instrument %in% groups[[gitem]]),
tapply(da , hour, sum) ) }
damat <- matrix(c(sapply(gmax, which.max),
sapply(gmax, max)) , ncol=2)
# The "db" results
for( gitem in seq_along(groups) ) {
gmax[[gitem]] <- with( subset(the.data , instrument %in% groups[[gitem]]),
tapply(db , hour, sum) ) }
dbmat <- matrix(c(sapply(gmax, which.max),
sapply(gmax, max)) , ncol=2)
#--------
> damat
[,1] [,2]
[1,] 2 34
[2,] 2 29
[3,] 2 45
[4,] 1 14
[5,] 2 42
> dbmat
[,1] [,2]
[1,] 2 50
[2,] 2 53
[3,] 1 72
[4,] 1 29
[5,] 1 73