R语言中基于原列名动态重命名数据框列名的实现问题
动态批量修改数据框列名的实现问题
问题背景
我有16个格式如下的数据框(通过循环读取.txt文件生成),示例数据:
head(data) # A tibble: 2 x 4 AAA AAC AB AC 1 18 25 39 9 2 20 25 30 7
我希望根据文件名中的特征(比如50、100这类数字)动态修改所有列名,尝试用str_glue实现但报错,以下是循环中无法运行的代码片段:
### 我的for循环代码(无法运行)(循环的一部分) assign(str_glue("df_{str_sub(data[i], 23, - 5)}"), read.delim(data[i], sep = ",", header = T) %>% mutate(ID = Participants, str_glue("New_{str_sub(data[i], 23, - 5)}_AAA") = AAA, str_glue("New_{str_sub(data[i], 23, - 5)}_AAB") = AAC, str_glue("New_{str_sub(data[i], 23, - 5)}_AB") = AB, str_glue("New_{str_sub(data[i], 23, - 5)}_AC") = AC)
期望输出
根据索引i对应的文件名不同,str_glue("New_{str_sub(data[i], 23, - 5)}_AAA")会生成包含50、100或150的列名,比如当i=1时的期望输出:
### i=1时的期望输出 New_50_AAA New_50_AAC New_50_AB New_50_AC 1 18 25 39 9 2 20 25 30 7
我希望找到更优雅的实现方式,最好能避免重复书写原列名,减少代码冗余。
补充说明
完整循环如下:data是16个.txt文件的列表,文件名格式为xxxxxxxxx_xx_50.txt、xxxxxxxxx_xx_100.txt等:
for (i in 1:length(data)) { if (grepl("xxxxxxxxx_x1_.txt$", data[i])) { assign(str_glue("df_narr{str_sub(data[i], 23, - 5)}"), read.delim(data[i], sep = ",", header = T) %>% mutate(ID = Participants, str_glue("New_1{str_sub(data[i], 23, - 5)}_AAA") = AAA, str_glue("New_1{str_sub(data[i], 23, - 5)}_AAB") = AAC, str_glue("New_1{str_sub(data[i], 23, - 5)}_AB") = AB, str_glue("New_1{str_sub(data[i], 23, - 5)}_AC") = AC) %>% mutate_if(is.numeric, round, digits = 2)) } else if (grepl("xxxxxxxxx_x2_.txt$", data[i])) { assign(str_glue("df_narr{str_sub(data[i], 23, - 5)}"), read.delim(data[i], sep = ",", header = T) %>% mutate(ID = Participants, str_glue("New_2{str_sub(data[i], 23, - 5)}_AAA") = AAA, str_glue("New_2{str_sub(data[i], 23, - 5)}_AAB") = AAC, str_glue("New_2{str_sub(data[i], 23, - 5)}_AB") = AB, str_glue("New_2{str_sub(data[i], 23, - 5)}_AC") = AC) %>% mutate_if(is.numeric, round, digits = 2)) } }
解决方案
核心问题分析
当前代码的错误在于:mutate中不能直接用str_glue生成的字符串作为列名,需要使用tidyeval语法处理动态列名;另外重复书写列名导致代码冗余,assign创建零散数据框不利于后续管理。
优化实现步骤
- 提取文件名关键信息:用字符串处理函数获取文件名中的组别(1/2)和数字部分(50/100等),避免硬编码索引位置。
- 用
rename_with批量重命名:无需逐个指定原列名,批量处理目标列,大幅减少冗余代码。 - 用列表存储结果:替代
assign,将所有处理后的数据框存入一个命名列表,方便统一操作。
具体代码示例
library(tidyverse) # 初始化列表存储处理后的结果 processed_dfs <- list() for (file in data) { # 提取组别标识(1或2) group <- ifelse(grepl("xxxxxxxxx_x1_.txt$", file), "1", "2") # 提取文件名中的数字部分 num_part <- str_sub(file, 23, -5) # 读取并处理数据 df <- read.delim(file, sep = ",", header = TRUE) %>% # 保留需要的列并重命名ID select(ID = Participants, AAA, AAC, AB, AC) %>% # 批量重命名目标列 rename_with( ~ str_glue("New_{group}{num_part}_{.x}"), .cols = c(AAA, AAC, AB, AC) ) %>% # 格式化数值 mutate_if(is.numeric, round, digits = 2) # 将结果存入列表,设置对应名称 list_name <- str_glue("df_narr{num_part}") processed_dfs[[list_name]] <- df } # 调用单个数据框示例:processed_dfs$df_narr50
更简洁的批量处理方式(无需循环)
如果所有文件结构一致,可使用map函数批量处理,进一步简化代码:
processed_dfs <- map(data, function(file) { group <- ifelse(grepl("xxxxxxxxx_x1_.txt$", file), "1", "2") num_part <- str_sub(file, 23, -5) read.delim(file, sep = ",", header = TRUE) %>% select(ID = Participants, AAA, AAC, AB, AC) %>% rename_with(~ str_glue("New_{group}{num_part}_{.x}"), c(AAA, AAC, AB, AC)) %>% mutate_if(is.numeric, round, digits = 2) }) %>% # 给列表元素设置对应名称 set_names(str_glue("df_narr{str_sub(data, 23, -5)}"))
内容的提问来源于stack exchange,提问作者Larissa Cury
相关产品推荐
相关产品推荐

