我的数据表格式如下:
id source
1 A
1 B
2 A
3 B
4 A
4 B
我想制作一个按 id
分组的新列,其值反映相应的 source
值(即。 A, B, or Both
)如果 both
与id
和A
相对应,则会使用B
。
我希望输出如此:
id source source_group
1 A both
1 B both
2 A A
3 B B
4 A both
4 B both
如果您可以通常用于处理 source
的其他值,例如A, B, C, D, ... etc.
答案 0 :(得分:5)
您可以使用ave()
df$source_group <- with(df, {
ave(as.character(source), id, FUN=function(x) if(length(x) > 1) "both" else x)
})
给出了
df
# id source source_group
# 1 1 A both
# 2 1 B both
# 3 2 A A
# 4 3 B B
# 5 4 A both
# 6 4 B both
或者正如大卫建议的那样,我们可以使用 data.table
library(data.table)
setDT(df)[, source_group := if(.N > 1) "both" else as.character(source), by = id]
给出了
df
# id source source_group
# 1: 1 A both
# 2: 1 B both
# 3: 2 A A
# 4: 3 B B
# 5: 4 A both
# 6: 4 B both
请注意,这两个都假设source
列属于因子类。
答案 1 :(得分:5)
仅供参考,这是一个可以说是更合适的基准:
library(data.table)
library(dplyr)
library(microbenchmark)
DT = data.table(id=seq(1e5))[,
.(source = c(if (runif(1) > .5) "A", if (runif(1) > .5)"B")), by=id]
DF = data.frame(DT)
microbenchmark(
dplyr =
DF %>% group_by(id) %>% mutate(gr = if(n()>1) "both" else as.character(source)),
dplyr_dt =
DT %>% group_by(id) %>% mutate(gr = if(n()>1) "both" else as.character(source)),
ave = DF$gr <-
ave(as.character(DF$source), DF$id, FUN = function(x) if(length(x) > 1) "both" else x),
dt = DT[, gr := if (.N > 1) "both" else as.character(source), by=id],
dt2 = DT[,
gr := as.character(source)][ DT[, if (.N > 1) 1, by=id][, V1 := NULL],
gr := "both", on = "id"],
times=10)
结果:
Unit: milliseconds
expr min lq mean median uq max neval
dplyr 1200.13579 1215.56997 1328.73931 1245.81556 1252.66023 1828.02921 10
dplyr_dt 38.43108 41.58004 47.98858 43.89661 49.27464 68.64005 10
ave 149.67549 153.03421 167.09148 163.19261 181.60074 191.22481 10
dt 32.31500 33.60741 41.00644 35.80188 37.60350 65.76292 10
dt2 25.99567 26.44592 28.11141 28.19138 28.55474 31.42691 10
我不知道为什么ave
在这里做得更糟。也许正如@bunk所说,ave
不能很好地适应许多群体。 Dplyr在data.frame上运行缓慢,但在使用data.table后端(如所宣传的那样)时速度更快。
对于它的价值,我的data.table解决方案有点不同(证明一个单独的答案?):
DT[,
gr := as.character(source)
][DT[, if (.N > 1) 1, by=id][, V1 := NULL],
gr := "both"
, on = "id"]
首先,它将gr
设置为source
,然后将both
替换为具有两行的组。
答案 2 :(得分:2)
或使用
'url' => env('APP_URL'),
事实上,理查德的这种数据方法将比dplyr / ifelse或dplyr / if-else甚至数据表版本更快。
library(dplyr)
library(tidyr)
tab%>%
group_by(id)%>%
mutate(gr = ifelse(length(source)==2, 'both', source))
id source gr
1 1 A both
2 1 B both
3 2 A A
4 3 B B
5 4 A both
6 4 B both