[英]Product Combination of variables by loop in R with data table
我在 R 中有一个初始表,包括 7 个变量,如下所示:
library(data.table)
Data<-data.frame(
ID=c(1,1,1,2,2,2,3,3,3,4,4,4),
CP1 =c(1,0,0,1,0,0,1,0,0,1,0,0),
CP2 =c(0,1,1,0,0,1,0,1,0,0,0,0),
CP3 =c(0,0,0,0,0,0,0,0,0,0,0,1),
PR1 =c(1,1,0,0,0,0,0,0,0,0,0,0),
PR2=c(0,0,1,0,0,0,0,0,0,0,0,0),
PR3=c(0,0,0,0,1,0,0,0,0,0,0,1)
)
Data
> Data
ID CP1 CP2 CP3 PR1 PR2 PR3
1 1 1 0 0 1 0 0
2 1 0 1 0 1 0 0
3 1 0 1 0 0 1 0
4 2 1 0 0 0 0 0
5 2 0 0 0 0 0 1
6 2 0 1 0 0 0 0
7 3 1 0 0 0 0 0
8 3 0 1 0 0 0 0
9 3 0 0 0 0 0 0
10 4 1 0 0 0 0 0
11 4 0 0 0 0 0 0
12 4 0 0 1 0 0 1
我想用 PR1、PR2 和 PR3 变量创建 CP1、CP2 和 CP3 的所有产品组合,名称如下 CP1_PR1、CP1_PR2、CP1_PR3、CP2_PR1、CP2_PR2、CP2_PR3、CP3_PR1、CP3_PR2 和 CP3_PR3。
但是我想使用一个条件来做这个产品。 当 CP 和 PR 变量都等于 1 时,我想创建 CP_PR 变量,它将等于 1 并且还使初始 CP 变量为零。
我用 CP 变量的名称和 PR 变量的向量制作了一个向量:
ListCP<-colnames(Data)[2:4]
ListPr<-colnames(Data)[5:7]
然后我使用双 for 循环来创建所需的产品组合变量,这些变量正确地创建了我想要的组合:
for (i in ListPr) {
for (j in ListCP) {
Data<-Data[,paste0(j,"_",i) := ifelse(get(i)==1 & get(j)==1,1,0)]
}
}
> Data
> Data
ID CP1 CP2 CP3 Pr1 Pr2 Pr3 CP1_Pr1 CP2_Pr1 CP3_Pr1 CP1_Pr2 CP2_Pr2 CP3_Pr2 CP1_Pr3 CP2_Pr3 CP3_Pr3
1: 1 1 0 0 1 0 0 1 0 0 0 0 0 0 0 0
2: 1 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0
3: 1 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0
4: 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
5: 2 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
6: 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
7: 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
8: 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
9: 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
10: 4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
11: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
12: 4 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1
然后,当我尝试将初始 CP 变量设为零时,以防我在上面所说的出现错误。
> for (i in ListCP) {
+
+ for (j in ListPr) {
+
+ Data<-Data[paste0(j,"_",i)==1,.(j) := 0]
+
+
+ }
+
+ }
Error in `[.data.table`(Data, paste0(j, "_", i) == 1, `:=`(.(j), 0)) :
LHS of := must be a symbol, or an atomic vector (column names or positions).
我的问题是我是否可以将两个双 for 循环组合成一个而不会出错。 此外,因为我的数据集更大,任何其他更快的实现将不胜感激。
谢谢你。
以下解决方案使用变量.SD
及其附带的.SDcols
并且只需要一个for
循环。 这似乎是一种更自然的方式。
library(data.table)
Data<-data.frame(
ID=c(1,1,1,2,2,2,3,3,3,4,4,4),
CP1 =c(1,0,0,1,0,0,1,0,0,1,0,0),
CP2 =c(0,1,1,0,0,1,0,1,0,0,0,0),
CP3 =c(0,0,0,0,0,0,0,0,0,0,0,1),
PR1 =c(1,1,0,0,0,0,0,0,0,0,0,0),
PR2=c(0,0,1,0,0,0,0,0,0,0,0,0),
PR3=c(0,0,0,0,1,0,0,0,0,0,0,1)
)
Data2 <- as.data.table(Data)
Data <- as.data.table(Data)
ListCP<-colnames(Data)[2:4]
ListPr<-colnames(Data)[5:7]
for (i in ListPr) {
for (j in ListCP) {
Data<-Data[,paste0(j,"_",i) := ifelse(get(i)==1 & get(j)==1,1,0)]
}
}
for(j in ListPr) {
new_cols <- paste0(ListCP, "_", j)
j_val <- Data2[[j]]
Data2[, (new_cols) := lapply(.SD, \(i) +(i & j_val)), .SDcols = ListCP]
}
all.equal(Data, Data2)
#> [1] TRUE
由reprex package (v2.0.1) 创建于 2022-02-19
对于新问题,请尝试以下操作。
它必须在一个单独的循环中运行,首先使用上述CP
变量的原始值,然后只有在新列为 1 时才更改为 0。
for(j in ListPr) {
new_cols <- paste0(ListCP, "_", j)
Data2[, (ListCP) := ifelse(.SD == 1, 0L, .SD), .SDcols = ListCP, by = new_cols]
}
df = melt(Data[, id:=.I], id="id",measure =patterns("CP", "PR"), value.name = c("CP", "PR"))
prods = list()
for( i in unique(df$variable)) {
for(j in unique(df$variable)) {
prod = merge(df[variable==i], df[variable==j], by="id")[,`:=`(p=CP.x*PR.y)]
df <- df[prod[, .(id,p)], CP:=fifelse(p==1 & variable==i, 0, CP), on="id"]
prods = c(prods,list(setnames(prod[,.(p)],new=paste0("CP",i,"_PR",j))))
}
}
cbind(
Data[, .(ID)],
dcast(df, id~variable, value.var=c("CP","PR"), sep=""),
do.call(cbind, prods)
)[,id:=NULL][]
Output:
ID CP1 CP2 CP3 PR1 PR2 PR3 CP1_PR1 CP1_PR2 CP1_PR3 CP2_PR1 CP2_PR2 CP2_PR3 CP3_PR1 CP3_PR2 CP3_PR3
1: 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0
2: 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0
3: 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0
4: 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
5: 2 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
6: 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
7: 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
8: 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
9: 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
10: 4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
11: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
12: 4 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1
这是另一种方法 - 到目前为止,这只获取组合变量,但是当你澄清(见我的评论)哪个产品将决定 CP 是否从 1 替换为 0 时,我会更新它。
setDT(Data)
df = melt(Data[, id:=.I], id="id",measure =patterns("CP", "PR"), value.name = c("CP", "PR"))
result = do.call(cbind, lapply(unique(df$variable), function(i) {
do.call(cbind, lapply(unique(df$variable), function(j) {
result = merge(df[variable==i], df[variable==j], by="id")[,`:=`(p=CP.x*PR.y)]
setnames(result[, .(p)], new=paste0("CP",i,"_PR",j))
}))
}))
cbind(Data, result)[,id:=NULL][]
Output:
ID CP1 CP2 CP3 PR1 PR2 PR3 CP1_PR1 CP1_PR2 CP1_PR3 CP2_PR1 CP2_PR2 CP2_PR3 CP3_PR1 CP3_PR2 CP3_PR3
1: 1 1 0 0 1 0 0 1 0 0 0 0 0 0 0 0
2: 1 0 1 0 1 0 0 0 0 0 1 0 0 0 0 0
3: 1 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0
4: 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
5: 2 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
6: 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
7: 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
8: 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
9: 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
10: 4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
11: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
12: 4 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1```
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.