将data.table从long转换为宽

时间:2017-01-19 01:28:01

标签: r data.table dcast

我正在使用纵向数据集,对长格式data.table中的主题进行重复观察。大多数受试者具有少量(<10)重复观察,而少数受试者具有许多(> 100)观察结果。我可以将这个数据集从长到宽转换为如下所示,但它变得非常宽(我在每个时间点都有很多变量)并且大多数都是满足的,因为大多数主题在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")

1 个答案:

答案 0 :(得分:2)

一些想法

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