在R中处理JSON的更好方法|性能改进



数据准备

comp <- 
c('[{"id": 28, "name": "Google"}, {"id": 12, "name": "Microsoft"}]', 
'[{"id": 32, "name": "Microsoft"}, {"id": 878, "name": "Facebook"}]')
id = c(1,2)
jsonData = as.data.frame(id,comp)
jsonData
id
[{"id": 28, "name": "Google"}, {"id": 12, "name": "Microsoft"}]     1
[{"id": 32, "name": "Microsoft"}, {"id": 878, "name": "Facebook"}]  2
我不确定为什么"comp">

不作为列名出现,如果之前定义过,为什么"id"后来出现,如果我定义"as.data.frame(comp,id)",也会出错

现在我正在处理 JSON 数据

library(jsonlite)
library(tidyverse)
library(dplyr)
data <- jsonData %>% mutate(x = lapply(comp,fromJSON)) %>% unnest(x)
data
id id1      name
1  1  28    Google
2  1  12 Microsoft
3  2  32 Microsoft
4  2 878  Facebook

有没有更好的方法来处理 R 中的 JSON,就像任何直接将 JSON 转换为普通列的库一样,目前我正在获取小数据,所以它看起来很容易,但我有多个列有 JSON 输入,它对我的报告性能影响太大

JSON 是文本。文本解析速度很慢。也不知道为什么library(dplyr)在那里,因为它附带tidyverse.而且,您应该考虑阅读如何制作数据框。

无论。我们将举一个有代表性的例子:500,000 行:

library(tidyverse)
data_frame(
id = rep(c(1L, 2L), 250000),
comp = rep(c(
'[{"id": 28, "name": "Google"}, {"id": 12, "name": "Microsoft"}]', 
'[{"id": 32, "name": "Microsoft"}, {"id": 878, "name": "Facebook"}]'
), 250000)
) -> xdf

R中有许多JSON处理包。这使用ndjson,它有一个函数flatten(),它接受JSON字符串的字符向量,并从中创建一个"完全扁平"的结构。

我只是使用不同的数据框变量,以便稍后进行解释清晰和基准测试。

pull(xdf, comp) %>% 
ndjson::flatten() %>% 
bind_cols(select(xdf, id)) -> ydf

这使得:

ydf
## Source: local data table [500,000 x 5]
## 
## # A tibble: 500,000 x 5
##    `0.id` `0.name`  `1.id` `1.name`     id
##     <dbl> <chr>      <dbl> <chr>     <int>
##  1    28. Google       12. Microsoft     1
##  2    32. Microsoft   878. Facebook      2
##  3    28. Google       12. Microsoft     1
##  4    32. Microsoft   878. Facebook      2
##  5    28. Google       12. Microsoft     1
##  6    32. Microsoft   878. Facebook      2
##  7    28. Google       12. Microsoft     1
##  8    32. Microsoft   878. Facebook      2
##  9    28. Google       12. Microsoft     1
## 10    32. Microsoft   878. Facebook      2
## # ... with 499,990 more rows

我们可以将其转回更整洁的数据框:

bind_rows(
select(ydf, id = id, id1=`0.id`, name=`0.name`),
select(ydf, id = id, id1=`1.id`, name=`1.name`)
) %>% 
mutate(id1 = as.integer(id1))
## Source: local data table [1,000,000 x 3]
## 
## # A tibble: 1,000,000 x 3
##       id   id1 name     
##    <int> <int> <chr>    
##  1     1    28 Google   
##  2     2    32 Microsoft
##  3     1    28 Google   
##  4     2    32 Microsoft
##  5     1    28 Google   
##  6     2    32 Microsoft
##  7     1    28 Google   
##  8     2    32 Microsoft
##  9     1    28 Google   
## 10     2    32 Microsoft
## # ... with 999,990 more rows

现在,我们将使用 1,000 行进行基准测试,因为我不会等待完整的 500,000 行运行到微基准测试:

data_frame(
id = rep(c(1L, 2L), 500),
comp = rep(c(
'[{"id": 28, "name": "Google"}, {"id": 12, "name": "Microsoft"}]', 
'[{"id": 32, "name": "Microsoft"}, {"id": 878, "name": "Facebook"}]'
), 500)
) -> xdf
microbenchmark::microbenchmark(
faster = {
pull(xdf, comp) %>% 
ndjson::flatten() %>% 
bind_cols(select(xdf, id)) -> ydf
bind_rows(
select(ydf, id = id, id1=`0.id`, name=`0.name`),
select(ydf, id = id, id1=`1.id`, name=`1.name`)
) %>% 
mutate(id1 = as.integer(id1))
}
)
## Unit: milliseconds
##    expr      min       lq     mean   median       uq      max neval
##  faster 12.46409 13.71483 14.73997 14.40582 15.47529 21.09543   100

所以:

  • 1,000 行为 15ms
  • 15ms * 500 = 7.5s 表示 500,000

如果您对id1列必须是整数不迂腐,您可能会减少几毫秒。

还有其他方法。而且,如果您经常使用JSON数据列,我强烈建议您查看Apache Drill和sergeant包。

相关内容

  • 没有找到相关文章

最新更新