R语言 有没有一种简洁的方法来读取JSON字符串并转换为新的变量?

6mw9ycah  于 2023-06-19  发布在  其他
关注(0)|答案(2)|浏览(93)

我有一个JSON字符串,我想把它分成新的变量。我觉得一定有一个聪明的办法,但我找不到解决办法。

df <- structure(list(subject = c("dtv85251vucquc45", "mcj8vdqz7sxmjcr0"
), response = c("{\"P0_Q0\":{\"aktiv\":2,\"bekümmert\":3,\"interessiert\":4,\"freudig erregt\":2,\"verärgert\":2,\"stark\":0,\"schuldig\":1,\"erschrocken\":1,\"feindselig\":1,\"angeregt\":2},\"P1_Q0\":{\"stolz\":1,\"gereizt\":1,\"begeistert\":2,\"beschämt\":2,\"wach\":1,\"nervös\":1,\"entschlossen\":1,\"ängstlich\":1,\"aufmerksam\":2,\"durcheinander\":2}}", 
                "{\"P0_Q0\":{\"aktiv\":1,\"bekümmert\":3,\"interessiert\":1,\"freudig erregt\":1,\"verärgert\":0,\"stark\":0,\"schuldig\":2,\"erschrocken\":0,\"feindselig\":0,\"angeregt\":1},\"P1_Q0\":{\"stolz\":2,\"gereizt\":0,\"begeistert\":1,\"beschämt\":0,\"wach\":2,\"nervös\":0,\"entschlossen\":0,\"aufmerksam\":2,\"durcheinander\":0,\"ängstlich\":0}}"
)), class = c("tbl_df", 
              "tbl", "data.frame"), row.names = 1:2, class = "data.frame")

期望输出:

output <- structure(list(subject = c("dtv85251vucquc45", "mcj8vdqz7sxmjcr0"
), aktiv = 2:1, bekümmert = c(3L, 3L), interessiert = c(4L, 
1L), freudig.erregt = 2:1, verärgert = c(2L, 0L), 
    stark = c(0L, 0L), schuldig = 1:2, erschrocken = 1:0, 
    feindselig = 1:0, angeregt = 2:1, stolz = 1:2, 
    gereizt = 1:0, begeistert = 2:1, beschämt = c(2L, 
    0L), wach = 1:2, nervös = 1:0, entschlossen = 1:0, 
    ängstlich = 1:0, aufmerksam = c(2L, 2L), durcheinander = c(2L, 
    0L)), class = "data.frame", row.names = c(NA, -2L))

什么样的作品(但不整洁):

j <- list()
for(i in 1:nrow(df)){
  j[[i]] <- as.data.frame(jsonlite::fromJSON(df$response[i]))
}

output <- data.frame(subject=df$subject, bind_rows(j))

有更好的办法吗?

6ojccjat

6ojccjat1#

jsonlite::stream_in可以很好地处理这个问题。

library(dplyr)
jsonlite::stream_in(textConnection(df$response), simplifyDataFrame = FALSE) %>%
  lapply(bind_cols) %>%
  bind_rows() %>%
  bind_cols(df[,1,drop=FALSE], .)
#  Imported 2 records. Simplifying...
#            subject aktiv bekümmert interessiert freudig erregt verärgert stark
# 1 dtv85251vucquc45     2         3            4              2         2     0
# 2 mcj8vdqz7sxmjcr0     1         3            1              1         0     0
#   schuldig erschrocken feindselig angeregt stolz gereizt begeistert beschämt
# 1        1           1          1        2     1       1          2        2
# 2        2           0          0        1     2       0          1        0
#   wach nervös entschlossen ängstlich aufmerksam durcheinander
# 1    1      1            1         1          2             2
# 2    2      0            0         0          2             0

或者稍微重构:

library(dplyr)
library(tidyr) # unnest
df %>%
  mutate(
    response = jsonlite::stream_in(textConnection(response), simplifyDataFrame = FALSE),
    response = lapply(response, bind_cols)
  ) %>%
  unnest(response)
#  Imported 2 records. Simplifying...
# # A tibble: 2 × 21
#   subject      aktiv bekümmert interessiert `freudig erregt` verärgert stark schuldig erschrocken feindselig angeregt
#   <chr>        <int>     <int>        <int>            <int>     <int> <int>    <int>       <int>      <int>    <int>
# 1 dtv85251vuc…     2         3            4                2         2     0        1           1          1        2
# 2 mcj8vdqz7sx…     1         3            1                1         0     0        2           0          0        1
# # ℹ 10 more variables: stolz <int>, gereizt <int>, begeistert <int>, beschämt <int>, wach <int>, nervös <int>,
# #   entschlossen <int>, ängstlich <int>, aufmerksam <int>, durcheinander <int>
lbsnaicq

lbsnaicq2#

我不知道“聪明”,但{rjsoncons}实现了“jmespath”查询。我写了一个小助手函数,通过jmespath从json转换到R

from_jmespath = function(json, path) {
    rjsoncons::jmespath(json, path) |>
        jsonlite::fromJSON()
}

然后从数据框的行中提取相关信息

keys = from_jmespath(df$response[1], "*.keys(@)[]")
values = lapply(df$response, from_jmespath, "*.values(@)[]")

然后,我用各种组件构造了一个整洁的tibble

tbl = dplyr::tibble(
    subject = rep(df$subject, each = length(keys)),
    key = rep(keys, nrow(df)),
    value = unlist(values)
)

一个“宽”版本是

tbl |>
    tidyr::pivot_wider(names_from = "key", values_from = "value")

相关问题