如何用lapply为列表中各DataFrame的每行分配唯一ID?
为DataFrame列表批量添加ID列的高效解决方案
需求背景
现有一个名为files的DataFrame列表,单个DataFrame示例如下:
> head(files[[1]]) HabStruct SAR SYM WYLD 1 23.86667 7.924466 89.67190 95.39818 2 39.13333 9.805045 51.92198 92.27685 3 28.71667 9.440875 79.60088 92.15163 4 32.38333 9.278004 80.52912 93.11543 5 40.31667 8.913012 70.70845 93.45704 6 32.40000 9.518270 79.00460 92.21223 > head(files[[2]]) HabStruct SAR SYM WYLD 1 23.86667 7.924466 89.67190 95.39818 2 31.35000 9.278004 80.31146 92.84485 3 32.01667 9.192081 68.95144 93.64491 4 40.46667 8.705506 69.15392 93.91231 5 33.65000 9.518270 68.43120 92.04382 6 36.33333 9.871752 65.28246 91.16261
需要为列表中每个DataFrame新增ID列,格式为列表索引.行索引,最终效果示例:
> head(files[[1]]) HabStruct SAR SYM WYLD ID 1 23.86667 7.924466 89.67190 95.39818 1.1 2 39.13333 9.805045 51.92198 92.27685 1.2 3 28.71667 9.440875 79.60088 92.15163 1.3 4 32.38333 9.278004 80.52912 93.11543 1.4 5 40.31667 8.913012 70.70845 93.45704 1.5 6 32.40000 9.518270 79.00460 92.21223 1.6 > head(files[[2]]) HabStruct SAR SYM WYLD ID 1 23.86667 7.924466 89.67190 95.39818 2.1 2 31.35000 9.278004 80.31146 92.84485 2.2 3 32.01667 9.192081 68.95144 93.64491 2.3 4 40.46667 8.705506 69.15392 93.91231 2.4 5 33.65000 9.518270 68.43120 92.04382 2.5 6 36.33333 9.871752 65.28246 91.16261 2.6
原嵌套for循环方案效率较低:
for (i in 1:length(files)){ for (j in 1:nrow(files[[i]])){ files[[i]]$ID[j] <- paste(i,j, sep='.') } }
高效解决方案
1. 基础R lapply 实现
利用seq_along遍历列表索引,结合向量化操作批量生成ID列,避免逐行循环:
files <- lapply(seq_along(files), function(i) { df <- files[[i]] # 批量生成ID:列表索引 + 行索引,用点分隔 df$ID <- paste(i, seq_len(nrow(df)), sep = ".") df })
2. purrr 包简洁实现
如果习惯使用tidyverse工具链,purrr::imap可以同时获取DataFrame元素和对应的列表索引,写法更简洁:
library(purrr) library(dplyr) # 写法1:显式函数 files <- imap(files, function(df, list_idx) { mutate(df, ID = paste(list_idx, seq_len(nrow(df)), sep = ".")) }) # 写法2:简化的公式语法 files <- imap(files, ~ mutate(.x, ID = paste(.y, seq_len(nrow(.x)), sep = ".")))
效率说明
上述方案均采用向量化操作,直接为整列赋值,而非逐行修改,在数据量较大时,运行效率远高于嵌套for循环。
内容的提问来源于stack exchange,提问作者Toedi
相关产品推荐
相关产品推荐

