有没有更好的方法来处理R |中的JSON性能改进

时间:2018-02-22 12:14:38

标签: json r

数据准备

 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

我不确定为什么&#39; comp&#39;不是专栏名称,为什么&#39; id&#39;如果我之前定义了它,那么如果我定义&#39; as.data.frame(comp,id)&#39;

,它也会给出错误

现在我正在处理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输入并且它的性能太高了我的报告

1 个答案:

答案 0 :(得分:1)

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

现在,我们将以1000行为基准,因为我不等待完整的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

所以:

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

如果你对于需要为整数的id1列没有迂腐,你可能会减少几毫秒。

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