有没有办法从 JSON 列中有效地提取多个属性?

Is there a way to extract multiple attributes efficiently from a JSON column?

我有一个数据框,其中有一列包含 json 数据。我想从这个 json 数据中提取一些属性到数据框的命名列中。

示例数据

json_col = c('{"name":"john"}','{"name":"doe","points": 10}', '{"name":"jane", "points": 20}')
id = c(1,2,3)
df <- data.frame(id, json_col)

我能够使用

实现这个
library(tidyverse)
library(jsonlite)

extract_json_attr <- function(from, attr, default=NA) {
  value <- from %>% 
             as.character() %>% 
             jsonlite::fromJSON(txt = .) %>%
             .[attr]

  return(ifelse(is.null(value[[1]]), default, value[[1]]))
}

df <- df %>% 
        rowwise() %>%
        mutate(name = extract_json_attr(json_col, "name"),
               points = extract_json_attr(json_col, "points", 0))

在这种情况下,extract_json_attr 需要为要提取的每个属性多次解析 json 列。

有没有更好的方法一次提取所有属性?

我尝试将此函数 return 多个值作为一个列表,但我无法将它与 mutate 一起使用来设置多个列。

extract_multiple <- function(from, attributes){
  values <- from %>% 
             as.character() %>% 
             jsonlite::fromJSON(txt = .) %>%
             .[attributes]
  return (values)
} 

我可以使用此函数提取所需的值

extract_multiple(df$json_col[1],c('name','points'))
extract_multiple(df$json_col[2],c('name','points')) 

但不能将其应用于一次性设置多列。有没有更好的方法来有效地做到这一点?

这是使用 dplyr

中的 bind_rows 的一种方法
dplyr::bind_rows(lapply(as.character(df$json_col), jsonlite::fromJSON))

# A tibble: 3 x 2
#  name  points
#  <chr>  <int>
#1 john      NA
#2 doe       10
#3 jane      20

要从函数中提取特定属性,我们可以这样做

bind_rows(lapply(as.character(df$json_col), function(x) 
          jsonlite::fromJSON(x)[c('name', 'points')]))

在 R4DS 松弛通道上,我收到了一种将 json 数组作为列处理的替代方法。使用它,我发现了另一种方法,似乎在更大的数据集上效果更好。

library(tidyverse)
library(jsonlite)

extract <- function(input, fields){
    json_df <- fromJSON(txt=input)
    missing <- setdiff(fields, names(json_df))
    json_df[missing] <- NA

    return (json_df %>% select(fields))
}


df <- data.frame(id=c(1,2,3),
                 json_col=c('{"name":"john"}','{"name":"doe","points": 10}', '{"name":"jane", "points": 20}'),
                 stringsAsFactors=FALSE)
df %>%
  mutate(json_col = paste0('[',json_col,']'),
         json_col = map(json_col, function(x) extract(input=x, fields=c('name', 'points')))) %>%
  unnest(cols=c(json_col))