R,带有ifelse和grepl函数的for循环没有给出预期的结果
R, for loop with ifelse and grepl function does not give expected results
我正在尝试查找具有 my_list 和数据框 (df) 的匹配字符串,并且根据 TRUE/FALSE 我需要在 df 中填充 new_name 列,并在匹配中使用第一个字符串列表 (my_list[[i]][1]) 如果 TRUE ,或 "cat" 列值如果不匹配。
我的数据框如下:
name <- c("NETFLIX.COM", "BlueTV", "smv", "trafi", "alkatel")
cat<- c("none", "none", "none", "transportation", "communication")
df<-data.frame(name, cat)
我的名单:
travel<- c("travel","air_com", "AIRCAT", "tivago")
leasure<- c("leasure","MTV", "NETFLIX.COM")
my_list<- list(travel, leasure)
我使用 ifelse 和 grepl 的 for 循环如下:
for (j in 1:nrow(df)) {
for (i in 1:length(my_list)) {
df[j, "new_name"]<- ifelse(
grepl(paste(my_list[[i]], collapse="|"), tolower(df[j, "name"])),
my_list[[i]][1],
df[j, "cat"])
预期输出为:
df["new_name"]<- c("leasure", "none", "none", "transportation", "communication")
df
name cat new_name
1 NETFLIX.COM none leasure
2 BlueTV none none
3 smv none none
4 trafi transportation transportation
5 alkatel communication communication
目前,通过我编写的 for 循环,我获得了“cat”列的精确副本,这意味着所有情况在 ifelse 函数中都被视为不匹配 (FALSE)。我注意到这里出了什么问题......
如有任何帮助,我们将不胜感激!
这是使用 stringr::str_replace_all
-
的一种方法
travel<- c("travel","air_com", "AIRCAT", "tivago")
leasure<- c("leasure","MTV", "NETFLIX.COM")
#Create a named list
my_list<- dplyr::lst(travel, leasure)
result <- stringr::str_replace_all(df$name, setNames(names(my_list),
sapply(my_list, paste0, collapse = '|')))
#If the result is same as original value keep the previous cat.
df$new_name <- ifelse(result == df$name, df$cat, result)
df
# name cat new_name
#1 NETFLIX.COM none leasure
#2 BlueTV none none
#3 smv none none
#4 trafi transportation transportation
#5 alkatel communication communication
这里重要的部分是这段代码-
setNames(names(my_list), sapply(my_list, paste0, collapse = '|'))
#travel|air_com|AIRCAT|tivago leasure|MTV|NETFLIX.COM
# "travel" "leasure"
这意味着每当在字符串中遇到模式 travel|air_com|AIRCAT|tivago
时,它将 return "travel"
作为输出,与 "leasure"
.
相同
在这种情况下使用 ifelse()
没有意义:它用于矢量化选择。但是如果你有正确的模式匹配,你的代码就会工作。不幸的是,对于 j == 1
和 i == 2
(当您期望匹配时),您的模式是
"leasure|MTV|NETFLIX.COM"
并且您正在尝试将其匹配到 tolower(df[j, "name"])
,即
"netflix.com"
您应该将两个字符串都映射为小写,或者在 grepl()
调用中设置 ignore.case = TRUE
。例如,
name <- c("NETFLIX.COM", "BlueTV", "smv", "trafi", "alkatel")
cat<- c("none", "none", "none", "transportation", "communication")
df<-data.frame(name, cat)
travel<- c("travel","air_com", "AIRCAT", "tivago")
leasure<- c("leasure","MTV", "NETFLIX.COM")
my_list<- list(travel, leasure)
for (j in 1:nrow(df)) {
for (i in 1:length(my_list)) {
df[j, "new_name"] <-
if( grepl(paste(my_list[[i]], collapse="|"), df[j, "name"],
ignore.case = TRUE))
my_list[[i]][1]
else df[j, "cat"]
}
}
df
#> name cat new_name
#> 1 NETFLIX.COM none leasure
#> 2 BlueTV none none
#> 3 smv none none
#> 4 trafi transportation transportation
#> 5 alkatel communication communication
由 reprex package (v2.0.0)
于 2021-08-10 创建
一般来说,使用模式匹配来查找字符串是否在列表中是很棘手的;请务必小心,不要让 my_list
中的字符串包含任何 grepl()
在正则表达式中视为特殊的字符。对于您的示例,您将获得与 grepl()
使用测试
给出的结果相同的结果
tolower(df[j, "name"]) %in% tolower(my_list[[i]])
但这并非适用于所有可能的 name
值:grepl()
代码将允许部分匹配(例如 df[i, "name"]
等于 "netflix.com in a long string"
)和 %in%
不会。
我正在尝试查找具有 my_list 和数据框 (df) 的匹配字符串,并且根据 TRUE/FALSE 我需要在 df 中填充 new_name 列,并在匹配中使用第一个字符串列表 (my_list[[i]][1]) 如果 TRUE ,或 "cat" 列值如果不匹配。
我的数据框如下:
name <- c("NETFLIX.COM", "BlueTV", "smv", "trafi", "alkatel")
cat<- c("none", "none", "none", "transportation", "communication")
df<-data.frame(name, cat)
我的名单:
travel<- c("travel","air_com", "AIRCAT", "tivago")
leasure<- c("leasure","MTV", "NETFLIX.COM")
my_list<- list(travel, leasure)
我使用 ifelse 和 grepl 的 for 循环如下:
for (j in 1:nrow(df)) {
for (i in 1:length(my_list)) {
df[j, "new_name"]<- ifelse(
grepl(paste(my_list[[i]], collapse="|"), tolower(df[j, "name"])),
my_list[[i]][1],
df[j, "cat"])
预期输出为:
df["new_name"]<- c("leasure", "none", "none", "transportation", "communication")
df
name cat new_name
1 NETFLIX.COM none leasure
2 BlueTV none none
3 smv none none
4 trafi transportation transportation
5 alkatel communication communication
目前,通过我编写的 for 循环,我获得了“cat”列的精确副本,这意味着所有情况在 ifelse 函数中都被视为不匹配 (FALSE)。我注意到这里出了什么问题...... 如有任何帮助,我们将不胜感激!
这是使用 stringr::str_replace_all
-
travel<- c("travel","air_com", "AIRCAT", "tivago")
leasure<- c("leasure","MTV", "NETFLIX.COM")
#Create a named list
my_list<- dplyr::lst(travel, leasure)
result <- stringr::str_replace_all(df$name, setNames(names(my_list),
sapply(my_list, paste0, collapse = '|')))
#If the result is same as original value keep the previous cat.
df$new_name <- ifelse(result == df$name, df$cat, result)
df
# name cat new_name
#1 NETFLIX.COM none leasure
#2 BlueTV none none
#3 smv none none
#4 trafi transportation transportation
#5 alkatel communication communication
这里重要的部分是这段代码-
setNames(names(my_list), sapply(my_list, paste0, collapse = '|'))
#travel|air_com|AIRCAT|tivago leasure|MTV|NETFLIX.COM
# "travel" "leasure"
这意味着每当在字符串中遇到模式 travel|air_com|AIRCAT|tivago
时,它将 return "travel"
作为输出,与 "leasure"
.
在这种情况下使用 ifelse()
没有意义:它用于矢量化选择。但是如果你有正确的模式匹配,你的代码就会工作。不幸的是,对于 j == 1
和 i == 2
(当您期望匹配时),您的模式是
"leasure|MTV|NETFLIX.COM"
并且您正在尝试将其匹配到 tolower(df[j, "name"])
,即
"netflix.com"
您应该将两个字符串都映射为小写,或者在 grepl()
调用中设置 ignore.case = TRUE
。例如,
name <- c("NETFLIX.COM", "BlueTV", "smv", "trafi", "alkatel")
cat<- c("none", "none", "none", "transportation", "communication")
df<-data.frame(name, cat)
travel<- c("travel","air_com", "AIRCAT", "tivago")
leasure<- c("leasure","MTV", "NETFLIX.COM")
my_list<- list(travel, leasure)
for (j in 1:nrow(df)) {
for (i in 1:length(my_list)) {
df[j, "new_name"] <-
if( grepl(paste(my_list[[i]], collapse="|"), df[j, "name"],
ignore.case = TRUE))
my_list[[i]][1]
else df[j, "cat"]
}
}
df
#> name cat new_name
#> 1 NETFLIX.COM none leasure
#> 2 BlueTV none none
#> 3 smv none none
#> 4 trafi transportation transportation
#> 5 alkatel communication communication
由 reprex package (v2.0.0)
于 2021-08-10 创建一般来说,使用模式匹配来查找字符串是否在列表中是很棘手的;请务必小心,不要让 my_list
中的字符串包含任何 grepl()
在正则表达式中视为特殊的字符。对于您的示例,您将获得与 grepl()
使用测试
tolower(df[j, "name"]) %in% tolower(my_list[[i]])
但这并非适用于所有可能的 name
值:grepl()
代码将允许部分匹配(例如 df[i, "name"]
等于 "netflix.com in a long string"
)和 %in%
不会。