将 data.table 从长转换为宽时压缩相似的列
compressing similar columns when converting a data.table from long to wide
我正在处理一个纵向数据集,其中包含对长格式受试者的重复观察 data.table。大多数受试者有一些(<10)次重复观察,而少数受试者有很多(>100)次观察。我可以将这个数据集从长转换为宽,如下所示,但它变得非常宽(我在每个时间点都有很多变量)并且大部分都是 NA,因为大多数受试者在时间 11 到 100 没有变量数据. 有没有更优雅的方法将这些数据重铸为宽格式?我在想其他语言中参差不齐的数组的一些东西......
存在一些解决方案here,但我最关心的是对象大小:具有大量 NA 的宽矩阵占用了很多不必要的 space。
下面是一个 MWE 和我当前的(不理想的稀疏矩阵)解决方案。理想情况下,如果某种参差不齐的列表方法可行,生成的对象将有 3 行和 3 列,其中 "year" 和 "code" 列是列表或类似的。作为奖励,如果我可以将 "code" 变量嵌套在 "year" 变量中作为嵌套的参差不齐的数组,那就太好了。
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")
一些想法
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
我正在处理一个纵向数据集,其中包含对长格式受试者的重复观察 data.table。大多数受试者有一些(<10)次重复观察,而少数受试者有很多(>100)次观察。我可以将这个数据集从长转换为宽,如下所示,但它变得非常宽(我在每个时间点都有很多变量)并且大部分都是 NA,因为大多数受试者在时间 11 到 100 没有变量数据. 有没有更优雅的方法将这些数据重铸为宽格式?我在想其他语言中参差不齐的数组的一些东西......
存在一些解决方案here,但我最关心的是对象大小:具有大量 NA 的宽矩阵占用了很多不必要的 space。
下面是一个 MWE 和我当前的(不理想的稀疏矩阵)解决方案。理想情况下,如果某种参差不齐的列表方法可行,生成的对象将有 3 行和 3 列,其中 "year" 和 "code" 列是列表或类似的。作为奖励,如果我可以将 "code" 变量嵌套在 "year" 变量中作为嵌套的参差不齐的数组,那就太好了。
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")
一些想法
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