繁体   English   中英

R 和 data.table 中循环变量的乘积组合

[英]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]
}

更新

  • 根据 OP 的说明,重新更新 CP 值:
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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM