将类'data.table'和'data.frame'写入外部文件

n9vozmp4  于 2023-04-18  发布在  其他
关注(0)|答案(1)|浏览(86)

我在R中使用的一个程序生成Classes ‘data.table’ and 'data.frame'的输出
看起来像这样:

str(maytable)
Classes ‘data.table’ and 'data.frame':  106876 obs. of  17 variables:
$ col1  : num  1 2 3 4  ...
$ col2  : chr  "Chr00c00001" "Chr00c00001" "Chr00c00001" "Chr00c00001" ...
$ col3  : num  1 2 3 4 ...
$ col4 :List of 106876
..$ : chr
..$ : chr
..$ : chr 
..$ : chr "Chr1g00005011"
.. [list output truncated]
$col4 :List of 106876
..$ : chr "Chr1g00000491"
..$ : chr
..$ : chr
..$ : chr "Chr1g00000501"
.. [list output truncated]

我想把它写到一个表中,其中每个列都是一列,列上的数据都在行中,这样就可以使用write.table这样的函数

col1    col2      col3       col4       col5
  1  Chr00c00001   1                   Chr1g00000491
  2  Chr00c00001   2
  3  Chr00c00001   3
  4  Chr00c00001   4    Chr1g00005011  Chr1g00000501

我不熟悉data.table和data.frame类的对象,它们显然包含列表和列表元素中的一些其他列表。如果有人能告诉我我有什么样的对象以及如何将其转换为我可以写入文本文件的格式,那就太好了。

dauxcl2d

dauxcl2d1#

这是一个“列表列”和/或“嵌套数据”的概念。它在很多事情上相对有用,但同时许多在非嵌套data.frame类对象上工作得很好的函数不知道如何处理列表列/嵌套数据。这是有合理原因的:简单的(非列表)列显然只是向量,所以任何对向量起作用的东西都对框架的列起作用。然而,对于列表列,只要列表的长度与框架中的行数相同,你就可以在列表列的每个元素中放入 * 任何东西 *。这包括NULL,任意长度的向量,图形对象(grobs),其他类似data.frame的对象、任意嵌套的列表等。
但是,在您的例子中,列表列看起来是长度为0或1的向量。典型的数据解嵌套可能会删除长度为0的行,因此我们需要注意用合理的东西替换空元素,无论是NA还是空字符串(因为列表列看起来是基于字符串的)。
我认为你的数据看起来类似于这样:

obj <- data.table(col1=1:4, col2="c001", col3=11:14, col4=list(NULL, NULL, NULL, "5011"), col5=list("491", NULL, NULL, "501"))
obj
#     col1   col2  col3   col4   col5
#    <int> <char> <int> <list> <list>
# 1:     1   c001    11           491
# 2:     2   c001    12              
# 3:     3   c001    13              
# 4:     4   c001    14   5011    501
Classes 'data.table' and 'data.frame':  4 obs. of  5 variables:
 $ col1: int  1 2 3 4
 $ col2: chr  "c001" "c001" "c001" "c001"
 $ col3: int  11 12 13 14
 $ col4:List of 4
  ..$ : NULL
  ..$ : NULL
  ..$ : NULL
  ..$ : chr "5011"
 $ col5:List of 4
  ..$ : chr "491"
  ..$ : NULL
  ..$ : NULL
  ..$ : chr "501"

我知道这个示例显式显示了NULL,而你的示例没有。这不会改变任何东西:如果您数据是""而不是NULL,那么我的“防止长度为0”步骤不会造成任何损害。
我认为这是一个安全的事情,首先确认我们所拥有的将减少 * 简单 *。也就是说,如果任何元素的长度为(正如我上面提到的),我们需要使它们的长度为-1,并带有一些空的哨兵值。如果任何元素的长度为2或更长,那么这将表明该行需要在每个长度上重复。如果这是已知的和期望的行为,一切都是好的。如果不是,你需要考虑如何聚合/减少数据,例如,minmeanfirstlast,或 sample
另一个注意事项:你有两个(或更多)列表列。如果一个列表列的长度〉1,而另一个列表列的长度不同,那么解决方案就会变得更加模糊。如果它们的长度相同,那么我们可以假设两个在相同行中具有长度为n的元素的列表列应该扩展相同数量的行。然而,如果它们的长度都〉1但长度不同,那么......我们做笛卡尔展开吗?截断?很多方法都可能出错。(我不会在这里“修复”这个条件。)
现在,我假设:

  • 长度为0的元素应为NA(实际为NA_character_);
  • 长度为2+的元素应该扩展行数。

同样,如果你的数据都是长度为1的向量,那么这不会有什么坏处。

obj[, (islist) := lapply(.SD, function(z) replace(z, !sapply(z, length), NA)), .SDcols = islist]
#     col1   col2  col3   col4   col5
#    <int> <char> <int> <list> <list>
# 1:     1   c001    11     NA    491
# 2:     2   c001    12     NA     NA
# 3:     3   c001    13     NA     NA
# 4:     4   c001    14   5011    501

在这里,我们可以使用tidyr::unnest

tidyr::unnest(obj, c(col4, col5))
# # A tibble: 4 × 5
#    col1 col2   col3 col4  col5 
#   <int> <chr> <int> <chr> <chr>
# 1     1 c001     11 <NA>  491  
# 2     2 c001     12 <NA>  <NA> 
# 3     3 c001     13 <NA>  <NA> 
# 4     4 c001     14 5011  501

注意,这将它从类data.table转换为类tbl_df;如果您打算继续使用data.table方言处理帧,那么您将需要as.data.tablesetDT

相关问题