【问题标题】:tibble with list columns: Convert to array if possible带有列表列的小标题:如果可能,转换为数组
【发布时间】:2017-02-24 02:08:03
【问题描述】:

我有一个小标题如下:

uuu <- structure(list(IsCharacter = c("a", "b"),
                      ShouldBeCharacter = list("One", "Another"),
                      IsList = list("Element1", c("Element2", "Element3"))
               ),
           .Names = c("IsCharacter", "ShouldBeCharacter", "IsList"),
            row.names = c(NA, -2L), class = c("tbl_df", "tbl", "data.frame"))
uuu
## A tibble: 2 × 3
#  IsCharacter ShouldBeCharacter    IsList
#        <chr>            <list>    <list>
#1           a         <chr [1]> <chr [1]>
#2           b         <chr [1]> <chr [2]>

我想将“ShouldBeCharacter”之类的列(其中所有元素的长度和类型都相同)转换为类似于“IsCharacter”的列,而其余列保持不变。

到目前为止,我有以下功能可以解决问题,但对我来说它看起来很hacky。我想知道是否有更好的解决方案我没有考虑:

lists_to_atomic <- function(data) {
  # Elements of length larger than one should be kept as lists.
  # So we compute the maximum length for each column
  length_column_elements <- apply(data, 2,
                                  function(x) max(sapply(x, function(y) length(y))))
  # to_simplify will contain column names of class list and with all elements of length 1
  to_simplify <- colnames(data)[length_column_elements == 1 & sapply(data, class) == "list"]
  # Do the conversion
  data[,to_simplify] <- tibble::as_tibble(lapply(as.list(data[,to_simplify]), function(x) {do.call(c, x)}))
  return(data)  
}

这是我得到的结果,注意 ShouldBeCharacter 的类型是如何变化的:

lists_to_atomic(uuu)
## A tibble: 2 × 3
#  IsCharacter ShouldBeCharacter    IsList
#        <chr>             <chr>    <list>
#1           a               One <chr [1]>
#2           b           Another <chr [2]>

as_tibble(lapply(as.list(... do.call(c,...))) 行对我来说太复杂了,但我找不到更简单的替代方案。

是否有任何简化可以使我的lists_to_atomic 函数更可靠?

更新

我没有考虑在 list 类型的列和长度为 1 的元素上使用 tidyr::unnest,但是按照 @taavi-p 的回答,我已经能够将函数简化为:

lists_to_atomic <- function(data) {
  # Elements of length larger than one should be kept as lists.
  # So we compute the maximum length for each column
  length_column_elements <- apply(data, 2,
                                  function(x) max(sapply(x, function(y) length(y))))
  # to_simplify will contain column names of class list and with all elements of length 1
  to_simplify <- colnames(data)[length_column_elements == 1 & 
                                vapply(data,
                                       FUN = function(x) "list" %in% class(x),
                                       FUN.VALUE = logical(1))]

  # Do the conversion
  data2 <- tidyr::unnest_(data, unnest_cols = to_simplify)
  data2 <- data2[, colnames(data)] # Preserve original column order
  return(data2)
}

【问题讨论】:

  • 您是如何开始设计这样一个结构的?解决根本问题可能比事后清理混乱更容易。
  • @MrFlick 我有一堆文本文件。每个文本文件都有几个“键:值”字段,其中一些“值”是可变长度的数组。如果我创建一个每个文件一行,每个键一列的数据框,则某些列将类似于 ShouldBeCharacter,而其他列则类似于 IsList。据我所知,有很多 R 用户将线性模型存储在数据框列中,因此拥有数组对我来说似乎并不那么混乱......

标签: r tidyverse


【解决方案1】:

你可以试试:

     library(tidyr)
     uuu %>% unnest(ShouldBeCharacter) 

更多关于如何处理列表列的例子可以在“R for Data Science”中找到:http://r4ds.had.co.nz/many-models.html#list-columns-1

【讨论】:

  • unnest 的一个问题是我不知道哪些列需要提前转换。但是,在阅读您的答案之前,我从未想过将 unnest 与长度为 1 的列表列一起使用,因此根据您的建议,我已经能够稍微简化我的功能!
猜你喜欢
  • 1970-01-01
  • 2020-02-11
  • 2023-03-19
  • 2018-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
相关资源
最近更新 更多