更新在OP的評論
的光。如果這樣做的百萬+行,從而提供所有的選項將是緩慢的。下面是一個100,000行僞數據集上的一些比較時序:
set.seed(12)
DF3 <- data.frame(id = sample(1000, 100000, replace = TRUE),
group = factor(rep(1:100, each = 1000)),
value = runif(100000))
DF3 <- within(DF3, idu <- factor(paste(id, group, sep = "_")))
> system.time(out1 <- do.call(rbind, lapply(split(DF3, DF3["group"]), `[`, 1,)))
user system elapsed
19.594 0.053 19.984
> system.time(out3 <- aggregate(DF3[,-2], DF3["group"], function (x) x[1]))
user system elapsed
12.419 0.141 12.788
我放棄了做了一百萬行。遠遠快,無論你相信與否,就是:
out2 <- matrix(unlist(lapply(split(DF3[, -4], DF3["group"]), `[`, 1,)),
byrow = TRUE, nrow = (lev <- length(levels(DF3$group))))
colnames(out2) <- names(DF3)[-4]
rownames(out2) <- seq_len(lev)
out2 <- as.data.frame(out2)
out2$group <- factor(out2$group)
out2$idu <- factor(paste(out2$id, out2$group, sep = "_"),
levels = levels(DF3$idu))
輸出是(有效)相同:
> all.equal(out1, out2)
[1] TRUE
> all.equal(out1, out3[, c(2,1,3,4)])
[1] "Attributes: < Component 2: Modes: character, numeric >"
[2] "Attributes: < Component 2: target is character, current is numeric >"
(out1
(或out2
)和out3
(在aggregate()
版本之間的差異)是隻是在組件的rownames)
用的時序:
user system elapsed
0.163 0.001 0.168
在10萬行的問題,並在此萬行的問題:
set.seed(12)
DF3 <- data.frame(id = sample(1000, 1000000, replace = TRUE),
group = factor(rep(1:1000, each = 1000)),
value = runif(1000000))
DF3 <- within(DF3, idu <- factor(paste(id, group, sep = "_")))
與
user system elapsed
11.916 0.000 11.925
與基體版本工作(即產生out2
)的定時更快做百萬行其他版本正在處理100,000行問題。這只是表明,使用矩陣的確很快,並且我的do.call()
版本中的瓶頸是rbind()
-結果在一起。
的百萬行的問題正與做:
system.time({out4 <- matrix(unlist(lapply(split(DF3[, -4], DF3["group"]),
`[`, 1,)),
byrow = TRUE,
nrow = (lev <- length(levels(DF3$group))))
colnames(out4) <- names(DF3)[-4]
rownames(out4) <- seq_len(lev)
out4 <- as.data.frame(out4)
out4$group <- factor(out4$group)
out4$idu <- factor(paste(out4$id, out4$group, sep = "_"),
levels = levels(DF3$idu))})
原始
如果你的數據在DF
,說出來的話:
do.call(rbind, lapply(with(DF, split(DF, group)), head, 1))
會做你想要什麼:
> do.call(rbind, lapply(with(DF, split(DF, group)), head, 1))
idu group
1 1 1
2 4 2
3 7 3
如果新的數據是DF2
然後我們得到:
> do.call(rbind, lapply(with(DF2, split(DF2, group)), head, 1))
id group idu value
1 1 1 1_1 34
2 4 2 4_2 6
3 1 3 1_3 34
但對於速度,我們可能要子集,而不是使用head()
,我們可以通過不使用with()
贏得了一下,如:
do.call(rbind, lapply(split(DF2, DF2$group), `[`, 1,))
> system.time(replicate(1000, do.call(rbind, lapply(split(DF2, DF2$group), `[`, 1,))))
user system elapsed
3.847 0.040 4.044
> system.time(replicate(1000, do.call(rbind, lapply(split(DF2, DF2$group), head, 1))))
user system elapsed
4.058 0.038 4.111
> system.time(replicate(1000, aggregate(DF2[,-2], DF2["group"], function (x) x[1])))
user system elapsed
3.902 0.042 4.106
+1這是一個很好的例子。 – 2011-04-28 21:30:39
這是一個不錯的方法,但要添加一個附註,實際數據也可以重複組代碼,這需要一個額外的步驟:添加一個真實的單個組ID到整個數據集,可能基於時間戳列 – 2011-04-29 08:04:38
怎麼回事!重複返回重複組的第一個值? – zach 2011-11-09 23:28:42