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

时间:2018-03-28 09:13:34

标签: r conditional

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

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然后返回1,否则返回7.或如果a1到19包含5或6,则返回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

我所知道的是笨重的,但在某种程度上是有效的。然而,一旦有多个值/条件,并非所有值都被正确填充(返回3个期望/指定值中的2个)。对于我使用!=以及><的“其他”规则。 我也尝试使用ifelse,但效果相同。

我也知道解决方案会相对简单并且盯着我看,但我很感激你让我找到一个合理的解决方案。

如果你有什么需要我澄清的,请告诉我。

提前致谢。

3 个答案:

答案 0 :(得分:2)

dplyr中有一个vectorised 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
    )
  )

条件位于~的左侧,您想要的结果位于右侧。

返回:

  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)

这是一个适用于多个规则的想法。 但是你的例子不清楚,没有1,2,5和6的线路会发生什么? 7或3?

无论如何,这里的想法适应性基于: 1或2 - &gt; 1; 5或6 - &gt; 6(假设1或2和5或6不能混合); 否则 - &gt; 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函数代替循环

答案 2 :(得分:1)

在这里,你应该在那个(基础r)循环中很好地解释一切。您只需花一些时间创建系数文件,以便将其推广到其他数据。当你的条件发生变化时,你也需要调整一下(&amp;而不是|,&lt;而不是= etc。)

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