使用 !duplicated
按 "ID" 获取第一行 (比 "by group" 操作更高效)。将结果与原数据使用 rbind
合并,再使用 order
排序:
df = data.frame(ID = rep(1:2, each = 4), Value = 1:8)
d2 = rbind(df, df[!duplicated(df$ID), ])
d2[order(d2$ID), ]
与
data.table :: duplicated
相同的思路:
d = as.data.table(df)
d2 = rbindlist(list(d, d[!duplicated(d, by = "ID")]))
setorder(d2, ID)
使用 data.table::unique
更加简单明了:
d2 = rbindlist(list(d, unique(d, by = "ID")))
setorder(d2, ID)
还有 data.table::rowid
:
d2 = rbindlist(list(d, d[rowid(ID) == 1]))
setorder(d2, ID)
避免使用“按组”操作,在5000行数据集上,!duplicated
、unique
和rowid
替代方法都比之前基准测试中的明显胜者data.table
解决方案(使用by
)更快。(参见OP):
df = data.frame(ID = rep(1:1250, each = 4), Value = 1:5e3)
d = as.data.table(d)
microbenchmark(
f_by = {
d1 = d[ , .(Value = c(Value, first(Value))), by = ID]
},
f_dupl_df = {
d2 = rbind(df, df[!duplicated(df$ID), ])
d2 = d2[order(d2$ID), ]
},
f_dupl_dt = {
d3 = rbindlist(list(d, d[!duplicated(d, by = "ID")]))
setorder(d3, ID)
},
f_uniq_dt = {
d4 = rbindlist(list(d, unique(d, by = "ID")))
setorder(d4, ID)
},
f_rowid = {
d5 = rbindlist(list(d, d[rowid(ID) == 1]))
setorder(d5, ID)
},
times = 10L)
all.equal(d1, as.data.table(d2))
all.equal(d1, d3)
all.equal(d1, d4)
all.equal(d1, d5)
然而,亚秒级基准测试并不十分具有信息性,因此请尝试在具有许多组的大型数据上进行测试。
base
解决方案会失去优势。
data.table::duplicated
、
unique
和
rowid
的扩展效果更好,现在快了约 20 倍,其中
data.table::unique
最快。
df = data.frame(ID = rep(1:1250000, each = 4), Value = 1:5e6)
d = as.data.table(df)
为了完整起见,使用mult = "first"的二分查找来选择第一个匹配项:
d[.(unique(ID)), on = .(ID), mult = "first"]
然而,在上述两种情况下,它的结束时间是与unique
替代方案相比两倍长。
dat %>% group_by(ID) %>% summarize(bind_rows(cur_data(), cur_data()[1,]))
- Gregor Thomas