【问题标题】:compressing similar columns when converting a data.table from long to wide [duplicate]将data.table从长转换为宽时压缩相似的列[重复]
【发布时间】:2017-01-19 01:28:00
【问题描述】:

我正在处理一个纵向数据集,并在长格式 data.table 中对主题进行重复观察。大多数受试者有少数(100)次观察。我可以将这个数据集从长转换为宽,如下所示,但它变得非常宽(我在每个时间点都有很多变量)并且大部分都充满了 NA,因为大多数受试者在 11 到 100 的时间没有变量数据. 有没有更优雅的方式将这些数据重铸为宽格式?我在想其他语言中的参差不齐的数组......

存在一些解决方案here,但对我来说一个大问题是对象大小:具有大量 NA 的宽矩阵占用了大量不必要的空间。

下面是我当前(不希望的稀疏矩阵)解决方案的 MWE。理想情况下,如果某种参差不齐的列表方法可行,则生成的对象将有 3 行和 3 列,其中“年份”和“代码”列是列表或类似的。作为奖励,如果我可以将“代码”变量嵌套在“年份”变量中作为嵌套的不规则数组,那就太好了。

library(data.table)

dat <- data.table(id=c(rep(1,5), rep(2,10), rep(3,85)),
    year=sample(2013:2016, 100, replace=TRUE),
    code=sample(LETTERS, 100, replace=TRUE))

wideDat <- dcast(dat, id~paste0("code", dat[,seq_len(.N), by=id]$V1), 
    value.var="code")

【问题讨论】:

  • 您能否提供一个看起来像您想要的输出的对象?我猜它不像wideDat
  • @Frank 这实际上是我的问题的一部分:我最近才开始使用 data.table,并且在许多情况下发现灵活定义数据对象的奇妙惊喜。希望有人可以在这里同样启发我。在一个伪对象中:列id=c(1,2,3);列year 是一个长度为 3 的列表,每个项目的条目数与纵向观测值一样多(不存储数百个 NA);列 code 是一个长度为 3 的列表,其定义类似于 year。不一定停留在列表上(并且不确定在 data.table 的上下文中是否可行),这就是我想到的。
  • 好的。您可以使用dat[, lapply(.SD, list), by=id],但这对于分析或打印或我能想到的其他任何事情都不是非常有用的格式。

标签: r data.table dcast


【解决方案1】:

一些想法

object.size(wideDat)
# 22432 bytes

# the following structures leverages the fact that years are missing 
wideDat2 <- dcast(dat, id+year~code)   
#   id year A B C D E F G I J K L M N O P Q R S T U V W X Y Z
#1:  1 2014 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
#2:  1 2015 0 0 1 0 0 0 0 0 1 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0
#3:  2 2013 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
#4:  2 2014 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0
#5:  2 2015 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
#6:  2 2016 0 1 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0
#7:  3 2013 1 0 0 1 0 1 1 2 2 0 1 1 2 1 1 2 3 0 1 0 0 2 0 0 1
#8:  3 2014 1 2 0 0 2 1 0 3 0 0 3 0 0 0 3 1 0 2 1 1 0 2 0 0 2
#9:  3 2015 0 2 1 0 0 0 0 2 2 1 1 0 0 0 1 0 3 1 2 1 2 1 1 0 0
#10: 3 2016 1 0 0 2 0 1 0 0 0 1 0 2 1 2 1 1 1 0 1 0 1 1 0 1 0

object.size(wideDat2)
# 6872 bytes

## the following struture just compresses the codes as strings
library(dplyr)
wideDat3 <- dat %>% 
  group_by(id, year) %>% 
  arrange(id, year, code) %>%
  summarize(codes = paste0(code, collapse=","))
#      id  year                                           codes
<#   dbl> <int>                                           <chr>
#1      1  2014                                               P
#2      1  2015                                         C,J,L,L
#3      2  2013                                               B
#4      2  2014                                             S,W
#5      2  2015                                             A,A
#6      2  2016                                       B,G,K,O,S
#7      3  2013   A,D,F,G,I,I,J,J,L,M,N,N,O,P,Q,Q,R,R,R,T,W,W,Z
#8      3  2014 A,B,B,E,E,F,I,I,I,L,L,L,P,P,P,Q,S,S,T,U,W,W,Z,Z
#9      3  2015       B,B,C,I,I,J,J,K,L,P,R,R,R,S,T,T,U,V,V,W,X
#10     3  2016               A,D,D,F,K,M,M,N,O,O,P,Q,R,T,V,W,Y
object.size(wideDat3)
# 2856 bytes

## .. or as nested list 
wideDat4 <- dat %>% 
  group_by(id, year) %>% 
  arrange(id, year, code) %>%
  summarize(codes = list(code))
#   id  year      codes
#<dbl> <int>     <list>
#  1      1  2014  <chr [1]>
#  2      1  2015  <chr [4]>
#  3      2  2013  <chr [1]>
#  4      2  2014  <chr [2]>
#  5      2  2015  <chr [2]>
#  6      2  2016  <chr [5]>
#  7      3  2013 <chr [23]>
#  8      3  2014 <chr [24]>
#  9      3  2015 <chr [21]>
#  10     3  2016 <chr [17]>

object.size(widedat4)
# 6776 bytes

【讨论】:

  • 非常有帮助,感谢您提出一个我在原始问题中忘记提及的关键思想:对象大小。我的实际数据比 MWE 大得多,所以我在wideDat 中的所有NA 中使用了大量不必要的空间。您的 wideDat4 将我带到了我想去的地方,修改 wideDat5 &lt;- dat %&gt;% group_by(id) %&gt;% arrange(id, year, code) %&gt;% summarize(years=list(year), codes = list(code)) 提供了“tibble”对象(大小 4960 字节),这正是我所寻求的。
  • @T.Gerke Fyi wideDat6 = setnames(dat[order(id, year, code), lapply(.SD, list), by=id], c("id", "years", "codes")) 是到达那里的另一种方式(使用 data.table)。 all.equal(data.frame(wideDat5), data.frame(wideDat6)) # TRUE 对象大小为4904 bytes
  • @Frank 这正是我正在寻找的:打印比wideDat5更干净一点,在data.table的范围内工作(并不是我非常反对调用 dplyr,但确实使事情更清洁),并且比 wideDat5 略小
猜你喜欢
  • 2019-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多