rjson::fromJSON returns 仅第一项
rjson::fromJSON returns only the first item
我有一个包含多个列的 sqlite 数据库文件。其中一列中嵌入了一个 JSON 字典(带有两个键)。我想将 JSON 列提取到 R 中的数据框中,该数据框在单独的列中显示每个键。
我试过 rjson::fromJSON,但它只读取第一项。有没有我想念的把戏?
这是一个模仿我的问题的例子:
> eg <- as.vector(c("{\"3x\": 20, \"6y\": 23}", "{\"3x\": 60, \"6y\": 50}"))
> fromJSON(eg)
$3x
[1] 20
$6y
[1] 23
所需的输出类似于:
# a data frame for both variables
3x 6y
1 20 23
2 60 50
或者,
# a data frame for each variable
3x
1 20
2 60
6y
1 23
2 50
您要查找的实际上是 lapply
和 rbind
或相关应用程序的组合。
我会稍微扩展你的数据,只需要有 2 个以上的元素。
eg <- c("{\"3x\": 20, \"6y\": 23}",
"{\"3x\": 60, \"6y\": 50}",
"{\"3x\": 99, \"6y\": 72}")
library(jsonlite)
使用 base R,我们可以做到
do.call(rbind.data.frame, lapply(eg, fromJSON))
# X3x X6y
# 1 20 23
# 2 60 50
# 3 99 72
您可能想做类似 Reduce(rbind, lapply(eg, fromJSON))
的事情,但显着的区别是在 Reduce
模型中,rbind
被调用 "N-1" 次,其中 "N"是eg
中的元素个数;这会导致大量的数据复制,虽然它可能适用于小 "N",但它的扩展性非常糟糕。使用 do.call
选项,rbind
只被调用一次。
请注意,列标签已被 R 化,因为 data.frame
列名称不应以数字开头。 (这是可能的,但通常不鼓励。)
如果您确信所有子字符串都将具有完全相同的元素,那么您在这里可能会很好。如果有机会在某个时候有所不同,也许
eg <- c(eg, "{\"3x\": 99}")
然后您会注意到默认情况下基本 R 解决方案不再有效。
do.call(rbind.data.frame, lapply(eg, fromJSON))
# Error in (function (..., deparse.level = 1, make.row.names = TRUE, stringsAsFactors = default.stringsAsFactors()) :
# numbers of columns of arguments do not match
可能有一些技术可以尝试规范化元素,这样您就可以确保匹配。但是,如果您不反对 tidyverse
套餐:
library(dplyr)
eg2 <- bind_rows(lapply(eg, fromJSON))
eg2
# # A tibble: 4 × 2
# `3x` `6y`
# <int> <int>
# 1 20 23
# 2 60 50
# 3 99 72
# 4 99 NA
尽管您不能直接使用美元方法调用它,但您仍然可以使用 [[
或反引号。
eg2x
# Error: unexpected numeric constant in "eg2"
eg2[["3x"]]
# [1] 20 60 99 99
eg2$`3x`
# [1] 20 60 99 99
我有一个包含多个列的 sqlite 数据库文件。其中一列中嵌入了一个 JSON 字典(带有两个键)。我想将 JSON 列提取到 R 中的数据框中,该数据框在单独的列中显示每个键。
我试过 rjson::fromJSON,但它只读取第一项。有没有我想念的把戏?
这是一个模仿我的问题的例子:
> eg <- as.vector(c("{\"3x\": 20, \"6y\": 23}", "{\"3x\": 60, \"6y\": 50}"))
> fromJSON(eg)
$3x
[1] 20
$6y
[1] 23
所需的输出类似于:
# a data frame for both variables
3x 6y
1 20 23
2 60 50
或者,
# a data frame for each variable
3x
1 20
2 60
6y
1 23
2 50
您要查找的实际上是 lapply
和 rbind
或相关应用程序的组合。
我会稍微扩展你的数据,只需要有 2 个以上的元素。
eg <- c("{\"3x\": 20, \"6y\": 23}",
"{\"3x\": 60, \"6y\": 50}",
"{\"3x\": 99, \"6y\": 72}")
library(jsonlite)
使用 base R,我们可以做到
do.call(rbind.data.frame, lapply(eg, fromJSON))
# X3x X6y
# 1 20 23
# 2 60 50
# 3 99 72
您可能想做类似 Reduce(rbind, lapply(eg, fromJSON))
的事情,但显着的区别是在 Reduce
模型中,rbind
被调用 "N-1" 次,其中 "N"是eg
中的元素个数;这会导致大量的数据复制,虽然它可能适用于小 "N",但它的扩展性非常糟糕。使用 do.call
选项,rbind
只被调用一次。
请注意,列标签已被 R 化,因为 data.frame
列名称不应以数字开头。 (这是可能的,但通常不鼓励。)
如果您确信所有子字符串都将具有完全相同的元素,那么您在这里可能会很好。如果有机会在某个时候有所不同,也许
eg <- c(eg, "{\"3x\": 99}")
然后您会注意到默认情况下基本 R 解决方案不再有效。
do.call(rbind.data.frame, lapply(eg, fromJSON))
# Error in (function (..., deparse.level = 1, make.row.names = TRUE, stringsAsFactors = default.stringsAsFactors()) :
# numbers of columns of arguments do not match
可能有一些技术可以尝试规范化元素,这样您就可以确保匹配。但是,如果您不反对 tidyverse
套餐:
library(dplyr)
eg2 <- bind_rows(lapply(eg, fromJSON))
eg2
# # A tibble: 4 × 2
# `3x` `6y`
# <int> <int>
# 1 20 23
# 2 60 50
# 3 99 72
# 4 99 NA
尽管您不能直接使用美元方法调用它,但您仍然可以使用 [[
或反引号。
eg2x
# Error: unexpected numeric constant in "eg2"
eg2[["3x"]]
# [1] 20 60 99 99
eg2$`3x`
# [1] 20 60 99 99