对数据帧的共同名称执行多次搜索和替换

时间:2012-05-04 19:56:13

标签: regex r dataframe batch-rename

我有一个95 cols的数据框,并希望用简单的正则表法批量重命名它们,比如底部的代码片段,有大约30个这样的行。任何其他与搜索正则表达式不匹配的列都必须保持不变。

****示例:姓名(tr)= c('foo','bar','xxx_14','xxx_2001','yyy_76','baz','zzz_22',...)** **

我从一个25 gsub()s的墙开始 - 粗糙但有效:

names(tr) <- gsub('_1$',    '_R', names(tr))
names(tr) <- gsub('_14$',   '_I', names(tr))
names(tr) <- gsub('_22$',   '_P', names(tr))
names(tr) <- gsub('_50$',   '_O', names(tr))
... yada yada

@Joshua:mapply不起作用,事实证明它更复杂,也不可能进行矢量化。 names(tr)包含其他列,当这些模式确实发生时,您不能假设所有这些模式都出现,更不用说我们定义它们的确切顺序了。因此,尝试2是:

pattern <- paste('_', c('1','14','22','50','52','57','76','1018','2001','3301','6005'), '$', sep='')
replace <- paste('_', c('R','I', 'P', 'O', 'C', 'D', 'M', 'L',   'S',   'K',   'G'),         sep='')
do.call(gsub, list(pattern, replace, names(tr)))
Warning messages:
1: In function (pattern, replacement, x, ignore.case = FALSE, perl = FALSE,  :
  argument 'pattern' has length > 1 and only the first element will be used
2: In function (pattern, replacement, x, ignore.case = FALSE, perl = FALSE,  :
  argument 'replacement' has length > 1 and only the first element will be used

任何人都可以帮我解决这个问题吗?


编辑:我在这个主题上读了SO和R doc一天多了,找不到任何东西......然后当我发布它时,我想找到'[r]翻译表',我发现< EM> XLATE 。 grep / sub / gsub 文档中的任何地方都没有提到。

  1. base/gsubfn/data.table 等有什么可以让我写一个搜索和替换指令吗? (如字典或翻译表)

  2. 你能改进我笨重的语法,以便通过引用来调用tr吗? (不得创建整个df的临时副本)


  3. EDIT2:我阅读后的最大努力是:

    字典方法( xlate )可能是部分答案,但这不仅仅是一个简单的翻译表,因为正则表达式必须是终端(例如'_14 $')。

    我可以使用 gsub() strsplit()拆分“_”然后在最后一个组件上执行 xlate 转换,然后粘贴()将它们放回原处。寻找更干净的1/2线习语。

    否则我只使用 gsub()s 的墙。

3 个答案:

答案 0 :(得分:4)

gsub的墙可以始终由for-loop替换。你可以把它写成一个函数:

renamer <- function(x, pattern, replace) {
    for (i in seq_along(pattern))
            x <- gsub(pattern[i], replace[i], x)
    x
}

names(tr) <- renamer(
     names(tr),
     sprintf('_%s$', c('1','14','22','50','52','57','76','1018','2001','3301','6005')),
     sprintf('_%s' , c('R','I', 'P', 'O', 'C', 'D', 'M', 'L',   'S',   'K',   'G'))
)

我发现sprintfpaste更有用于创建这种字符串。

答案 1 :(得分:1)

这个问题早于 tidyverse 的繁荣,但使用 c(pattern1 = replacement1) 中的 stringr::str_replace_all 选项很容易解决这个问题。

tr <- data.frame("whatevs_1" = NA, "something_52" = NA)

tr
#>   whatevs_1 something_52
#> 1        NA           NA

patterns <- sprintf('_%s$', c('1','14','22','50','52','57','76','1018','2001','3301','6005'))
replacements <- sprintf('_%s' , c('R','I', 'P', 'O', 'C', 'D', 'M', 'L',   'S',   'K',   'G'))
                        
names(replacements) <- patterns

names(tr) <- stringr::str_replace_all(names(tr), replacements)

tr
#>   whatevs_R something_C
#> 1        NA          NA

当然,这个特殊情况可以受益于 dplyr

dplyr::rename_all(tr, stringr::str_replace_all, replacements)
#>   whatevs_R something_C
#> 1        NA          NA

答案 2 :(得分:0)

使用 do.call() 几乎可以做到,它反对不同的arg长度。我想我需要在 do.call() 中嵌套 apply() ,就像apply function to elements over a list一样。

但我需要部分 do.call() over pattern并替换。

这一切都开始使gsub(...,fixed = TRUE)的墙看起来像一个更有效的习语,如果松弛的代码。

pattern <- paste('_', c('1','14','22','50'), '$', sep='')
replace <- paste('_', c('R','I', 'P', 'O'),       sep='')
do.call(gsub, list(pattern, replace, names(tr)))
Warning messages:
1: In function (pattern, replacement, x, ignore.case = FALSE, perl = FALSE,  :
  argument 'pattern' has length > 1 and only the first element will be used
2: In function (pattern, replacement, x, ignore.case = FALSE, perl = FALSE,  :
  argument 'replacement' has length > 1 and only the first element will be used