【问题标题】:Extract JSON data from the rows of an R data frame从 R 数据框的行中提取 JSON 数据
【发布时间】:2015-08-21 07:59:08
【问题描述】:

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

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

我想提取每一行的参数并将它们作为列 AB1B2 附加到数据框中>B3.

我该怎么做?

如果可能且高效,我宁愿使用 dplyr

【问题讨论】:

  • @akrun 是的,但我不知道如何将 fromJSON 应用到每一行并将数据附加到数据框中
  • 如果要提取数字部分,library(stringr);do.call(rbind,lapply(str_extract_all(df1$Parameters, '[0-9.]+'), as.numeric)) 并将列命名为A, B1:B4
  • 库(rjson); v = c('{"a":0,"b":[10.2,11.5,22.1]}','{"a":3,"b":[4.0,6.2,-3.3]}'); lapply(v,fromJSON)
  • @akrun 不可以用fromJSON吗?也可以提取字符串变量。
  • @Medicalphysicist 库(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=','))))))

标签: json r dplyr sapply


【解决方案1】:

在您的示例数据中,每一行都包含一个 json 对象。这种格式称为jsonlines又名ndjson,而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 字符串并一起解析(a la fromJSON(sprintf('{%s}', paste(sprintf('"%s": %s', my_key, my_json_column), collapse = ',')))快一点(在 60K 记录上为 4 v 5 秒),这是大致预期的吗?
  • 尝试生成一个包含 60M 记录的 json 字符串。
【解决方案2】:

我实际上遇到了类似的问题,我在数据框中有多个变量,这些变量是 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)
} 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多