Grepl匹配多种条件,包括'和'和'或'条件

时间:2017-05-30 14:30:09

标签: r contains grepl

我的数据框如下

df <- data.frame(c("Utility grid", "Grid connection", "Grid", "", "", "Dry-cell-torch", "Solar", ""), c("solar", "", "", "", "", "", "Dry-cell-torch", ""), c("", "fan", "TV", "", "Utility grid connection", "", "", "Unreachable"), c("", "radio", "", "", "", "", "", "")) 
colnames(df) <- c(paste("de_", 1:4, sep=""))

我想在此数据框中附加第5列“de”,其中包含以下条件 -

  • 条件1.如果所有行都为空(如第4行),则“de”应为0.

  • 条件2.如果只有4行是非空白的,并且该值是“包含”“网格”而不区分大小写,或者是“无法访问”,或者是“干细胞火炬” “,那么”de“应为0。

  • 条件3.否则“de”应为1

所需的“de”应为

df$de <- (c(1, 1, 1, 0, 0, 0, 1, 0))

请注意我的原始数据帧是600行和45列。我只是在这里放了一个子集,但这个子集说明了我想要完成的详尽条件。

所以我尝试了使用grepl的以下正则表达式(改编自你们其中一个人在stackoverflow中给出的一个解决方案,在一个不同但类似的问题中) -

df$de <- (!grepl("grid|Unreachable|Dry-cell-torch|^$", 
                  apply(df,1,paste, collapse=""), ignore.case=TRUE))+0L

除了在第1行中我们说“实用网格”,在第二列中我有“太阳能”,在第一行我有“太阳能”的情况下,它给我de为0,而我需要1.我理解问题 - 如果存在网格,无法访问等之一,则应该与同一行中所有其他单元格的'和'条件组合应该为空,但我无法确定如何实现此

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

这应该有效。我将默认值设置为1,然后将值设置为零(如果只有空格),或者除了一个之外只有空白,并且此异常值适合您的正则表达式。

df <- data.frame(c("Utility grid", "Grid connection", "Grid", "", "", "Dry-cell-torch", "Solar", ""), c("solar", "", "", "", "", "", "Dry-cell-torch", ""), c("", "fan", "TV", "", "Utility grid connection", "", "", "Unreachable"), c("", "radio", "", "", "", "", "", "")) 
colnames(df) <- c(paste("de_", 1:4, sep=""))
df$de <- 1 # default value
blank_rows <- apply(df,1,function(row){sum(row == "")==ncol(df)-1})
regex_rows <- apply(df,1,function(row){sum(row == "")==ncol(df)-2 & any(grepl("grid|Unreachable|Dry-cell-torch|^$", row,ignore.case = TRUE))})
df$de[blank_rows | regex_rows] <- 0

# de_1           de_2                    de_3  de_4 de
# 1    Utility grid          solar                                1
# 2 Grid connection                                    fan radio  1
# 3            Grid                                     TV        1
# 4                                                               0
# 5                                Utility grid connection        0
# 6  Dry-cell-torch                                               0
# 7           Solar Dry-cell-torch                                1
# 8                                            Unreachable        0

答案 1 :(得分:1)

考虑明确分割条件:

f <- function(x) {
  if ( all(x == '') ) 0
  else if ( sum(x != '') == 1 ) {
    if ( grepl('grid', tolower(x[x != ''])) |
         (x[x != ''] %in% c('Unreachable', 'Dry-cell-torch')) ) 0
    else 1
  } 
  else 1
}

然后使用apply apply(df, 1, f)

我似乎得到了你想要的矢量:

> apply(df, 1, f)
[1] 1 1 1 0 0 0 1 0

<强>更新

可以使用另一个参数来索引f中所需的特定列。请注意,这不是一个强大的实现 - 设置错误的列会破坏它。

f <- function(x, columns) {

  y <- x[columns]

  if ( all(y == '') ) 0
  else if ( sum(y != '') == 1 ) {
    if ( grepl('grid', tolower(y[y != ''])) |
         (y[y != ''] %in% c('Unreachable', 'Dry-cell-torch')) ) 0
    else 1
  } 
  else 1
}

然后使用apply apply(df, 1, f, columns = 1:4)。只需将1:4替换为您想要的列。

更新2:

不确定我是否完全理解您的最新评论,但如果您想考虑多个“特殊”单元格,您可以考虑以下结构(虽然我不确定它是否会比“优雅”更加“优雅”你尝试了什么):

f <- function(x, columns) {

  y <- x[columns]

  n.not.blank <- sum( y != '' )
  special <- c('Unreachable', 'Dry-cell-torch')
  n.special <- sum( grepl('grid', tolower(y)) | (y %in% special) )

  if (n.not.blank == 0) 0
  else if (n.not.blank == n.special) 0
  else 1

}

然后像以前一样使用apply。