Grepl 匹配多个条件包括 'and' 和 'or' 条件
Grepl matching for multiple conditions including 'and' and 'or' conditions
我的dataframe如下
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 行中的非空白,并且该值是 'contains' "grid" 不区分大小写,或者是 "Unreachable",或者是"Dry-cell-torch",那么"de"应该是0.
条件3.否则"de"应该是1
所需的 "de" 应该是
df$de <- (c(1, 1, 1, 0, 0, 0, 1, 0))
请注意我的原始数据框是 600 行和 45 列。我只是在这里放一个子集,但这个子集说明了我想要完成的详尽条件。
所以我使用 grepl 尝试了以下正则表达式(改编自你们中的一个人在 Whosebug 上针对不同但相似的问题给出的解决方案)-
df$de <- (!grepl("grid|Unreachable|Dry-cell-torch|^$",
apply(df,1,paste, collapse=""), ignore.case=TRUE))+0L
除了在第 1 行中有 "Utility grid",第二列中有 "solar" 的情况外,这有效1.我理解这个问题 - 如果存在网格,无法访问等之一,这应该与同一行中所有其他单元格的 'and' 条件相结合,但我无法弄清楚如何实施这个
感谢您的帮助!
这应该有效。我将默认值设置为 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
考虑明确拆分条件:
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(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(df, 1, f, columns = 1:4)
。只需将 1:4 替换为您想要的列即可。
更新二:
不确定我是否完全理解你最近的评论,但如果你想考虑多个 "special" 单元格,你可以考虑以下结构(虽然我不确定它是否会更多"elegant" 比你试过的要好):
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。
我的dataframe如下
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 行中的非空白,并且该值是 'contains' "grid" 不区分大小写,或者是 "Unreachable",或者是"Dry-cell-torch",那么"de"应该是0.
条件3.否则"de"应该是1
所需的 "de" 应该是
df$de <- (c(1, 1, 1, 0, 0, 0, 1, 0))
请注意我的原始数据框是 600 行和 45 列。我只是在这里放一个子集,但这个子集说明了我想要完成的详尽条件。
所以我使用 grepl 尝试了以下正则表达式(改编自你们中的一个人在 Whosebug 上针对不同但相似的问题给出的解决方案)-
df$de <- (!grepl("grid|Unreachable|Dry-cell-torch|^$",
apply(df,1,paste, collapse=""), ignore.case=TRUE))+0L
除了在第 1 行中有 "Utility grid",第二列中有 "solar" 的情况外,这有效1.我理解这个问题 - 如果存在网格,无法访问等之一,这应该与同一行中所有其他单元格的 'and' 条件相结合,但我无法弄清楚如何实施这个
感谢您的帮助!
这应该有效。我将默认值设置为 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
考虑明确拆分条件:
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(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(df, 1, f, columns = 1:4)
。只需将 1:4 替换为您想要的列即可。
更新二:
不确定我是否完全理解你最近的评论,但如果你想考虑多个 "special" 单元格,你可以考虑以下结构(虽然我不确定它是否会更多"elegant" 比你试过的要好):
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。