我认为这将提供预期的输出:
library(tidyverse)
df1 %>%
group_by(Cluster) %>%
mutate(Dependent = ifelse(Project == "A", ProjectID[Project=="C"], NA))
#output
# A tibble: 9 x 4
# Groups: Cluster [3]
Cluster Project ProjectID Dependent
<fct> <fct> <int> <int>
1 Aaa A 1 3
2 Aaa B 2 NA
3 Aaa C 3 NA
4 Bbb A 4 NA
5 Bbb B 5 NA
6 Ccc A 6 8
7 Ccc B 7 NA
8 Ccc C 8 NA
9 Ccc D 9 NA
在每个集群中,如果项目 A 返回项目 C 的项目 ID,否则返回 NA
数据:
df1 <- read.table(text="Cluster Project ProjectID
Aaa A 1
Aaa B 2
Aaa C 3
Bbb A 4
Bbb B 5
Ccc A 6
Ccc B 7
Ccc C 8
Ccc D 9", header = TRUE)
基准测试提供了小数据集的答案
library(microbenchmark)
microbenchmark(missuse = df1 %>%
group_by(Cluster) %>%
mutate(Dependent = ifelse(Project == "A", ProjectID[Project=="C"], NA)),
Rui_Barradas = lapply(split(df1, df1$Cluster), function(DF){
DF$Dependent <- NA
if(any(DF$Project == "A") && any(DF$Project == "C"))
DF$Dependent[DF$Project == "A"] <- DF$ProjectID[DF$Project == "C"]
DF
}),
MKR = left_join(df1,filter(df1, Project=="C"), by="Cluster") %>%
mutate(Dependent = ifelse(Project.x == "A", ProjectID.y, NA)) %>%
select(Cluster, Project = Project.x, ProjectID = ProjectID.x, Dependent)
)
Unit: milliseconds
expr min lq mean median uq max neval cld
missuse 3.525404 3.566450 4.220243 3.604535 3.785439 40.69046 100 b
Rui_Barradas 1.390526 1.423534 1.685952 1.495683 1.511552 16.30843 100 a
MKR 9.770077 9.959867 10.605632 10.215248 10.592078 21.14565 100 c
更大数据集(90k 行)的基准测试
df1 <- df1[rep(1:nrow(df1), times = 10000),]
microbenchmark(missuse = df1 %>%
group_by(Cluster) %>%
mutate(Dependent = ifelse(Project == "A", ProjectID[Project=="C"], NA)),
Rui_Barradas = lapply(split(df1, df1$Cluster), function(DF){
DF$Dependent <- NA
if(any(DF$Project == "A") && any(DF$Project == "C"))
DF$Dependent[DF$Project == "A"] <- DF$ProjectID[DF$Project == "C"]
DF
}), times = 20)
Unit: milliseconds
expr min lq mean median uq max neval cld
missuse 25.05783 25.53072 29.95501 25.83243 28.49352 55.34345 20 a
Rui_Barradas 35.42203 36.85572 47.61315 39.87882 56.25432 95.80752 20 b
在 900k 行上:
df1 <- df1[rep(1:nrow(df1), times = 100000),] #original df1
Unit: milliseconds
expr min lq mean median uq max neval cld
missuse 466.6968 721.9709 945.8628 1062.6262 1101.914 1255.214 20 a
Rui_Barradas 718.8869 768.0912 1077.7594 934.1785 1308.145 1854.415 20 a
我在最后两个基准测试中遗漏了 MKR 答案,因为它使我的会话崩溃。
免责声明:我在土豆 PC 上运行基准测试。稍后我将在另一台更新的 PC 上重新测试,如果结果不同(就相对性能而言),我将更新答案。
更新:我觉得(由我)生成的数据有点欺骗性。这是另一个尝试:
df1 <- df1[rep(1:nrow(df1), times = 10000),]
df1 %>%
mutate(rle = rleid(Cluster)) %>%
mutate(Cluster = paste(Cluster, rle, sep = "_")) %>%
select(-rle) -> df1
MKR2 <- function(df1){
setDT(df1)
df1[Project == "A"][df1[Project == "C"], on="Cluster", nomatch=0][
df1, on=.(Cluster, Project)][
,.(Cluster, Project, ProjectID = i.ProjectID.1, Dependent = i.ProjectID)]
}
所以有很多小组的数据
这里我不得不省略 Rui Barradas 解决方案,因为它花费的时间太长:
microbenchmark(missuse = df1 %>%
group_by(Cluster) %>%
mutate(Dependent = ifelse(Project == "A", ProjectID[Project=="C"], NA)),
MKR = left_join(df1,filter(df1, Project=="C"), by="Cluster") %>%
mutate(Dependent = ifelse(Project.x == "A", ProjectID.y, NA)) %>%
select(Cluster, Project = Project.x, ProjectID = ProjectID.x, Dependent),
MKR2(df1),
times = 10
)
Unit: milliseconds
expr min lq mean median uq max neval cld
missuse 7445.97748 7815.2364 9609.4009 8350.0508 9565.2411 19965.5040 10 b
MKR 55.61109 59.9900 123.2263 80.4056 191.7361 250.5065 10 a
MKR2(df1) 100.97692 216.4811 994.8457 277.3159 1452.0668 4011.1804 10 a
有趣的东西