如何拆解含子DataFrame的复杂DataFrame并保留ResourceId
问题描述
我正在尝试拆解一个每行包含子DataFrame的复杂DataFrame。问题在于,各列中的子DataFrame尺寸不同(如1x3、2x3和2x2),且子DataFrame的Conversions.Value列存在数值与字符混合的数据格式,拆解时出现can't recycle input of size 3 to size 2.等报错。
DataFrame结构
structure(list (Conversions = list(structure(list(Field = "Volume", Unit = "m3", Value = 338L), class = "data.frame", row.names = 1L), structure(list(Field = "Volume", Unit = "m3", Value = 450L), class = "data.frame", row.names = 1L)), Categories = list(structure(list(CategorySystem = c("Base", NA), Title = c("Mineral materials and glass (excluding concrete)", "213.7 Kevytbetoni, Aerated concrete"), ClassificationType = c(NA, "Talo2000")), class = "data.frame", row.names = 1:2), structure(list( CategorySystem = c("Base", NA), Title = c("Mineral materials and glass (excluding concrete)", "213.7 Kevytbetoni, Aerated concrete"), ClassificationType = c(NA, "Talo2000")), class = "data.frame", row.names = 1:2)), DataItems.DataValueItems = list(structure(list(DataModuleCode = c("A1-A3 Conservative", "A1-A3 Typical"), Value = c(0.43, 0.36)), class = "data.frame", row.names = 1:2), structure(list(DataModuleCode = c("A1-A3 Conservative", "A1-A3 Typical"), Value = c(0.41, 0.34)), class = "data.frame", row.names = 1:2)), ResourceId = c(7000000995, 7000000996)), row.names = 1:2, class = "data.frame")
已尝试的方法及报错
- 方法1:
unnest_wider(df, col = 1:3, names_repair = "universal") # 能运行但同一行仍有多个列表形式的观测,且长度不一致
- 方法2:
unnest_longer(df, col = 1:3, names_repair = "universal") %>% mutate(across(.fns = as.character)) %>% type_convert() # 报错:Can't combine `..1$Conversions$Value` <integer> and `..6$Conversions$Value` <character>.
- 方法3:
df$Conversions=lapply(df$Conversions, FUN=as.character) unnest_longer(df, col = 1:3, names_repair = "universal") %>% mutate(across(.fns = as.character)) %>% type_convert() # 报错:! In row 1, can't recycle input of size 3 to size 2.
补充:单独对各列使用rbindlist可合并,但会丢失唯一标识ResourceId,导致数据无法关联。需要为各列子DataFrame添加对应ResourceId后再合并。
解决方案
方法1:使用tidyverse工具链(dplyr + purrr)
核心思路是为每个子DataFrame绑定对应的ResourceId,再分别展开各列,最后按需合并:
- 处理Conversions列(统一Value类型避免冲突):
library(dplyr) library(purrr) conversions_df <- df %>% select(ResourceId, Conversions) %>% mutate(Conversions = map(Conversions, ~ .x %>% mutate(Value = as.character(Value)))) %>% unnest(Conversions)
- 处理Categories列:
categories_df <- df %>% select(ResourceId, Categories) %>% unnest(Categories)
- 处理DataItems.DataValueItems列(重命名Value避免冲突):
data_items_df <- df %>% select(ResourceId, DataItems.DataValueItems) %>% unnest(DataItems.DataValueItems) %>% rename(DataValue = Value)
- 按需合并(按ResourceId关联所有信息):
combined_df <- conversions_df %>% left_join(categories_df, by = "ResourceId") %>% left_join(data_items_df, by = "ResourceId")
方法2:使用data.table的rbindlist+map
利用map2将ResourceId和每个子DataFrame绑定,再用rbindlist合并:
library(data.table) # 处理Conversions conversions_dt <- rbindlist(map2(df$ResourceId, df$Conversions, ~ .y %>% mutate(ResourceId = .x, Value = as.character(Value)))) # 处理Categories categories_dt <- rbindlist(map2(df$ResourceId, df$Categories, ~ .y %>% mutate(ResourceId = .x))) # 处理DataItems.DataValueItems data_items_dt <- rbindlist(map2(df$ResourceId, df$DataItems.DataValueItems, ~ .y %>% mutate(ResourceId = .x))) %>% setnames("Value", "DataValue") # 合并数据集 final_dt <- conversions_dt[categories_dt, on = "ResourceId"][data_items_dt, on = "ResourceId"]
关键说明
- 针对
Conversions.Value的类型混合问题,提前转为字符型(后续可按需转换为合适类型),避免合并时的类型冲突。 - 通过绑定
ResourceId到每个子DataFrame,确保拆分后的数据集保留唯一标识,解决数据关联问题。 - 分列拆分再合并的方式,规避了不同尺寸子DataFrame直接unnest时的回收错误。
内容的提问来源于stack exchange,提问作者schlindd
相关产品推荐
相关产品推荐

