简体   繁体   English

使用 rapply、purrr、tidyr 完全展平高度嵌套的列表列表

[英]Completely flatten highly nested lists of lists with rapply, purrr, tidyr

Downloaded Facebook data gives me a head ache.下载的 Facebook 数据让我头疼。 It is highly nested (lists of list) and not all lists are equally long.它是高度嵌套的(列表列表)并且并非所有列表都一样长。 The data should become a flat matrix where one list and its sublists are in one row, ie one list including its sublist per row.数据应该成为一个平面矩阵,其中一个列表及其子列表在一行中,即一个列表包括每行的子列表。 So far I have explored three options.到目前为止,我已经探索了三个选项。

Option 1: flatten from purrr选项 1:从purrr变平

Flattens the data structure but scrambles it.扁平化数据结构但打乱它。 So no way of knowing what text was posted when with what kind of picture.所以无法知道用什么样的图片发布了什么文字。 According to the purrr reference manual , I cannot specify an object, eg timestamp, by which the lists should be flattened?根据 purrr参考手册,我不能指定一个对象,例如时间戳,列表应该被展平? I am thinking about thereshape2 package that allows to define an ID variable by which the data is reshaped/manipulated.我正在考虑reshape2 包,它允许定义一个 ID 变量,通过它可以对数据进行整形/操作。

library(RJSONIO)
#read in data with utf-8 encoding else the German Umlaute won't display
dataRAW <- RJSONIO::fromJSON("C:/***file path***/FB rot 2.json",
                    encoding = 'utf-8', stringAsFactors = F)

dataRAWflat <- purrr:::flatten(dataRAW) #scrambles data

--> I know that jsonlite has a flatten function when reading in JSON files. --> 我知道jsonlite在读取 JSON 文件时具有展平功能。 But fromJSON from jsonlite does not allow to define the encoding.但是fromJSON从jsonlite不允许定义编码。 The encoding needs to be defined else it does not display the German Umlaute correctly.需要定义编码,否则它不能正确显示德语变音。 Also tried rjson without success.也试过rjson没有成功。 The text of the posts is key to the project.帖子的文本是项目的关键。 I spent a good amount of figuring out how to display the Umlaute so happy to help with that :-)我花了很多时间弄清楚如何显示 Umlaute 很高兴能帮助解决这个问题:-)

Option 2: unnest_wider from tidyr选项 2:来自tidyr 的 unnest_wider
Gives an error message saying that it should be numeric or a character, but the list 'data' in dataRAW is a character.给出一条错误消息,指出它应该是数字或字符,但 dataRAW 中的列表 'data' 是一个字符。 New to tibbles as a special kind of dataframe.作为一种特殊类型的数据框,tibbles 的新手。 Do tibbles, like dataframes, need to have equally long columns? tibbles 和 dataframes 一样需要有同样长的列吗? What am I missing?我错过了什么?

library(tibble)
tib <- tibble(dataRAW)
tib %>% tidyr:::unnest_wider(data)
Error: Must extract column with a single valid subscript.
x Subscript `var` has the wrong type `function`.
i It must be numeric or character.
Run `rlang::last_error()` to see where the error occurred.
> rlang::last_error()
<error/vctrs_error_subscript_type>
Must extract column with a single valid subscript.
x Subscript `var` has the wrong type `function`.
i It must be numeric or character.
Backtrace:
  1. tib %>% tidyr:::unnest_wider(data)
  2. tidyr:::unnest_wider(., data)
  3. tidyselect::vars_pull(tbl_vars(data), !!enquo(col))
  4. tidyselect:::pull_as_location2(loc, n, vars)
 12. vctrs::vec_as_subscript2(i, arg = "var", logical = "error")
 13. vctrs:::result_get(...)
Run `rlang::last_trace()` to see the full context.
> rlang:::last_trace()
<error/vctrs_error_subscript_type>
Must extract column with a single valid subscript.
x Subscript `var` has the wrong type `function`.
i It must be numeric or character.
Backtrace:
     x
  1. +-tib %>% tidyr:::unnest_wider(data)
  2. \-tidyr:::unnest_wider(., data)
  3.   \-tidyselect::vars_pull(tbl_vars(data), !!enquo(col))
  4.     \-tidyselect:::pull_as_location2(loc, n, vars)
  5.       +-tidyselect:::with_subscript_errors(...)
  6.       | +-base::tryCatch(...)
  7.       | | \-base:::tryCatchList(expr, classes, parentenv, handlers)
  8.       | |   \-base:::tryCatchOne(expr, names, parentenv, handlers[[1L]])
  9.       | |     \-base:::doTryCatch(return(expr), name, parentenv, handler)
 10.       | \-tidyselect:::instrument_base_errors(expr)
 11.       |   \-base::withCallingHandlers(...)
 12.       \-vctrs::vec_as_subscript2(i, arg = "var", logical = "error")
 13.         \-vctrs:::result_get(...)



Option 3: rapply and lapply选项 3: rapply 和 lapply
Both code snippets work and preserve the data structure.两个代码片段都可以工作并保留数据结构。 When I want to convert the data to a matrix for further processing the data structure is messed up.当我想将数据转换为矩阵以进行进一步处理时,数据结构就搞砸了。 I suspect because the data is still nested one level deep.我怀疑是因为数据仍然嵌套一层深。

#code line returns list nested one level deep
FBraw <- lapply(dataRAW, rapply, f = c)
str(FBraw)
List of 40
 $ : Named chr [1:7] "1611853326" "posts/media/ChronikFotos_QNGAWvS8aw/144245114_3813727445333297_3682316138130576479_n_3813727441999964.jpg" "1611853319" "1613542113" ...
  ..- attr(*, "names")= chr [1:7] "timestamp" "attachments.data.media.uri" "attachments.data.media.creation_timestamp" "attachments.data.media.media_metadata.photo_metadata.exif_data.taken_timestamp" ...
 $ : Named chr [1:7] "1611860575" "posts/media/ChronikFotos_QNGAWvS8aw/143276316_3813978641974844_3663341405860849380_n_3813978635308178.png" "1611860403" "1612935033" ...
  ..- attr(*, "names")= chr [1:7] "timestamp" "attachments.data.media.uri" "attachments.data.media.creation_timestamp" "attachments.data.media.media_metadata.photo_metadata.exif_data.taken_timestamp" ...
 $ : Named chr [1:7] "1612948020" "posts/media/ChronikFotos_QNGAWvS8aw/143732770_3813831571989551_5247994518213519901_n_3813831568656218.png" "1611856188" "1617631305" ...

#code snippet 2 
FBraw <- lapply(dataRAW, function(x) data.frame(t(rapply(x, function(x) x[1]))))
str(FBraw, head = 1)
List of 40
 $ :'data.frame':   1 obs. of  7 variables:
 $ :'data.frame':   1 obs. of  7 variables:
 $ :'data.frame':   1 obs. of  7 variables:



Sample Data样本数据

dataRAW <- list(list(timestamp = 1611853326, attachments = list(list(data = list(
  list(media = list(uri = "posts/media/ChronikFotos_QNGAWvS8aw/144245114_3813727445333297_3682316138130576479_n_3813727441999964.jpg", 
                    creation_timestamp = 1611853319, media_metadata = list(
                      photo_metadata = list(exif_data = list(c(taken_timestamp = 1613542113)))), 
                    title = "Chronik-Fotos", description = "Da haben wir den Salat! <U+0001F957> \nGemischt oder grün: Verfeinert mit Frieda’s Traum Salatsauce wird der einfachste Salat zum Gaumenschmaus.\n\nProbieren Sie auch unsere Gewürze, Bouillons und verschiedene Käse! \nHier finden Sie alle unsere würzigen Produkte:  www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>'<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E> – Saucen Bouillons Gewürze\nwww.friedas-traum.ch | shop@friedas.ch | Tel. 055 0"))))), 
  data = list(c(post = "Da haben wir den Salat! <U+0001F957> \nGemischt oder grün: Verfeinert mit Frieda’s Traum Salatsauce wird der einfachste Salat zum Gaumenschmaus.\n\nProbieren Sie auch unsere Gewürze, Bouillons und verschiedene Käse! \nHier finden Sie alle unsere würzigen Produkte:  www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>'<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E> – Saucen Bouillons Gewürze\nwww.friedas-traum.ch | shop@friedas.ch | Tel. 055 "))), 
  list(timestamp = 1611860575, attachments = list(list(data = list(
    list(media = list(uri = "posts/media/ChronikFotos_QNGAWvS8aw/143276316_3813978641974844_3663341405860849380_n_3813978635308178.png", 
                      creation_timestamp = 1611860403, media_metadata = list(
                        photo_metadata = list(exif_data = list(c(taken_timestamp = 1612935033)))), 
                      title = "Chronik-Fotos", description = "Früher über die Gasse – heute im Online- Shop: <U+0001D5D9><U+0001D5FF><U+0001D5F6><U+0001D5F2><U+0001D5F1><U+0001D5EE>’<U+0001D600> <U+0001D5E7><U+0001D5FF><U+0001D5EE><U+0001D602><U+0001D5FA> Produkte. \n\nWas im Restaurant Löwen in Spreitenbach begann, geht heute online weiter: Sie erhalten 100% Geschmack!\n\nEinfach bestellen im Shop: www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>’<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E> – Saucen, Bouillons, Gewürze\nshop@friedas.ch  | Tel. +41 (0) 55 0"))))), 
    data = list(c(post = "Früher über die Gasse – heute im Online- Shop: <U+0001D5D9><U+0001D5FF><U+0001D5F6><U+0001D5F2><U+0001D5F1><U+0001D5EE>’<U+0001D600> <U+0001D5E7><U+0001D5FF><U+0001D5EE><U+0001D602><U+0001D5FA> Produkte. \n\nWas im Restaurant Löwen in Spreitenbach begann, geht heute online weiter: Sie erhalten 100% Geschmack!\n\nEinfach bestellen im Shop: www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>’<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E> – Saucen, Bouillons, Gewürze\nshop@friedas.ch  | Tel. +41 (0) 55 0"))), 
  list(timestamp = 1612948020, attachments = list(list(data = list(
    list(media = list(uri = "posts/media/ChronikFotos_QNGAWvS8aw/143732770_3813831571989551_5247994518213519901_n_3813831568656218.png", 
                      creation_timestamp = 1611856188, media_metadata = list(
                        photo_metadata = list(exif_data = list(c(taken_timestamp = 1617631305)))), 
                      title = "Chronik-Fotos", description = "<U+0001D5E1><U+0001D5EE><U+0001D5F0><U+0001D5F5> <U+0001D5EE><U+0001D5F9><U+0001D601><U+0001D5F2><U+0001D5FA> <U+0001D5E5><U+0001D5F2><U+0001D607><U+0001D5F2><U+0001D5FD><U+0001D601> von Hand gemischt und abgefüllt: Frieda’s Salatsaucen sind beliebt wie eh und je. <U+0001F44C>\n\nFrüher der Renner im Restaurant Löwen in Spreitenbach, heute: DER Hit zum Bestellen für Sie zu Hause.\n\nProbieren Sie auch unsere Bouillons, Gewürze und unseren Käse! \n\nHier geht’s zum Shop:  www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>’<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E>® – Saucen Bouillons Gewürze\nshop@friedas.ch | Tel. 055 0"))))), 
    data = list(c(post = "<U+0001D5E1><U+0001D5EE><U+0001D5F0><U+0001D5F5> <U+0001D5EE><U+0001D5F9><U+0001D601><U+0001D5F2><U+0001D5FA> <U+0001D5E5><U+0001D5F2><U+0001D607><U+0001D5F2><U+0001D5FD><U+0001D601> von Hand gemischt und abgefüllt: Frieda’s Salatsaucen sind beliebt wie eh und je. <U+0001F44C>\n\nFrüher der Renner im Restaurant Löwen in Spreitenbach, heute: DER Hit zum Bestellen für Sie zu Hause.\n\nProbieren Sie auch unsere Bouillons, Gewürze und unseren Käse! \n\nHier geht’s zum Shop:  www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>’<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E>® – Saucen Bouillons Gewürze\nshop@friedas.ch | Tel. 055 0")))) 
  

Any ideas and suggestions appreciated.任何想法和建议表示赞赏。 Thanks.谢谢。

You have a list of elements which have the same properties (eg timestamps and attachments ).您有一个具有相同属性(例如timestampsattachments )的元素列表。 Since these are of different types, you can use a data frame instead of a matrix by enframing the list:由于这些是不同类型的,你可以通过座架列表中使用的数据帧,而不是一个矩阵:

library(tidyverse)

dataRAW <- list(
  list(
    timestamp = 1611853326, attachments = list(list(data = list(
      list(media = list(
        uri = "posts/media/ChronikFotos_QNGAWvS8aw/144245114_3813727445333297_3682316138130576479_n_3813727441999964.jpg",
        creation_timestamp = 1611853319, media_metadata = list(
          photo_metadata = list(exif_data = list(c(taken_timestamp = 1613542113)))
        ),
        title = "Chronik-Fotos", description = "Da haben wir den Salat! <U+0001F957> \nGemischt oder grün: Verfeinert mit Frieda’s Traum Salatsauce wird der einfachste Salat zum Gaumenschmaus.\n\nProbieren Sie auch unsere Gewürze, Bouillons und verschiedene Käse! \nHier finden Sie alle unsere würzigen Produkte:  www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>'<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E> – Saucen Bouillons Gewürze\nwww.friedas-traum.ch | shop@friedas.ch | Tel. 055 0"
      ))
    ))),
    data = list(c(post = "Da haben wir den Salat! <U+0001F957> \nGemischt oder grün: Verfeinert mit Frieda’s Traum Salatsauce wird der einfachste Salat zum Gaumenschmaus.\n\nProbieren Sie auch unsere Gewürze, Bouillons und verschiedene Käse! \nHier finden Sie alle unsere würzigen Produkte:  www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>'<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E> – Saucen Bouillons Gewürze\nwww.friedas-traum.ch | shop@friedas.ch | Tel. 055 "))
  ),
  list(
    timestamp = 1611860575, attachments = list(list(data = list(
      list(media = list(
        uri = "posts/media/ChronikFotos_QNGAWvS8aw/143276316_3813978641974844_3663341405860849380_n_3813978635308178.png",
        creation_timestamp = 1611860403, media_metadata = list(
          photo_metadata = list(exif_data = list(c(taken_timestamp = 1612935033)))
        ),
        title = "Chronik-Fotos", description = "Früher über die Gasse – heute im Online- Shop: <U+0001D5D9><U+0001D5FF><U+0001D5F6><U+0001D5F2><U+0001D5F1><U+0001D5EE>’<U+0001D600> <U+0001D5E7><U+0001D5FF><U+0001D5EE><U+0001D602><U+0001D5FA> Produkte. \n\nWas im Restaurant Löwen in Spreitenbach begann, geht heute online weiter: Sie erhalten 100% Geschmack!\n\nEinfach bestellen im Shop: www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>’<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E> – Saucen, Bouillons, Gewürze\nshop@friedas.ch  | Tel. +41 (0) 55 0"
      ))
    ))),
    data = list(c(post = "Früher über die Gasse – heute im Online- Shop: <U+0001D5D9><U+0001D5FF><U+0001D5F6><U+0001D5F2><U+0001D5F1><U+0001D5EE>’<U+0001D600> <U+0001D5E7><U+0001D5FF><U+0001D5EE><U+0001D602><U+0001D5FA> Produkte. \n\nWas im Restaurant Löwen in Spreitenbach begann, geht heute online weiter: Sie erhalten 100% Geschmack!\n\nEinfach bestellen im Shop: www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>’<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E> – Saucen, Bouillons, Gewürze\nshop@friedas.ch  | Tel. +41 (0) 55 0"))
  ),
  list(
    timestamp = 1612948020, attachments = list(list(data = list(
      list(media = list(
        uri = "posts/media/ChronikFotos_QNGAWvS8aw/143732770_3813831571989551_5247994518213519901_n_3813831568656218.png",
        creation_timestamp = 1611856188, media_metadata = list(
          photo_metadata = list(exif_data = list(c(taken_timestamp = 1617631305)))
        ),
        title = "Chronik-Fotos", description = "<U+0001D5E1><U+0001D5EE><U+0001D5F0><U+0001D5F5> <U+0001D5EE><U+0001D5F9><U+0001D601><U+0001D5F2><U+0001D5FA> <U+0001D5E5><U+0001D5F2><U+0001D607><U+0001D5F2><U+0001D5FD><U+0001D601> von Hand gemischt und abgefüllt: Frieda’s Salatsaucen sind beliebt wie eh und je. <U+0001F44C>\n\nFrüher der Renner im Restaurant Löwen in Spreitenbach, heute: DER Hit zum Bestellen für Sie zu Hause.\n\nProbieren Sie auch unsere Bouillons, Gewürze und unseren Käse! \n\nHier geht’s zum Shop:  www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>’<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E>® – Saucen Bouillons Gewürze\nshop@friedas.ch | Tel. 055 0"
      ))
    ))),
    data = list(c(post = "<U+0001D5E1><U+0001D5EE><U+0001D5F0><U+0001D5F5> <U+0001D5EE><U+0001D5F9><U+0001D601><U+0001D5F2><U+0001D5FA> <U+0001D5E5><U+0001D5F2><U+0001D607><U+0001D5F2><U+0001D5FD><U+0001D601> von Hand gemischt und abgefüllt: Frieda’s Salatsaucen sind beliebt wie eh und je. <U+0001F44C>\n\nFrüher der Renner im Restaurant Löwen in Spreitenbach, heute: DER Hit zum Bestellen für Sie zu Hause.\n\nProbieren Sie auch unsere Bouillons, Gewürze und unseren Käse! \n\nHier geht’s zum Shop:  www.friedas-traum.ch/\n\n<U+0001D46D><U+0001D493><U+0001D48A><U+0001D486><U+0001D485><U+0001D482>’<U+0001D494> <U+0001D47B><U+0001D493><U+0001D482><U+0001D496><U+0001D48E>® – Saucen Bouillons Gewürze\nshop@friedas.ch | Tel. 055 0"))
  )
)

dataRAW %>%
  enframe()
#> # A tibble: 3 x 2
#>    name value           
#>   <int> <list>          
#> 1     1 <named list [3]>
#> 2     2 <named list [3]>
#> 3     3 <named list [3]>

dataRAW %>%
  enframe() %>%
  unnest_wider(value)
#> # A tibble: 3 x 4
#>    name  timestamp attachments data      
#>   <int>      <dbl> <list>      <list>    
#> 1     1 1611853326 <list [1]>  <list [1]>
#> 2     2 1611860575 <list [1]>  <list [1]>
#> 3     3 1612948020 <list [1]>  <list [1]>

dataRAW %>%
  enframe() %>%
  unnest_wider(value) %>%
  # flatten list with only one element
  unnest(data) %>%
  unnest(data) %>%
  unnest(attachments) %>%
  unnest(attachments) %>%
  unnest(attachments) %>%
  unnest(attachments) %>%
  unnest_wider(attachments) %>%
  select(name, timestamp, creation_timestamp, title, description)
#> # A tibble: 3 x 5
#>    name  timestamp creation_timesta… title   description                        
#>   <int>      <dbl>             <dbl> <chr>   <chr>                              
#> 1     1 1611853326        1611853319 Chroni… "Da haben wir den Salat! <U+0001F9…
#> 2     2 1611860575        1611860403 Chroni… "Früher über die Gasse – heute im …
#> 3     3 1612948020        1611856188 Chroni… "<U+0001D5E1><U+0001D5EE><U+0001D5…

Created on 2021-11-04 by the reprex package (v2.0.1)reprex 包(v2.0.1) 于 2021 年 11 月 4 日创建

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM