【问题标题】:Perform multiple search-and-replaces on the colnames of a dataframe对数据框的列名执行多次搜索和替换
【发布时间】:2012-05-14 09:08:50
【问题描述】:

我有一个包含 95 列的数据框,并且想用简单的正则表达式批量重命名其中的很多,比如底部的 sn-p,有大约 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] 翻译表”,我发现 xlate。 grep/sub/gsub 文档中的任何地方都没有提到。

  1. base/gsubfn/data.table 等中是否有任何内容可以让我编写一个搜索和替换指令? (如字典或翻译表)

  2. 您能否改进我笨拙的语法,使其成为对 tr 的引用调用? (不得创建整个 df 的临时副本)


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

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

我可以使用 gsub()strsplit() 在 '_' 上拆分,然后对最后一个组件进行 xlate 翻译,然后 paste() 将它们重新组合在一起。寻找更简洁的 1/2 行成语。

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

【问题讨论】:

    标签: regex r dataframe batch-rename


    【解决方案1】:

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

    但我需要部分 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
    

    【讨论】:

      【解决方案2】:

      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 更适合创建这种字符串。

      【讨论】:

      • 如果说sprintfpaste 更有用,我想你的意思是因为我们可以直接给它整数向量?
      • @smci 我在考虑字符串格式:你知道sprintf 的第一个参数的模式是什么。在包含许多元素的 paste 中,有时很难找到结果的样子。
      • @smci 但是是的 - 通过混合类型(数字和字符)提供它是另一个优势。
      • 好点,您可能希望将它们编辑到您的答案中。对我来说最重要的是我们可以直接参数化pattern=vector(int)
      • 这非常有用,我看到您必须明确返回 x 才能使其工作。如何将其扩展到所有需要相同替换模式的 data.frames 列表?
      【解决方案3】:

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

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-24
        • 1970-01-01
        • 2015-06-07
        • 2021-01-31
        • 2016-10-17
        • 1970-01-01
        相关资源
        最近更新 更多