我有一个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
任何人都可以帮我解决这个问题吗?
base/gsubfn/data.table
等有什么可以让我写一个搜索和替换指令吗? (如字典或翻译表)
你能改进我笨重的语法,以便通过引用来调用tr吗? (不得创建整个df的临时副本)
EDIT2:我阅读后的最大努力是:
字典方法( xlate )可能是部分答案,但这不仅仅是一个简单的翻译表,因为正则表达式必须是终端(例如'_14 $')。
我可以使用 gsub()或 strsplit()拆分“_”然后在最后一个组件上执行 xlate 转换,然后粘贴()将它们放回原处。寻找更干净的1/2线习语。
否则我只使用 gsub()s 的墙。
答案 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'))
)
我发现sprintf
比paste
更有用于创建这种字符串。
答案 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