如何避免在使用R从JSON读取后循环列表
我在R中有一个JSON数据向量,我用Lappy提取信息:如何避免在使用R从JSON读取后循环列表,json,r,Json,R,我在R中有一个JSON数据向量,我用Lappy提取信息: list <- lapply(temp, fromJSON) 这适用于第一个元素:list[[1]]$hnrlbl,但如何一次对整个列表执行此操作?类似于list[.]$hnrlbl经过几个小时寻找最干净的方法,我们做到了: kadaster_building_temp$hnrlbl <- sapply(list,function(x){x$hnrlbl} ) 在这种情况下,您可以使用rlist包中的list.map:
list <- lapply(temp, fromJSON)
这适用于第一个元素:list[[1]]$hnrlbl,但如何一次对整个列表执行此操作?类似于list[.]$hnrlbl经过几个小时寻找最干净的方法,我们做到了:
kadaster_building_temp$hnrlbl <- sapply(list,function(x){x$hnrlbl} )
在这种情况下,您可以使用rlist包中的list.map: 警告:通过使用正则表达式,此解决方案在某些情况下可能会失败,具体取决于您在列表中使用的名称。如果速度不是一个选项,则list.map或使用sapply的解决方案都更可靠 通过在此处使用unlist并查找名称,您可以获得相当快的速度。选择以下函数: 这方面的基准:
require(rbenchmark)
benchmark(
sapply(aList,function(i)i$z),
myselect(aList,"z"),
columns=c("test","elapsed","relative"),
replications=10000
)
test elapsed relative
2 myselect(aList, "z") 0.24 1.000
1 sapply(aList, function(i) i$z) 0.39 1.625
对于较大的对象,改进可能是实质性的。在我的工作区dput中碰巧有一个列表上使用此选项在这里不是一个选项…:
> benchmark(
+ sapply(StatN0_1,function(i)i$SP),
+ myselect(StatN0_1,"SP"),
+ columns=c("test","elapsed","relative"),
+ replications=100
+ )
test elapsed relative
2 myselect(StatN0_1, "SP") 0.02 1.0
1 sapply(StatN0_1, function(i) i$SP) 1.13 56.5
我有一个助手函数,它对这些场景非常有用:
pluck <- function(x, name, type) {
if (missing(type)) {
lapply(x, .subset2, name)
} else {
vapply(x, .subset2, name, FUN.VALUE = type)
}
}
也可以按位置选择:X、2、字符10
标杆管理
这种方法也很快:
x_big <- rep(x, 1000)
myselect <- function(x,name){
tmp <- unlist(x, recursive = FALSE)
id <- grep(paste0("\\.",name,"$"), names(tmp))
tmp[id]
}
library(microbenchmark)
options(digits = 2)
microbenchmark(
sapply(x_big, function(i)i$z),
myselect(x_big,"z"),
pluck(x_big, "z", character(1))
)
#> Unit: microseconds
#> expr min lq median uq max neval
#> sapply(x_big, function(i) i$z) 2771 2886 2972 3124 5903 100
#> myselect(x_big, "z") 2250 2330 2366 2401 3551 100
#> pluck(x_big, "z", character(1)) 717 786 825 889 1731 100
您想从每个列表项中提取hnrlbl?能否提供dputlist?另外,你认为LUpEt是循环的吗?@ McEeleNeaRe:是的,这正是我想要的。do@DavidArenburg不,我不认为LoPipe是循环的,那就好了。你觉得我的回答怎么样?如果你看到一些更干净、更快的东西,我很高兴给你发一份清单。它看起来是解决这类问题的常用方法,而且是一种简单的方法。由于list.map基于mapply,因此它仍然是一个内在循环函数,速度不一定比sapply快。此方法假定顶级列表已命名,使用正则表达式将非常脆弱。@hadley改编为允许使用未命名的顶级列表。我同意使用易损坏的正则表达式,这就是为什么我强调在这种特殊情况下这是为了提高速度。我加了一句话来反映这一点。换言之:为速度而放弃安全的人,两者都不配。
require(rbenchmark)
benchmark(
sapply(aList,function(i)i$z),
myselect(aList,"z"),
columns=c("test","elapsed","relative"),
replications=10000
)
test elapsed relative
2 myselect(aList, "z") 0.24 1.000
1 sapply(aList, function(i) i$z) 0.39 1.625
> benchmark(
+ sapply(StatN0_1,function(i)i$SP),
+ myselect(StatN0_1,"SP"),
+ columns=c("test","elapsed","relative"),
+ replications=100
+ )
test elapsed relative
2 myselect(StatN0_1, "SP") 0.02 1.0
1 sapply(StatN0_1, function(i) i$SP) 1.13 56.5
pluck <- function(x, name, type) {
if (missing(type)) {
lapply(x, .subset2, name)
} else {
vapply(x, .subset2, name, FUN.VALUE = type)
}
}
x <- list(
a = list(x = rnorm(10), y = letters[1:10], z = "OK"),
b = list(x = rnorm(10), y = letters[11:20], z = "notOK")
)
# List of results
str(pluck(x, "z"))
#> List of 2
#> $ a: chr "OK"
#> $ b: chr "notOK"
# Vector of results
str(pluck(x, "z", character(1)))
#> Named chr [1:2] "OK" "notOK"
#> - attr(*, "names")= chr [1:2] "a" "b"
x_big <- rep(x, 1000)
myselect <- function(x,name){
tmp <- unlist(x, recursive = FALSE)
id <- grep(paste0("\\.",name,"$"), names(tmp))
tmp[id]
}
library(microbenchmark)
options(digits = 2)
microbenchmark(
sapply(x_big, function(i)i$z),
myselect(x_big,"z"),
pluck(x_big, "z", character(1))
)
#> Unit: microseconds
#> expr min lq median uq max neval
#> sapply(x_big, function(i) i$z) 2771 2886 2972 3124 5903 100
#> myselect(x_big, "z") 2250 2330 2366 2401 3551 100
#> pluck(x_big, "z", character(1)) 717 786 825 889 1731 100