从深度嵌套列表提取指定元素并转换为R语言DataFrame
处理嵌套列表提取元素生成DataFrame的解决方案
问题场景
通过fromJSON()读取JSON文件得到一个深度嵌套列表(部分层级实际为数据框),需要从多个层级提取指定元素,将顶层元素(如PhraseText)与深层元素(如CandidateCUI)关联,生成目标DataFrame。
示例嵌套列表
conditions <- list( list( PMID = 00001, Phrases = list( list( PhraseText = "Hodgkin Lymphoma", Mappings = mappings1 <- list( list( MappingScore = 1000, MappingCandidates = mc1 <- list( list(CandidateScore = 1000, CandidateCUI = "C075655", CandidateMatched = "Hodgkins Lymphoma", CandidatePreferred = "Hodgkins Lymphoma", MatchedWords = list(c("hodgkin", "lymphoma"))), list(CandidateScore = 850, CandidateCUI = "C095659", CandidateMatched = "Lymphoma", CandidatePreferred = "Lymphoma", MatchedWords = list(c("lymphoma")))) ) ) ) ) ), list( PMID = 00002, Phrases = list( list( PhraseText = "Plaque Psoriasis", Mappings = mappings2 <- list( list(MappingScore = 1000, MappingCandidates = mc2 <- list( list(CandidateScore = 1000, CandidateCUI = "C0125609", CandidateMatched = "Plaque Psoriasis", CandidatePreferred = "Plaque Psoriasis", MatchedWords = list(c("plaque", "psoriasis"))), list(CandidateScore = 750, CandidateCUI = "C0320011", CandidateMatched = "Psoriasis", CandidatePreferred = "Psoriasis", MatchedWords = list(c("psoriasis"))))) ) ) ) ) )
目标DataFrame
output <- data.frame( PhraseText = c("Hodgkin Lymphoma", "Hodgkin Lymphoma", "Plaque Psoriasis", "Plaque Psoriasis"), MappingScore = c(1000, 1000, 1000, 1000), CandidateScore = c(1000, 850, 1000, 750), CandidateCUI = c("C075655", "C095659", "C0125609", "C0320011"), CandidatePreferred = c("Hodgkins Lymphoma", "Lymphoma", "Plaque Psoriasis", "Psoriasis") )
用户尝试代码(存在关联问题)
x <- lapply(conditions, function(i) { lapply(i[["Phrases"]][[1]][["Mappings"]], function(j) { lapply(j[["MappingCandidates"]], function(k) { k[c("CandidateScore", "CandidateCUI", "CandidatePreferred")] }) }) })
解决方案
方法1:使用purrr的map_dfr逐层绑定
通过三层嵌套的map_dfr,将上层的PhraseText、MappingScore传递到深层循环中,自动合并所有结果为DataFrame,完美关联各层级元素:
library(tidyverse) result <- map_dfr(conditions, function(cond) { # 提取当前条目下的PhraseText phrase_text <- cond$Phrases[[1]]$PhraseText # 遍历每个Mapping对象 map_dfr(cond$Phrases[[1]]$Mappings, function(map) { mapping_score <- map$MappingScore # 遍历每个候选对象,绑定上层字段 map_dfr(map$MappingCandidates, function(cand) { tibble( PhraseText = phrase_text, MappingScore = mapping_score, CandidateScore = cand$CandidateScore, CandidateCUI = cand$CandidateCUI, CandidatePreferred = cand$CandidatePreferred ) }) }) }) # 转为data.frame格式(若需要) result <- as.data.frame(result)
方法2:利用unnest系列函数扁平化结构(适合含数据框的层级)
如果嵌套结构中部分层级是数据框,使用tidyverse的unnest_wider和unnest可以更简洁地展开嵌套结构,直接提取所需字段:
library(tidyverse) result <- tibble(data = conditions) %>% # 展开第一层列表为列 unnest_wider(data) %>% # 展开Phrases下的嵌套内容 unnest_wider(Phrases) %>% # 展开Mappings下的嵌套内容 unnest_wider(Mappings) %>% # 展开MappingCandidates列表为多行 unnest(MappingCandidates) %>% # 筛选需要的字段 select(PhraseText, MappingScore, CandidateScore, CandidateCUI, CandidatePreferred) # 转为data.frame格式(若需要) result <- as.data.frame(result)
两种方法都能生成符合要求的目标DataFrame,方法1更通用适配纯列表结构,方法2在存在数据框层级时更高效简洁。
内容的提问来源于stack exchange,提问作者mark_ediger
相关产品推荐
相关产品推荐

