You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JSON转R DataFrame遇阻,求可行转换方案及原理说明

嵌套JSON转R DataFrame的解决方案及原理说明

问题背景

我尝试将JSON数据转换为DataFrame,使用as.data.frame(ss_dtd)和以下代码均无效:

test <- lapply(ss_dtd, function(x) {
  x[sapply(x, is.null)] <- NA
  unlist(x)
})
test2 <-as.data.frame(do.call("cbind", test))

通过ss_dtd <- jsonlite::fromJSON("original_json.json")导入的JSON结构如下(str(ss_dtd)输出):

List of 8232
 $ billy@fakeemail.com                     :List of 2
  ..$ joins        :'data.frame':   1 obs. of  2 variables:
  .. ..$ project: chr "Sunflower Project"
  .. ..$ when   : chr "2020-09-18T13:09:53.789030"
  ..$ participation: list()
 $ sara@fakeemail.com                :List of 2
  ..$ joins        :'data.frame':   1 obs. of  2 variables:
  .. ..$ project: chr "Project with Cells"
  .. ..$ when   : chr "2020-05-12T15:15:40.557827"
  ..$ participation: list()
 $ jerry@fakeemail.com                           :List of 2
  ..$ joins        :'data.frame':   2 obs. of  2 variables:
  .. ..$ project: chr [1:2] "Water Project" "Sunflower Project"
  .. ..$ when   : chr [1:2] "2022-01-12T15:37:45.467523" "2020-10-15T18:57:59.623376"
  ..$ participation:'data.frame':   1 obs. of  3 variables:
  .. ..$ project    : chr "Sunflower Project"
  .. ..$ when       : chr "2020-10-15T20:16:12.689239"
  .. ..$ repetitions: int 1
 $ randy@fakeemail.com                          :List of 2
  ..$ joins        :'data.frame':   1 obs. of  2 variables:
  .. ..$ project: chr "Cloud Project"
  .. ..$ when   : chr "2022-02-17T20:05:24.991847"
  ..$ participation: list()

期望输出的DataFrame结构:

email join_or_participate            project                       when repetitions
1 billy@fakeemail.com                join  Sunflower Project 2020-09-18T13:09:53.789030          NA
2  sara@fakeemail.com                join Project with Cells 2020-05-12T15:15:40.557827          NA
3 jerry@fakeemail.com                join      Water Project 2022-01-12T15:37:45.467523          NA
4 jerry@fakeemail.com                join  Sunflower Project 2020-10-15T18:57:59.623376          NA
5 jerry@fakeemail.com         participate  Sunflower Project 2020-10-15T20:16:12.689239           1
6 randy@fakeemail.com                join      Cloud Project 2022-02-17T20:05:24.991847          NA

可行转换代码

使用purrr和dplyr包处理嵌套结构,代码如下:

library(purrr)
library(dplyr)

# 定义单个用户数据的处理函数
process_user <- function(user_data, email) {
  # 处理joins记录
  joins_df <- if (nrow(user_data$joins) > 0) {
    user_data$joins %>%
      mutate(
        email = email,
        join_or_participate = "join",
        repetitions = NA_integer_
      ) %>%
      select(email, join_or_participate, project, when, repetitions)
  } else {
    NULL
  }
  
  # 处理participation记录
  participation_df <- if (nrow(user_data$participation) > 0) {
    user_data$participation %>%
      mutate(
        email = email,
        join_or_participate = "participate"
      ) %>%
      select(email, join_or_participate, project, when, repetitions)
  } else {
    NULL
  }
  
  # 合并两类记录
  bind_rows(joins_df, participation_df)
}

# 遍历所有用户并合并结果
final_df <- imap_dfr(ss_dtd, process_user)

# 查看最终结果
print(final_df)

转换原理说明

1. 原始结构解析

导入后的ss_dtd是命名列表:

  • 列表元素名为用户邮箱
  • 每个元素是子列表,包含joins和participation两个字段:
    • joins为DataFrame,存储用户"加入"项目的记录(含project和when)
    • participation为DataFrame(或空列表),存储用户"参与"项目的记录(多了repetitions字段)

之前方法失效的原因:

  • as.data.frame(ss_dtd)直接将嵌套DataFrame作为列,无法展开成扁平结构
  • unlist会破坏层级,丢失joins和participation的类型区分

2. 核心逻辑

  • 保留类型标记:分别处理两类记录,给每条记录添加join_or_participate字段区分操作类型
  • 统一字段结构:给joins记录补充repetitions为NA,保证两类记录字段一致
  • 批量合并:用imap_dfr遍历所有用户(同时获取邮箱名和对应数据),自动合并所有记录为扁平DataFrame

3. 关键函数解释

  • imap_dfr:遍历命名列表,同时传递元素值和名字(此处名字即邮箱),最终自动合并为DataFrame
  • bind_rows:合并结构相似的DataFrame,自动补全缺失字段为NA
  • mutate:添加新字段,统一不同类型记录的数据结构

内容的提问来源于Stack Exchange,提问作者Bradley Allf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 07:55:21