【问题标题】:Grepl matching for multiple conditions including 'and' and 'or' conditionsGrepl 匹配多个条件,包括 'and' 和 'or' 条件
【发布时间】:2017-10-31 02:18:00
【问题描述】:

我的数据框如下

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 行中说,在 1 列中我有“公用事业网格”,而在第二列中我有“太阳能”,它给我 de 为 0 而我需要 1。我理解问题 - 如果存在网格、无法访问等之一,则应与同一行中所有其他单元格的“和”条件相结合,但我无法弄清楚如何实现这一点

感谢您的帮助!

【问题讨论】:

  • 你说了很多行而不是列,你能清理你的问题吗?
  • 我对您在条件 2 中寻找的内容感到困惑。如果您正在检查 4 列中的任何一列是否有值,然后检查这些值是否为“无法访问”或“干电池火炬”或包含“网格”。那么对于您的示例,每个 de 值都是 0。
  • 穆迪,那是因为我打算将它作为行而不是列。所以我希望 R 代码遍历 4 列中的每一行,并检查列出的 3 个条件,并相应地为 de 赋值。马特,在条件 2 中,如果任何列是“无法到达”或“干电池火炬”或包含“网格”,并且如果列除了这些值之外还有非空白值,则 de 应为 1,否则 de应该是 0。

标签: r contains grepl


【解决方案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。

【讨论】:

  • 感谢 Ssokolen!这是一个很好的解决方案。我的数据框是 45 列和 600 行。就列的顺序而言,有问题的 4 列是列 33:36。这个解决方案可以适应列的子集吗?
  • @user3816784 当然,有几种方法可以做到这一点。您可以简单地从函数中索引 x 或添加一个新参数以更一般的方式执行此操作。我将根据更改编辑我的答案。
  • 感谢 Ssokolen!感谢您提供编辑后的答案。代码工作正常,除了在一种情况下 - 其中两列非空,一列假设包含“网格”,另一列是“无法访问”,其他列是空白的。为了使 de 为 1,我需要至少一个非空白列,它不包含网格,并且不是不可到达的和干电池火炬。我可以通过为每列编写几个 if else 语句来做到这一点,但我想知道是否有更优雅的解决方案。谢谢!
  • @user3816784 我不确定当我对答案进行编辑时是否会收到通知,但请查看最新更新。
  • 感谢 Ssokolen!您的解决方案非常直观,非常适合。很抱歉这么晚才承认这一点。我一直在旅行,刚刚回到代码。我已接受您的解决方案作为答案。
【解决方案2】:

这应该可行。我将默认值设置为 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

【讨论】:

  • 谢谢!这确实有效,我可以看到它如何有助于打破不同代码行中的条件。我正在尝试慢慢理解 blank_rows 和 regex_rows 的代码,并有以下问题(我还是个初学者!)。 Q1 - 您在 apply 中分配了一个函数,但您没有在任何地方使用任何参数调用此函数?它是如何工作的。
  • Q2 - 在 LHS 上的代码“sum(row == "")==ncol(df)-1”的过去,您正在分配一个对象,但该对象也在执行一个操作那个怎么样?我的意思是LHS上的对象只接受RHS上的操作,操作是如何在“
  • row == "" 返回布尔值数组,取它们的总和返回真值的计数(此处为空白值)
  • 如果此数量等于您的df中的列数,则该行为空白,除了我添加的de列,因此ncol(df)-1
  • == 不是赋值运算符,请确保您理解 :)
猜你喜欢
  • 2019-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-25
相关资源
最近更新 更多