计算(对于每一行)满足多个列上的OR条件的次数

时间:2014-09-25 15:15:20

标签: regex r dataframe conditional-statements

我的问题类似于this one,但有点不同。在最初的问题中,我试图计算(每行)有多少列满足条件。我想做类似的事情,除了条件涉及带有OR条件的多个列,并且我的真实数据有很多列,所以理想情况下,我想使用正则表达式引用列。

我有以下数据:

colnames <- c(paste("col",rep(LETTERS[1:2],each=4),rep(1:4,2),sep=""),c("meh","muh"))
df <- as.data.frame(matrix(sample(c("Yes","No"),200,replace=TRUE),ncol=10))
names(df) <- colnames
df
   colA1 colA2 colA3 colA4 colB1 colB2 colB3 colB4 meh muh
1     No   Yes    No    No    No   Yes   Yes    No Yes Yes
2     No   Yes   Yes   Yes   Yes    No   Yes    No  No  No
3     No    No    No   Yes    No    No    No    No Yes  No
4    Yes    No   Yes   Yes   Yes   Yes   Yes   Yes  No Yes
5    Yes    No   Yes    No    No    No    No   Yes  No Yes
6    Yes    No    No    No   Yes   Yes    No    No  No  No
7    Yes    No    No    No   Yes   Yes   Yes    No Yes  No
8    Yes    No   Yes    No   Yes   Yes    No   Yes Yes  No
9     No   Yes    No    No    No   Yes   Yes    No  No  No
10   Yes   Yes    No    No   Yes    No   Yes    No Yes  No
11    No   Yes    No    No   Yes    No   Yes   Yes  No  No
12    No   Yes   Yes   Yes    No    No   Yes    No  No  No
13    No    No   Yes   Yes    No   Yes   Yes   Yes Yes  No
14   Yes   Yes    No    No    No    No   Yes    No  No Yes
15   Yes    No   Yes   Yes    No   Yes    No   Yes  No  No
16    No   Yes   Yes    No    No    No   Yes    No  No  No
17   Yes    No    No    No    No   Yes   Yes   Yes  No Yes
18   Yes    No   Yes   Yes    No    No    No    No  No Yes
19    No    No    No    No    No   Yes    No    No  No Yes
20    No   Yes    No    No   Yes   Yes   Yes    No  No  No

我想创建一个新列Nb,记录每一行:colA2,colA3,colA4中至少有一个==“是”加上至少一个的次数colB2,colB3,colB4是==“是”。

如果在查看一组列[colA2,colA3,colA4]时没有隐含这个“OR”条件,并且我正在添加满足条件的列数,我可以使用类似的东西:

df$Nb <- rowSums(df[, grep("^col[A-B][2-4]", names(df))] == "Yes")

我想使用正则表达式来引用列,因为在我的实际数据中,字母和数字分别比B和5更远。

谢谢!

1 个答案:

答案 0 :(得分:3)

您可以将rowSums方法调整为每个OR条件中的列组,然后添加> 0以使其成为&#34;至少一个。&#34;因此,&#34; A值中的至少一个是是&#34;看起来像是:

rowSums(df[, grep("^colA[2-4]", names(df))] == "Yes") > 0

然后您可以使用+组合它们:

(rowSums(df[, grep("^colA[2-4]", names(df))] == "Yes") > 0) +
 (rowSums(df[, grep("^colB[2-4]", names(df))] == "Yes") > 0)

顺便提一下,如果您的数据位于tidy format,那么您可以更轻松地回答类似这样的问题:也就是说,如果每列都是一个单独的变量。现在,您似乎将数据的属性(A,B,1-4)存储为列名称的一部分,这就是&#34;使用值为&#39;的列的操作的原因。 A&#39;&#34;非常尴尬。如果您使用dplyr和tidyr软件包重新排列数据,如下所示:

library(dplyr)
library(tidyr)
df$index <- 1:nrow(df)
newdf <- df %>% gather(key, value, colA1:colB4) %>%
    separate(key, c("col", "letter", "number"), c(-3, -2)) %>%
    mutate(number = as.numeric(number))

这会将您的数据重新排列为(请注意,我为您的每一行添加了自己的&#34;索引&#34;变量):

  meh muh index col letter number value
1 Yes  No     1 col      A      1   Yes
2 Yes  No     2 col      A      1   Yes
3  No  No     3 col      A      1   Yes
4 Yes  No     4 col      A      1    No
5 Yes Yes     5 col      A      1    No
6 Yes Yes     6 col      A      1   Yes

然后,您可以更自然地对这些观察进行分组,汇总,过滤和操作。例如,您似乎想要删除数字为1的列:而不是需要正则表达式,您只需执行newdf %>% filter(number > 1)

以下是您将如何执行您所描述的OR操作:

hasyes <- newdf %>% group_by(index, letter) %>% filter(number > 1) %>%
              summarize(hasyes = any(value == "Yes"))

对于每个原始行+字母组合,您现在具有Yes是否出现的逻辑值:

  index letter hasyes
1     1      A   TRUE
2     1      B   TRUE
3     2      A   TRUE
4     2      B   TRUE
5     3      A  FALSE
6     3      B   TRUE

另外一个摘要操作会将其转换为您想要的形式:

result <- hasyes %>% group_by(index) %>% summarize(yeses = sum(hasyes))

这个解决方案的重要之处在于它可以同样轻松地为任意数量的字母(即,如果它来自AZ而不仅仅是A和B)起作用。