3

我有一个包含 95 列的数据框,并且想用简单的正则表达式批量重命名其中的很多,就像底部的代码段一样,有大约 30 行这样的行。任何其他与搜索正则表达式不匹配的列都必须保持不变。

**** 示例:names(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 文档,但找不到任何东西......然后当我发布它时,我想搜索 '[r] translation table' 并找到xlategrep/sub/gsub文档中的任何地方都没有提到。

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

  2. 你能把我笨拙的语法改进为对 tr 的引用调用吗?(不得创建整个 df 的临时副本)


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

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

我可以使用gsub()strsplit()在 '_' 上拆分,然后在最后一个组件上进行xlate翻译,然后将它们粘贴在一起。寻找更干净的 1/2 行成语。

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

4

3 回答 3

4

Wall ofgsub可以始终替换为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'))
)

而且我发现比创建这种字符串sprintf更有用。paste

于 2012-05-04T22:21:17.023 回答
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
于 2021-01-04T23:09:34.887 回答
0

使用do.call()几乎可以做到这一点,它反对不同的 arg 长度。我想我需要嵌套do.call()在里面apply(),就像在将函数应用于列表中的元素一样。

但我需要部分do.call()过度模式并替换。

这一切都开始使 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
于 2012-05-04T21:11:01.563 回答