【问题标题】:Can I control how tidyjson joins nested arrays?我可以控制 tidyjson 如何加入嵌套数组吗?
【发布时间】:2020-04-07 05:50:41
【问题描述】:

似乎tidyjson 在嵌套数组上使用了类似 inner-join 的行为,因此删除了具有空子数组的记录。有没有办法获得类似 left-join 的行为,用NAs 填充?

例如,这些假数据有一条记录,其中包含一个填充的嵌套数组 (middles),还有两条记录,其中middles 为空:

library(tidyjson)

people <- c('{"age": 32, "name": [{"first": "Bob",   "last": "Smith", "middles":[{"middle1":"John", "middle2":"Rick"}]}]}',
            '{"age": 54, "name": [{"first": "Susan", "last": "Doe", "middles":[]}]}',
            '{"age": 18, "name": [{"first": "Ann",   "last": "Jones", "middles":[]}]}')

从这些数据中,我希望有一个数据框,其中保留了所有父记录并缺少用NAs(〜左连接)填充的子数组信息:

# A tibble: 3 x 5
    age first last  middle1 middle2
  <dbl> <chr> <chr> <chr>   <chr>  
1    32 Bob   Smith John    Rick   
2    54 Susan Doe   NA      NA
3    18 Ann   Jones NA      NA

但是,提取包含一些空子数组的嵌套数组会导致丢失其父级的信息(~ 内连接):

people %>% 
    spread_all() %>%  
    enter_object("name") %>% gather_array() %>% 
    spread_all() %>% select(-document.id,-array.index) %>% 
    enter_object("middles") %>% gather_array %>% 
    spread_all()  %>% select(-array.index) %>% 
    tbl_df()
# A tibble: 1 x 5
    age first last  middle1 middle2
  <dbl> <chr> <chr> <chr>   <chr>  
1    32 Bob   Smith John    Rick   

有没有办法避免这种情况;即,即使子数组为空,也要保留所有行?


解决方法,但不是解决方案

一种可能的解决方法是从字面上进行左连接,但这意味着复制 JSON 读取,考虑到千兆字节的数据,这并非易事。

wrap_dplyr_verb <- function(dplyr.verb) {

    # Creates a tidyjson verb out of a dplyr verb
    # https://github.com/colearendt/tidyjson/blob/master/R/tbl_json.R

    function(.data, ...) {

        # Check if reserved ..JSON name already in data.frame
        if ("..JSON" %in% names(.data))
            stop("'..JSON' in the column names of tbl_json object being filtered")

        # Assign JSON to the data.frame so it is treated as any other column
        .data$..JSON <- attr(.data, "JSON")

        # Apply the transformation
        y <- dplyr.verb(dplyr::as_tibble(.data), ...)

        # Reconstruct tbl_json without ..JSON column
        tbl_json(dplyr::select(y, -..JSON), y$..JSON)

    }
}
left_join_json = wrap_dplyr_verb(left_join)

people %>% 
    spread_all() %>%  
    enter_object("name") %>% gather_array() %>% 
    spread_all() %>% select(-document.id,-array.index) %>% 
    left_join_json(
        people %>% 
            spread_all() %>%  
            enter_object("name") %>% gather_array() %>% 
            spread_all() %>% select(-document.id,-array.index) %>% 
            enter_object("middles") %>% gather_array %>% 
            spread_all()  %>% select(-array.index)
    ) %>% 
    tbl_df()
Joining, by = c("age", "first", "last")
# A tibble: 3 x 5
    age first last  middle1 middle2
  <dbl> <chr> <chr> <chr>   <chr>  
1    32 Bob   Smith John    Rick   
2    54 Susan Doe   NA      NA     
3    18 Ann   Jones NA      NA     

【问题讨论】:

    标签: r json tidyverse


    【解决方案1】:

    非常感谢您提出这个问题!这绝对是一个有趣的用例,我认为可以在 tidyjson 中改进。

    当然,我忘了我had already worked with you on this question in GitHub,所以我在这里用不同的模式实现,以防它对你或其他人有任何帮助。基本上,这个想法是先“高”而不是“宽”。我不知道它对执行时间有什么影响,也不知道这里是否隐藏了影响时间的左连接。

    library(tidyjson)
    library(dplyr)
    library(tidyr)
    
    people <- c('{"age": 32, "name": [{"first": "Bob",   "last": "Smith", "middles":[{"middle1":"John", "middle2":"Rick"}]}]}',
                '{"age": 54, "name": [{"first": "Susan", "last": "Doe", "middles":[]}]}',
                '{"age": 18, "name": [{"first": "Ann",   "last": "Jones", "middles":[]}]}')
    
    as_tbl_json(people) %>% spread_all() %>% enter_object("name") %>% gather_array("nameid") %>%
      gather_object("key") %>% 
      {bind_rows(
        filter(., key != "middles") %>% append_values_string("value"),
        filter(., key == "middles") %>% gather_array("middleid") %>% 
          select(-key) %>%
          gather_object("key") %>%
          append_values_string("value")
      )} %>%
      # drop tbl_json
      as_tibble() %>%
      select(-document.id, -nameid, -middleid) %>%
      # could also use tidyr::pivot_wider
      tidyr::spread(key, value)
    #> # A tibble: 3 x 5
    #>     age first last  middle1 middle2
    #>   <dbl> <chr> <chr> <chr>   <chr>  
    #> 1    18 Ann   Jones <NA>    <NA>   
    #> 2    32 Bob   Smith John    Rick   
    #> 3    54 Susan Doe   <NA>    <NA>
    

    reprex package (v0.3.0) 于 2020 年 6 月 28 日创建

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-01
      • 2013-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多