根据条件用一列中的多个元素替换

时间:2020-03-04 13:35:39

标签: r search replace

替换数据框的列中的值时遇到一些问题。

我有两个看起来像这样的数据框:

结果表:

r <- data.frame(d = c("100", "100,111", "100,111,123"), r = c("3", "3,6,7", "42,57"))

映射表:

m <- data.frame(id = c("3", "6", "7", "42", "57", "100", "111", "123"), name= c("tc1", "tc2", "tc3", "tc4", "tc5", "tc6", "tc7", "tc8"))

现在,我希望基于m$name中的匹配项/部分匹配项,将r$d中的字符串替换为r$rm$id中的数字,其中最困难的部分是我自己,则可以出现多个数字。

示例:元组“ 100,111”,“ 3,6,7”最后应为“ tc6,tc7”,“ tc1,tc2,tc3”。

任何帮助将不胜感激。

5 个答案:

答案 0 :(得分:4)

gsubfn将替换其第一个参数中模式的每个匹配项,并用第二个参数中给定列表中与该名称对应的值替换该匹配项。我们lapplyr的每一列。

library(gsubfn)

L <- with(m, as.list(setNames(as.character(name), id)))
replace(r, TRUE, lapply(r, function(x) gsubfn("\\d+", L, as.character(x)))

给予:

            d           r
1         tc6         tc1
2     tc6,tc7 tc1,tc2,tc3
3 tc6,tc7,tc8     tc4,tc5

注意

如果rm的列是字符而不是要素,那么我们可以简化一下。

m[] <- lapply(m, as.character)
r[] <- lapply(r, as.character)

L <- with(m, as.list(setNames(name, id)))
r[] <- lapply(r, gsubfn, pattern = "\\d+", replacement = L)

,或者如果您要保留输入r

,请在最后一行使用它
replace(r, TRUE, lapply(r, gsubfn, pattern = "\\d+", replacement = L))

答案 1 :(得分:3)

这里是一个使用底R的衬里,

r[] <- lapply(r, function(i) sapply(strsplit(as.character(i), ','), 
                                function(j)paste(m$name[match(j, m$id)], collapse = ',')))

给出,

            d           r
1         tc6         tc1
2     tc6,tc7 tc1,tc2,tc3
3 tc6,tc7,tc8     tc4,tc5

答案 2 :(得分:2)

一种tidyverse方法是获取长格式的列,基于逗号分隔行,group_by每行和每一列,并创建一个以逗号分隔的字符串。最后,我们再次获得宽格式的数据。

library(dplyr)
library(tidyr)

r %>%
  mutate(row = row_number()) %>%
  pivot_longer(cols = -row, values_to = 'id') %>%
  separate_rows(id, sep = ",", convert = TRUE)  %>%
  left_join(m %>% 
             type.convert(as.is = TRUE), by = 'id')  %>%
  group_by(row, name.x)  %>%
  summarise(name = toString(name.y)) %>%
  pivot_wider(names_from = name.x, values_from = name) %>%
  ungroup %>%
  select(-row)

# A tibble: 3 x 2
#  d             r            
#  <chr>         <chr>        
#1 tc6           tc1          
#2 tc6, tc7      tc1, tc2, tc3
#3 tc6, tc7, tc8 tc4, tc5     

答案 3 :(得分:1)

这是使用apply函数的基本R方式。我们可以在lapplyd列上使用r(仅显示d的代码),然后迭代带有替换项的术语数据框。然后,我们为找到的每个术语/替换调用sub

r$d <- lapply(r$d, function(x) {
    apply(m, 1, function(y) {
        x <<- gsub(paste0("\\b", y[1], "\\b"), y[2], x)
    })
    return(x)
})
r

               d     r
1         tc6     3
2     tc6,tc7 3,6,7
3 tc6,tc7,tc8 42,57

数据:

r <- data.frame(d = c("100", "100,111", "100,111,123"), r = c("3", "3,6,7", "42,57"), stringsAsFactors=FALSE)
m <- data.frame(id = c("3", "6", "7", "42", "57", "100", "111", "123"), name= c("tc1", "tc2", "tc3", "tc4", "tc5", "tc6", "tc7", "tc8"))

请注意,使用<<-父作用域赋值运算符通常是邪恶的,但是在这种情况下,我使用它来引用对lapply的外部调用中定义的作用域,所以也许是更可接受。

答案 4 :(得分:1)

使用基数R的建议解决方案:

r <- data.frame(d = c("100", "100,111", "100,111,123"), r = c("3", "3,6,7", "42,57"))
m <- data.frame(id = c("3", "6", "7", "42", "57", "100", "111", "123"), name= c("tc1", "tc2", "tc3", "tc4", "tc5", "tc6", "tc7", "tc8"))

将因素转换为字符:

m <- apply(m, 2, as.character)
r <- apply(r, 2, as.character)

遍历每个单元格,并使用m替换元组的元素:

result <- r
for (i in seq_along(r[, 1])) {
  for (j in seq_along(r[1, ])) {
    result[i, j] <- paste0(sapply(strsplit(r[i, j], ","), function(x) m[m[, 1] %in% x, 2]), collapse=", ")
  }
}

result现在是:

     d               r              
[1,] "tc6"           "tc1"          
[2,] "tc6, tc7"      "tc1, tc2, tc3"
[3,] "tc6, tc7, tc8" "tc4, tc5"