2016-08-19 49 views
3

我有数据,看起来像这样:ifelse没有结束行循环如预期

df <- read.table(tc <- textConnection(" 
    var1 var2 var3 var4 
     1  1  7  NA 
     4  4  NA  6 
     2  NA  3  NA     
     4  4  4  4    
     1  3  1  1"), header = TRUE); close(tc) 

我试图创造,如果有,如果没有匹配或0返回1的新列。

我不工作的代码如下所示:

df$var5 = ifelse("1" %in% df$var1,1, 
       ifelse("1" %in% df$var2,1, 
         ifelse("1" %in% df$var3,1, 
          ifelse("1" %in% df$var4,1,0)))) 

给我一个表:

var1 var2 var3 var4 var5 
     1  1  7  NA  1 
     4  4  NA  6  1 
     2  NA  3  NA  1   
     4  4  4  4  1   
     1  3  1  1  1 

表其实我是想应该像

var1 var2 var3 var4 var5 
     1  1  7  NA  1 
     4  4  NA  6  0 
     2  NA  3  NA  0   
     4  4  4  4  0   
     1  3  1  1  1 

我已经看了帖子:

ifelse not working as expected in R

Loop over rows of dataframe applying function with if-statement

,但我无法得到任何回答我的问题。

回答

2

正确的方法应该是

with(df, ifelse(var1 %in% 1,1, 
      ifelse(var2 %in% 1,1, 
        ifelse(var3 %in% 1,1, 
         ifelse(var4 %in% 1,1,0))))) 
#[1] 1 0 0 0 1 

其原因是​​返回仅单个元件的那1

1 %in% df$var1 
#[1] TRUE 

同样地,在所有的所有列,有1 ,因此所有ifelse将返回TRUE,结果为值1.

wh ereas相反

df$var1 %in% 1 
#[1] TRUE FALSE FALSE FALSE TRUE 

返回逻辑矢量具有相同length为原始列。从本质上说,通过使用%in%,返回的长度将在lhs%in%


ifelse它不是必需的,更好的选择是基于对象的length,在逻辑使用rowSum矩阵(df ==1),并检查它是否不等于0,用as.integer转换为二进制。

as.integer(rowSums(df == 1, na.rm =TRUE)!=0) 
#[1] 1 0 0 0 1 

或者另一种选择是Reduce|

as.integer(Reduce(`|`, lapply(replace(df, is.na(df), 0), `==`, 1))) 
#[1] 1 0 0 0 1 
0

而不是单独使用ifelse每列可以检查行明智的,如果存在整行1,然后返回1或0相应

as.numeric(apply(df, 1, function(x) any(x == 1)) %in% TRUE) 
#[1] 1 0 0 0 1 

只是为了更好地解释步骤:

apply(df, 1, function(x) any(x == 1)) 
#[1] TRUE NA NA FALSE TRUE 

apply(df, 1, function(x) any(x == 1)) %in% TRUE 
#[1] TRUE FALSE FALSE FALSE TRUE 

as.numeric(apply(df, 1, function(x) any(x == 1)) %in% TRUE) 
#[1] 1 0 0 0 1