如何基于另一DataFrame的名称匹配筛选目标DataFrame列?
基于分组名匹配筛选DataFrame列(大数据集适配方案)
需求背景
我有两个DataFrame:
- List1:包含
Group(分组名称)和Number两列 - DF1:固定前两列是
Name、Key,后面跟着一堆以分组名为列名的数值列
现在需要保留DF1的Name、Key列,同时只保留DF1中列名能在List1$Group里找到的分组列,把不匹配的列(比如示例里的group2)删掉,而且这个方案得能高效处理大数据集。
示例数据
List1
| Group | Number |
|---|---|
| group1 | 0.5 |
| group3 | 0.6 |
| group4 | 0.8 |
| group5 | 0.9 |
DF1
| Name | Key | group1 | group2 | group3 |
|---|---|---|---|---|
| XAS /// HUA | test1234 | 10 | 10 | 8 |
| MPA1 /// AAS2 | test4553 | 8 | 7 | 4 |
| MPAS | test3341 | 5 | 5 | 5 |
| SSPA1 | test2142 | 5 | 6 | 8 |
| MAS61A | test4722 | 6 | 7 | 4 |
处理后目标结果
| Name | Key | group1 | group3 |
|---|---|---|---|
| XAS /// HUA | test1234 | 10 | 8 |
| MPA1 /// AAS2 | test4553 | 8 | 4 |
| MPAS | test3341 | 5 | 5 |
| SSPA1 | test2142 | 5 | 8 |
| MAS61A | test4722 | 6 | 4 |
示例数据生成代码
# 构建DF1 Name <- c("XAS /// HUA", "MPA1 /// AAS2", "MPAS", "SSPA1", "MAS61A") Key <- c("test1234", "test4553", "test3341", "test2142", "test4722") group1 <- c(10, 8, 5, 5, 6) group2 <- c(10, 7, 5, 6, 7) group3 <- c(8, 4, 5, 8, 4) DF1 <- data.frame(Name, Key, group1, group2, group3, stringsAsFactors = FALSE) # 构建List1 Group <- c("group1", "group3", "group4", "group5") Number <- c(0.5, 0.6, 0.8, 0.9) List1 <- data.frame(Group, Number, stringsAsFactors = FALSE)
高效实现方案
下面的方案都针对大数据集做了优化,尽量减少内存复制,保证处理速度:
1. 基础R原生方案(不用装额外包)
直接用列名索引筛选,操作简单且内存友好:
# 找出List1分组名和DF1列名的交集(只保留DF1里存在的分组) matched_groups <- intersect(List1$Group, colnames(DF1)) # 确定要保留的列:前两列 + 匹配的分组列 keep_cols <- c(colnames(DF1)[1:2], matched_groups) # 筛选DF1得到结果 result_baseR <- DF1[, keep_cols, drop = FALSE]
- 注意:
drop=FALSE是为了防止筛选后只剩一列时自动转为向量,确保结果始终是DataFrame;原生索引操作不会额外复制数据,对大数据集内存压力小。
2. dplyr方案(tidyverse生态)
语法简洁,dplyr底层做了性能优化,处理大数据比普通循环快很多:
library(dplyr) result_dplyr <- DF1 %>% select(Name, Key, all_of(intersect(List1$Group, colnames(.))))
- 解释:
all_of用来引用字符向量里的列名,intersect确保只保留DF1中实际存在的分组列,避免出现列名不存在的错误。
3. data.table方案(大数据最优选择)
data.table专门为大规模数据设计,内存效率和处理速度碾压普通data.frame:
library(data.table) # 把data.frame转成data.table(不复制数据,只是改引用) setDT(DF1) setDT(List1) # 找出匹配的分组列 matched_groups <- intersect(List1$Group, colnames(DF1)) # 筛选列,返回结果 result_datatable <- DF1[, c("Name", "Key", matched_groups), with = FALSE]
- 优势:data.table的列筛选是原地操作,不会复制整个数据集,对于百万行甚至千万行的大数据,内存占用能减少一半以上,处理速度也快得多;
with=FALSE允许直接用字符向量指定要选的列。
验证结果
以基础R方案为例,输出结果和目标一致:
print(result_baseR) #> Name Key group1 group3 #> 1 XAS /// HUA test1234 10 8 #> 2 MPA1 /// AAS2 test4553 8 4 #> 3 MPAS test3341 5 5 #> 4 SSPA1 test2142 5 8 #> 5 MAS61A test4722 6 4
内容的提问来源于stack exchange,提问作者dkcongo
相关产品推荐
相关产品推荐

