如何将嵌套列表键转为DataFrame列并拆分两队玩家数据
高效拆分嵌套列表列(teams)为玩家独立列的R方案
问题场景
从JSON文件读取得到raw_data DataFrame,其中大部分列可通过unnest顺利展开为非列表列,但teams列是特殊的嵌套列表结构——每个元素包含玩家1和玩家2的字典数据(含profile_id、result等键)。直接用unnest会丢失其中一方的玩家数据,需要将两个玩家的对应键拆分为独立列(如profile_id_p1、profile_id_p2),且最终所有列均为非列表格式。
原方案通过循环+append提取玩家数据,效率较低,以下是更高效的优化方案:
方案1:基于tidyverse的函数式实现(简洁易读)
利用purrr的向量化映射函数替代显式循环,结合dplyr和tidyr完成数据合并:
library(dplyr) library(purrr) library(tidyr) # 处理teams列:拆分每个元素的p1/p2数据,重命名键后合并为DataFrame processed_teams <- raw_data$teams %>% map_dfr(function(player_pair) { # 提取玩家1数据并添加_p1后缀 p1_data <- player_pair[[1]] %>% set_names(paste0(names(.), "_p1")) # 提取玩家2数据并添加_p2后缀 p2_data <- player_pair[[2]] %>% set_names(paste0(names(.), "_p2")) # 合并单条记录的p1/p2数据 c(p1_data, p2_data) }) # 合并到原数据:先展开其他列表列,再绑定处理后的teams数据 final_df <- raw_data %>% select(-teams) %>% # 移除原teams列 unnest(cols = everything()) %>% # 展开其他列表列 bind_cols(processed_teams)
方案2:基于data.table的高效实现(大数据量首选)
延续原方案中rbindlist的思路,用lapply替代循环+append,减少内存重复分配:
library(data.table) library(tidyr) # 用lapply批量提取每个teams元素的p1/p2数据(避免循环append的内存开销) p1_dic <- lapply(raw_data$teams, `[[`, 1) p2_dic <- lapply(raw_data$teams, `[[`, 2) # 转为data.table并添加列后缀 p1_df <- rbindlist(p1_dic) %>% setnames(paste0(names(.), "_p1")) p2_df <- rbindlist(p2_dic) %>% setnames(paste0(names(.), "_p2")) # 合并原数据 final_df <- raw_data %>% select(-teams) %>% unnest(cols = everything()) %>% bind_cols(p1_df, p2_df)
优化说明
- 避免低效循环:原方案的
for循环+append会反复修改向量并重新分配内存,而lapply/map_dfr是向量化操作,内存分配更高效,处理大数据量时速度提升明显。 - 直接映射处理:通过单次映射完成玩家数据的提取、重命名与合并,代码更简洁,可读性更强。
内容的提问来源于stack exchange,提问作者Rayby
相关产品推荐
相关产品推荐

