根据 R 中的多个条件分配新的列值

Assign new column values based on multiple conditions in R

我需要分配一个新列,其中包含基于多个条件的多个可能值。 示例数据

a1 a2 a3 a4 a5 a6 a7 a8 a9 
NA 1  NA 2  7  8  9  1  1 
7  7  7  7  7  7  7  7  7
6  6  6  6  6  6  5  5  5

所以我可能有一些规则,例如:如果 a1 到 a9 包含 1 或 2,则 return 1,否则,return 7。或者如果 a1 到 19 包含 5 或 6,return a 6,否则 3。我有很多这样的规则,所以需要一些可以容纳的东西。

要求的结果

a1 a2 a3 a4 a5 a6 a7 a8 a9 NEW
NA 1  NA 2  7  8  9  1  1  1
7  7  7  7  7  7  7  7  7  7
6  6  6  6  6  6  5  5  5  6

我试过用子集分配,即

df$NEW <- 7
df$NEW[df$a1==1 | df$a2==1 | df$a3==1] <- 1
df$NEW[df$a4==1 | df$a5==1 | df$a6==1] <- 1
df$NEW[df$a7==1 | df$a8==1 | df$a9==1] <- 1
df$NEW[df$a1==7 | df$a2==7 | df$a3==7] <- 7
df$NEW[df$a1==5 | df$a2==5 | df$a3==5] <- 6
df$NEW[df$a1==6 | df$a2==6 | df$a3==6] <- 6

我知道这很笨拙,但在一定程度上是可行的。然而,一旦有多个值/条件,并非所有值都被正确填充(returns 可能是 3+ 个期望/分配值中的 2 个)。对于 'otherwise' 规则,我使用了 != 以及 ><。 我也尝试过使用 ifelse 但效果相同。

我也知道解决方案会相对简单,而且会直接盯着我看,但如果你能给我指明一个合理的解决方案,我将不胜感激。

如果你有什么想让我澄清的,请告诉我。

提前致谢。

dplyr中有一个向量化的if语句可以帮助你调用case_when:

library(dplyr)

df <- read.table(text = 'a1 a2 a3 a4 a5 a6 a7 a8 a9 
           NA 1  NA 2  7  8  9  1  1 
           7  7  7  7  7  7  7  7  7
           6  6  6  6  6  6  5  5  5', header = T)

df %>% 
  mutate(
    NEW = case_when(
      a1 == 1 | a2 == 1 | a3 == 1 ~ 1,
      a1==1 | a2==1 | a3==1 ~ 1,
      a4==1 | a5==1 | a6==1 ~ 1,
      a7==1 | a8==1 | a9==1 ~ 1,
      a1==7 | a2==7 | a3==7 ~ 7,
      a1==5 | a2==5 | a3==5 ~ 6,
      a1==6 | a2==6 | a3==6 ~ 6
    )
  )

条件在~左边,你想要的结果在右边

Returns:

  a1 a2 a3 a4 a5 a6 a7 a8 a9 NEW
1 NA  1 NA  2  7  8  9  1  1   1
2  7  7  7  7  7  7  7  7  7   7
3  6  6  6  6  6  6  5  5  5   6

这是一个适用于多个规则的想法。 但是您的示例不清楚,没有 1,2,5 和 6 的行会发生什么? 7 还是 3?

无论如何,这里有一个可以根据以下内容进行调整的想法: 1 或 2 -> 1 ; 5 or 6 -> 6 (假设1 or 2和5 or 6不能混用) ; 否则 -> 7

df$new <- 7

for (i in 1:nrow(df)) {
  if (1 %in% as.numeric(df[i,]) | 2 %in% as.numeric(df[i,] )) {

    df[i,]$new <- 1
  } 
  else if (5 %in% as.numeric(df[i,]) | 6 %in% as.numeric(df[i,] )) {
    df[i,]$new <- 6
  }
}


df

您可以使用 apply 函数代替循环

给你...一切都应该在那个 (base r) 循环中得到很好的解释。您只需要花一些时间创建一个系数文件,以便将其推广到其他数据。当您的条件发生变化时,您还必须进行一些调整(& 而不是 |,< 而不是 = 等)

df <-data.frame(matrix(c(NA, 1,  NA, 2,  7,  8,  9,  1,  1,7,  7,  7,  7,  7,  7,  7,  7,  7,6,  6,  6,  6,  6,  6,  5,  5,  5),
                        nrow=3, ncol=9, byrow=T))
colnames(df) = c("a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9" )
nbconditions <- 6
condition <- matrix(NA, nrow=nrow(df) , ncol= nbconditions)
# you could read.xlsx an already prepared coefficient matrix here
coefficients <-  matrix(NA, nrow= ncol(df)  , ncol=nbconditions )
coefficients[c(1,2,3),1] <- 1
coefficients[c(4,5,6),2] <- 1
coefficients[c(7,8,9),3] <- 1
coefficients[c(1,2,3),4] <- 7
coefficients[c(1,2,3),5] <- 5
coefficients[c(1,2,3),6] <- 6
results <- c(1,1,1,7,6,6)
NEW <- rep(NA, nrow(df))

for(i in 1:nrow(df)) {
  found <- F
  for(j in nbconditions:1) {  #condition checking from least priority to most priority
    if(!found) {
      indicestocheck <- which(!is.na(coefficients[,j]))
      if(sum(is.na(df[i,indicestocheck]))==length(indicestocheck)) {
        NEW[i] <- NA 
      } else {
        checks <- (coefficients[,j] == df[i,indicestocheck])
        #print(checks)
        if( sum(is.na(checks)) < length(checks) & 1<=sum(checks[which(!is.na(checks))])) {
         NEW[i] <- results[j] 
         found <- T
         print(paste(j,"found",results[i]))
         }
      }
    }
  }
}
df$NEW <- NEW
df

> df
  a1 a2 a3 a4 a5 a6 a7 a8 a9 NEW
1 NA  1 NA  2  7  8  9  1  1   1
2  7  7  7  7  7  7  7  7  7   7
3  6  6  6  6  6  6  5  5  5   6