我正在尝试通过循环遍历其他数据帧中定义的正则表达式来清除某些数据帧中混乱的自由格式捕获的字符串。例如:
id <- c(1, 2, 3, 4)
text <- c(NA, "messy1 messy2", "MESSY2,,, messy1", "ignore")
df <- data.frame(id, text)
mapin <- c("messy1", "messy2")
mapout <- c("Clean 1", "Clean 2")
map <- data.frame(mapin, mapout)
cout <- c(NA, "Clean 1, Clean 2", "Clean 1, Clean 2", NA)
我想通过正则表达式df$cout
中的匹配标记(忽略大小写)创建新列map$mapin
,并在连接字符串中从map$mapout
输出相应的已清理标记,其中输出标记按字母顺序排序。在我看来,凌乱的数据帧列上的复制/正则表达式替换会更加痛苦,因为所有其他非匹配的东西都必须以某种方式被丢弃。
任何人都可以看到一个好的 R / vectorised / 非hammy 这样做的方法吗?
答案 0 :(得分:1)
使用stri_extract_all
中的stringi
- 包:
library(stringi)
m1 <- sapply(map$mapin, function(x) stri_extract_all_fixed(tolower(df$text), x))
m2 <- matrix(map$mapout[match(m1, map$mapin)], ncol = nrow(map))
vec <- apply(m2, 1, function(x) paste(na.omit(x), collapse = ", ") )
vec[vec == ''] <- NA
df$cout <- vec
你得到:
> df
id text cout
1 1 <NA> <NA>
2 2 messy1 messy2 Clean 1, Clean 2
3 3 MESSY2,,, messy1 Clean 1, Clean 2
4 4 ignore <NA>
答案 1 :(得分:0)
根据@ Jaap的优秀答案,在我的问题域中进行了一些调整,但这些调整可能对其他人来说很常见&#39;挑战:
创建矩阵m2
时动态确定地图的大小。
对输出标记进行一致排序。
使用stri_extract_first_fixed
对重复的输入令牌不敏感。
完整示例:
# Problem
id <- c(1, 2, 3, 4)
text <- c(NA, "messy1 messy2", "MESSY2,,, messy1,messy1", "ignore")
df <- data.frame(id, text)
mapin <- c("messy2", "messy1")
mapout <- c("Clean 2", "Clean 1")
map <- data.frame(mapin, mapout)
# Solution
m1 <- sapply(map$mapin, function(x) stri_extract_first_fixed(tolower(df$text), x))
m2 <- matrix(map$mapout[match(m1, map$mapin)], ncol = nrow(map))
vec <- apply(m2, 1, function(x)
paste0(c(unique(sort(x, na.last = NA)), use.names = FALSE), collapse = ", "))
vec[vec==''] <- NA
df$clean <- vec
Per @ r2evans&#39;上面的评论,如果您需要正则表达式,只需将stri_extract_first_fixed
替换为stri_extract_first_regex
。