使用数据框中的不同值替换字符串的某些相等元素

Replacement of some equal elements of a string using different values in a data frame

我想用 'a' 列中的每个元素替换 'test' 数据框的 'b' 列中的每个 'COL' 单词,并将结果放入在其他列中,但保留列 'b'.

的字符串的顺序和结构
test <- data.frame(a = c("COL167", "COL2010;COL2012"),
                   b = c("COL;MO, K", "P;COL, NY, S, COL"))

我尝试了以下方法,但不是我需要的结果:

for(i in 1:length(test$a)){
    test$c[i] <- gsub(pattern = "COL", x = test$b[i], replacement = test$a[i])
}

> test
                a                  b                                          c
1          COL167          COL;MO, K                               COL167;MO, K
2 COL2010;COL2012  P;COL, NY, S, COL  P;COL2010;COL2012, NY, S, COL2010;COL2012

我希望得到以下结果:

              a                  b                          c
1          COL167          COL;MO, K               COL167;MO, K
2 COL2010;COL2012  P;COL, NY, S, COL  P;COL2010, NY, S, COL2012

基于您已经完成的工作,我认为这可行,但请注意,如果您的 table 很大,您可能会遇到一些性能问题。另请注意,这假定要替换的值的大小等于用于替换的值。

由于gsub不允许向量化替换(用替换的第一个值替换所有匹配的实例),这里我将字符串和替换都转换为向量,所以我可以单独替换每个匹配的子字符串.

test <- data.frame(a = c("COL167", "COL2010;COL2012"),
                   b = c("COL;MO, K", "P;COL, NY, S, COL"))

re = function(string, replacement){
  gsub('COL', replacement, string)
}

for(i in 1:nrow(test)){
  #splitting values of column a into vector, this is required for replacement
  replacement = unlist(strsplit(test$a[i], ';'))
  
  #split values of column b into vecto, this is required for replacement
  b_value = unlist(strsplit(test$b[i], ' '))
  
  #select those which have 'COL' substring
  ind_to_replace = which(grepl('COL', b_value))
  
  #replace matched values
  result = mapply(re, b_value[ind_to_replace], replacement)
  
  #replace the column b value with new string
  b_value[ind_to_replace] = result
  
  #join the string
  test$results[i] = paste(b_value, collapse = ' ')
}

test
#>                 a                 b                   results
#> 1          COL167         COL;MO, K              COL167;MO, K
#> 2 COL2010;COL2012 P;COL, NY, S, COL P;COL2010, NY, S, COL2012

reprex package (v0.3.0)

于 2020-09-05 创建

我将使用 dplyrrowwise 函数提出一个解决方案。

虽然 gsub 确实没有矢量化,但同名包中的 mgsub 函数是矢量化的。我的方法是每一行:

  1. 将 b 列中的所有 COL 实例转换为向量

  2. 从 a 列的所有 COL+ 条目创建一个向量

  3. 使用向量 2 替换 b 中 COL 的旧值。 mutate 使用结果创建一个新列。

     library(mgsub)        
     library(stringr)
     library(dplyr)
    
     test %>%
     rowwise() %>%
     mutate(new_col = 
         unlist((mgsub(b,
               unlist(str_extract_all(b,"COL")),
               unlist(str_extract_all(a,"COL.*?\b")))
      )))
    
      # A tibble: 2 x 3
      # Rowwise: 
         a               b                 new_col                  
       <chr>           <chr>             <chr>                    
    1 COL167          COL;MO, K         COL167;MO, K             
    2 COL2010;COL2012 P;COL, NY, S, COL P;COL2010, NY, S, COL2010
    

mgsub 有 3 个参数。您正在处理的字符串、要在该字符串中替换的表达式以及要用作替换的表达式。这个包允许你有多个模式来替换和被替换——两者都可以显示为矢量。

我将此函数应用于每一行 - 首先我将 b 列指定为感兴趣的字符串。其次,b 列中的所有 COL 都是我们要替换的内容,我使用 stringr::str_extract_all 将其制作成一个向量。我提取了 COL 的所有实例,然后我们必须取消列出此输出,因为 str_extract_all returns 是一个列表。第三,我使用相同的过程从 a 列中提取 COL+ 条目。总之,我们使用 a 列中的条目替换 b 列中感兴趣的字符。

    "COL.*?\b" 

选择字母 COL 后跟尽可能少的字符,然后到达单词边界,这样我们就可以将 a 列中的条目变成多个项目(COL2010、COL2012 等)。

我们必须取消列出变异的行(即第一个“取消列出”),因为 dplyr 输出 list-column.