用Tidyverse转嵌套列表为DataFrame:优化慢速的unnest_wider
高效转换游戏日志嵌套列表为矩形格式的需求
我读取存储游戏日志的JSON文件后得到一个嵌套列表,其中time为简单向量,inputManagerStates和syncedProperties为可包含0或多个元素的列表。此前用tidyr的unnest_wider将数据转为矩形格式,但处理大量此类JSON文件时,unnest_wider运行速度极慢。
测试列表
test_list <- list(list(time = 9.92405605316162, inputManagerStates = list(), syncedProperties = list()), list(time = 9.9399995803833, inputManagerStates = list(list(inputId = "InputY", buttonState = FALSE, axisValue = 0), list(inputId = "InputX", buttonState = FALSE, axisValue = 0.0501395985484123), list(inputId = "xPos", buttonState = FALSE, axisValue = 5), list(inputId = "yPos", buttonState = FALSE, axisValue = 0.0799999982118607), list(inputId = "zPos", buttonState = FALSE, axisValue = 0), list(inputId = "xRot", buttonState = FALSE, axisValue = 0), list(inputId = "yRot", buttonState = FALSE, axisValue = -0.70664256811142), list(inputId = "zRot", buttonState = FALSE, axisValue = 0), list(inputId = "wRot", buttonState = FALSE, axisValue = 0.707570731639862)), syncedProperties = list(list(name = "timeStamp", value = "97,2"))), list(time = 9.95659446716309, inputManagerStates = list(list( inputId = "InputY", buttonState = FALSE, axisValue = 0), list(inputId = "InputX", buttonState = FALSE, axisValue = 0.0993990004062653), list(inputId = "xPos", buttonState = FALSE, axisValue = 5), list(inputId = "yPos", buttonState = FALSE, axisValue = 0.0799999982118607), list(inputId = "zPos", buttonState = FALSE, axisValue = 0), list(inputId = "xRot", buttonState = FALSE, axisValue = 0), list(inputId = "yRot", buttonState = FALSE, axisValue = -0.705721318721771), list(inputId = "zRot", buttonState = FALSE, axisValue = 0), list(inputId = "wRot", buttonState = FALSE, axisValue = 0.708489596843719)), syncedProperties = list(list(name = "timeStamp", value = "97,21667"))), list(time = 20.0626411437988, inputManagerStates = list(list( inputId = "InputY", buttonState = FALSE, axisValue = 0.601816594600677), list(inputId = "InputX", buttonState = FALSE, axisValue = 0), list(inputId = "xPos", buttonState = FALSE, axisValue = -1.31777036190033), list(inputId = "yPos", buttonState = FALSE, axisValue = 0.0800001174211502), list(inputId = "zPos", buttonState = FALSE, axisValue = 6.08214092254639), list(inputId = "xRot", buttonState = FALSE, axisValue = 0), list(inputId = "yRot", buttonState = FALSE, axisValue = -0.391442984342575), list(inputId = "zRot", buttonState = FALSE, axisValue = 0), list(inputId = "wRot", buttonState = FALSE, axisValue = 0.920202374458313)), syncedProperties = list(list(name = "timeStamp", value = "107,3167"), list(name = "previousGameState", value = "1"), list( name = "newGameState", value = "2"))))
当前转换代码
library(tidyverse) output_df <- test_list %>% tibble::enframe(name = "frame", value = "value") %>% tidyr::unnest_wider(value) %>% tidyr::unnest(inputManagerStates, keep_empty = TRUE) %>% tidyr::unnest(syncedProperties, keep_empty = TRUE) %>% tidyr::unnest_wider(syncedProperties) %>% tidyr::unnest_wider(inputManagerStates) output_df #> # A tibble: 46 x 7 #> frame time inputId buttonState axisValue name value #> <int> <dbl> <chr> <lgl> <dbl> <chr> <chr> #> 1 1 9.92 <NA> NA NA <NA> <NA> #> 2 2 9.94 InputY FALSE 0 timeStamp 97,2 #> 3 2 9.94 InputX FALSE 0.0501 timeStamp 97,2 #> 4 2 9.94 xPos FALSE 5 timeStamp 97,2 #> 5 2 9.94 yPos FALSE 0.0800 timeStamp 97,2 #> 6 2 9.94 zPos FALSE 0 timeStamp 97,2 #> 7 2 9.94 xRot FALSE 0 timeStamp 97,2 #> 8 2 9.94 yRot FALSE -0.707 timeStamp 97,2 #> 9 2 9.94 zRot FALSE 0 timeStamp 97,2 #> 10 2 9.94 wRot FALSE 0.708 timeStamp 97,2 #> # ... with 36 more rows
性能对比
对我的数据而言,unnest速度尚可,但unnest_wider速度极慢。第一个unnest_wider(value)可通过base R代码替代,且速度显著提升:
microbenchmark::microbenchmark( unnest_wider = test_list %>% tibble::enframe(name = "frame", value = "value") %>% tidyr::unnest_wider(value), baser_r = test_list %>% tibble::enframe(name = "frame", value = "value") %>% cbind(., do.call("rbind", .$value)) %>% select(-value) ) #> Unit: milliseconds #> expr min lq mean median uq max neval cld #> unnest_wider 3.1446 3.34645 4.031113 3.63625 4.22770 10.5289 100 b #> baser_r 1.4005 1.48225 1.770210 1.63475 1.86465 5.0407 100 a
需求
我正在寻求替代%>% tidyr::unnest_wider(syncedProperties) %>% tidyr::unnest_wider(inputManagerStates)的更快代码,但因行数量不一致,cbind方案无法适用。尝试用unnest::unnest()未得到预期结构,且tidytable::unnest_wider目前仅支持向量,恳请提供高效解决方案。
内容的提问来源于stack exchange,提问作者Claudiu Papasteri
相关产品推荐
相关产品推荐

