从R数据框的行中提取JSON数据

4

我有一个数据框,其中列参数的值是Json数据:

#  Parameters
#1 {"a":0,"b":[10.2,11.5,22.1]}
#2 {"a":3,"b":[4.0,6.2,-3.3]}
...

我希望提取每行的参数并将它们作为列追加到数据框中,包括 A, B1, B2B3

如何实现呢?

如果可能且有效,我更倾向于使用 dplyr


@akrun 是的,但我不知道如何将 fromJSON 应用于每一行并将数据附加到数据框中。 - Medical physicist
如果您想提取数字部分,library(stringr);do.call(rbind,lapply(str_extract_all(df1$Parameters, '[0-9.]+'), as.numeric)) 并将列命名为 A、B1:B4 - akrun
看起来@Galapagos展示了一种实现的方式。 - akrun
@akrun 我正在尝试,但是我遇到了一个格式愚蠢的问题:Error in FUN(c("{"a":0,"b":[10.2,11.5,22.1]}", : 没有数据可解析。 - Medical physicist
1
@Medicalphysicist library(rjson); v = c('{"a":0,"b":[10.2,11.5,22.1]}','{"a":3,"b":[4.0,6.2,-3.3]}'); v1 = lapply(v,fromJSON); data.frame(t(sapply(v1,function(y) lapply(y,function(x) paste(x,collapse=',')))))) - Stan Yip
显示剩余2条评论
2个回答

5

在你的示例数据中,每一行都包含一个json对象。这种格式称为jsonlinesndjson,而jsonlite软件包有一个特殊的函数stream_in来将这样的数据解析成数据帧:

# Example data
mydata <- data.frame(parameters = c(
  '{"a":0,"b":[10.2,11.5,22.1]}',
  '{"a":3,"b":[4.0,6.2,-3.3]}'
), stringsAsFactors = FALSE)

# Parse json lines
res <- jsonlite::stream_in(textConnection(mydata$parameters))

# Extract columns
a <- res$a
b1 <- sapply(res$b, "[", 1)
b2 <- sapply(res$b, "[", 2)
b3 <- sapply(res$b, "[", 3)

在你的例子中,JSON结构相当简单,因此其他建议同样适用,但此解决方案将适用于更复杂的JSON结构。

这只比构建一个巨大的JSON字符串和解析在一起略微快一些(在60000条记录上为4 v 5秒),这大致符合预期吗? - MichaelChirico
2
尝试生成包含6000万条记录的JSON字符串。 - Jeroen Ooms

0
我曾经遇到过一个类似的问题,我的数据框中有多个变量是JSON对象,其中很多是NA值,但我不想删除存在NA值的行。我编写了一个函数,该函数接受一个数据框、数据框中的ID(通常是记录ID)和要解析的变量名称(用引号括起来)。该函数将创建两个子集,一个用于包含JSON对象的记录,另一个用于跟踪相同变量的NA值记录,然后将这些数据框连接起来,并将它们的组合与原始数据框连接起来,从而替换前面的变量。也许这对你或其他人有帮助,因为在几种情况下它已经对我起作用了。我还没有真正清理它,所以如果我的变量名有点混乱,我很抱歉,因为这是我为工作编写的一个非常临时的函数。我还应该说明一下,我确实使用了另一个帖子的想法,用JSON对象创建的新变量替换了前面的变量。你可以在这里找到:Add (insert) a column between two columns in a data.frame 最后一点说明:有一个叫做tidyjson的包,它可能有一个更简单的解决方案,但显然不能处理列表类型的JSON对象。至少这是我的理解。
library(jsonlite)
library(stringr)
library(dplyr)

parse_var <- function(df,id, var) {
  m <- df[,var]
  p <- m[-which(is.na(m))]
  n <- df[,id]
  key <- n[-which(is.na(df[,var]))]

  #create df for rows which are NA
  key_na <- n[which(is.na(df[,var]))]
  q <- m[which(is.na(m))]
  parse_df_na <- data.frame(key_na,q,stringsAsFactors = FALSE)  

  #Parse JSON values and bind them together into a dataframe.
  p <- lapply(p,function(x){ 
    fromJSON(x) %>% data.frame(stringsAsFactors = FALSE)}) %>% bind_rows()
  #bind the record id's of the JSON values to the above JSON parsed dataframe and name the columns appropriately.
  parse_df <- data.frame(key,p,stringsAsFactors = FALSE)

## The new variables begin with a capital 'x' so I replace those with my former variables  name
  n <- names(parse_df) %>% str_replace('X',paste(var,".",sep = ""))
  n <- n[2:length(n)]
  colnames(parse_df) <- c(id,n)

  #join the dataframe for NA JSON values and the dataframe containing parsed JSON values, then remove the NA column,q.
  parse_df <- merge(parse_df,parse_df_na,by.x = id,by.y = 'key_na',all = TRUE)

#Remove the new column formed by the NA values#
  parse_df <- parse_df[,-which(names(parse_df) =='q')]

  ####Replace variable that is being parsed in dataframe with the new parsed and names values.######

  new_df <- data.frame(append(df,parse_df[,-which(names(parse_df) == id)],after = which(names(df) == var)),stringsAsFactors = FALSE)
  new_df <- new_df[,-which(names(new_df) == var)]
  return(new_df)
} 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接