R语言按另一数据框列值子集化数据框并为每个子集命名
问题根因
你当前写的subset()逻辑是向量级运算,df2的Lat列有多少行,判断条件就会循环比对多少个范围,最终返回的是匹配df2任意一行Lat±0.01范围的所有df1记录,根本不会按df2的单行条件拆分结果,自然没法绑定第三列的标识做子集命名。
实现方案
因为你是百万行级df1、数千次匹配的场景,优先选性能更高的非等值连接方案,比逐行循环效率高几十倍:
- 方案1:data.table 高性能实现(推荐大数据量用)
library(data.table) # 转data.table格式 setDT(df1) setDT(df2) # 提前算好每个匹配项的纬度上下限 df2[, c("lat_low", "lat_high") := .(Lat - 0.01, Lat + 0.01)] # 非等值连接批量匹配,自动关联df2第三列作为标识 # 注意:如果df2第三列有固定列名,比如叫SiteID,直接把下面get()部分换成对应列名即可 match_result <- df1[ df2, on = .(Latitude >= lat_low, Latitude <= lat_high), .SD, .SDcols = colnames(df1), match_id = get(colnames(df2)[3]), nomatch = NULL ] # 按标识拆成独立子集,存在列表里 subset_list <- split(match_result, by = "match_id", keep.by = FALSE) # 如果需要把每个子集单独存为全局变量,执行下面这行(大数据量不推荐,内存占用高) list2env(subset_list, envir = .GlobalEnv)
提示:如果某条df1记录同时落在多个df2的Lat范围内,该记录会同时归入所有匹配到的标识对应的子集,符合范围匹配的常规逻辑;如果需要每条记录只保留一个匹配项,可以在连接时加mult = "first"参数。
- 方案2:基础R实现(仅适合小数据量测试,大数据量运行很慢)
不依赖第三方包,逐行遍历df2做子集提取,直接用第三列值当子集名称:
# 提取df2第三列作为子集命名依据 id_col <- df2[[3]] subset_list <- lapply(seq_len(nrow(df2)), function(i) { lat_min <- df2$Lat[i] - 0.01 lat_max <- df2$Lat[i] + 0.01 df1[df1$Latitude >= lat_min & df1$Latitude <= lat_max, ] }) # 给子集命名 names(subset_list) <- id_col
注意:不建议把数千个子集直接扔到全局环境里,存在列表里按需读取是更稳妥的写法,能避免内存溢出、变量名冲突的问题。
内容的提问来源于stack exchange,提问作者Dylan Egan
相关产品推荐
相关产品推荐

