在R中将大量的长数据转换为宽数据

3

我可以帮助您将维度为1558810 x 84的长数据转换成1558810 x 4784的宽数据。以下是详细说明。

我的原始数据如下 -

数据有三个主要列 -

id  empId   dept
1   a       social
2   a       Hist
3   a       math
4   b       comp
5   a       social
6   b       comp
7   c       math
8   c       Hist
9   b       math
10  a       comp

id是唯一的关键字,它告诉我们某个员工在某天去了哪个大学部门。我需要按照以下方式对其进行转换。

id  empId   dept    social  Hist    math    comp
1   a       social  1       0       0       0
2   a       Hist    0       1       0       0
3   a       math    0       0       1       0
4   b       comp    0       0       0       1
5   a       social  1       0       0       0
6   b       comp    0       0       0       1
7   c       math    0       0       1       0
8   c       Hist    0       1       0       0
9   b       math    0       0       1       0
10  a       comp    0       0       0       1

我有两个数据集,一个包含4.9万行,另一个包含155万行。对于较小的数据集,其中有1100个唯一的部门值,我使用了reshape2包中的dcast函数来获取所需的数据集(因此,转换后的数据将具有3+1100列和49k行)。但是当我在具有4700个唯一部门值的大型数据集上使用同样的函数时,我的R会因为内存问题而崩溃。我尝试了各种其他替代方法,如xtabs、reshape等,但每次都因为内存错误而失败。
现在,我已经采用了一个粗糙的FOR循环来实现这个目的-
columns <- unique(ds$dept)

for(i in 1:length(unique(ds$dept))) 
{
  ds[,columns[i]] <- ifelse(ds$dept==columns[i],1,0)
}

但是这种方法非常缓慢,代码已经运行了10个小时了。我是否遗漏了什么解决方法?

任何建议都将非常有帮助!


1
你试过我建议的任何方法吗?第三种方法dcast.data.table应该更快。然而,我没有进行基准测试。 - akrun
tidyrspread 函数应该能够很好地处理大数据。 - bdecaf
2个回答

3
你可以尝试:
df$dept <- factor(df$dept, levels=unique(df$dept))
res <- cbind(df,  model.matrix(~ 0+dept, df))
colnames(res) <- gsub("dept(?=[A-Za-z])", "", colnames(res), perl=TRUE)
res
#   id empId   dept social Hist math comp
#1   1     a social      1    0    0    0
#2   2     a   Hist      0    1    0    0
#3   3     a   math      0    0    1    0
#4   4     b   comp      0    0    0    1
#5   5     a social      1    0    0    0
#6   6     b   comp      0    0    0    1
#7   7     c   math      0    0    1    0
#8   8     c   Hist      0    1    0    0
#9   9     b   math      0    0    1    0
#10 10     a   comp      0    0    0    1

或者您可以尝试:

cbind(df, as.data.frame.matrix(table(df[,c(1,3)])))

或者使用 data.table

library(data.table)
setDT(df)
dcast.data.table(df, id + empId + dept ~ dept, fun=length) 

或者使用qdap
library(qdap)
cbind(df, as.wfm(with(df, mtabulate(setNames(dept, id)))))

数据

df <- structure(list(id = 1:10, empId = c("a", "a", "a", "b", "a", 
"b", "c", "c", "b", "a"), dept = c("social", "Hist", "math", 
"comp", "social", "comp", "math", "Hist", "math", "comp")), .Names = c("id", 
"empId", "dept"), class = "data.frame", row.names = c(NA, -10L))

1
我认为可以避免使用 cbinddcast.data.table(df, id + empId + dept ~ dept, fun=length) - Arun
@Arun 谢谢,我会更新。 - akrun

0

尝试:

> cbind(dd[1:3], dcast(dd, dd$id~dd$dept, length)[-1])
Using dept as value column: use value.var to override.
   id empId   dept comp Hist math social
1   1     a social    0    0    0      1
2   2     a   Hist    0    1    0      0
3   3     a   math    0    0    1      0
4   4     b   comp    1    0    0      0
5   5     a social    0    0    0      1
6   6     b   comp    1    0    0      0
7   7     c   math    0    0    1      0
8   8     c   Hist    0    1    0      0
9   9     b   math    0    0    1      0
10 10     a   comp    1    0    0      0

数据:

> dput(dd)
structure(list(id = 1:10, empId = structure(c(1L, 1L, 1L, 2L, 
1L, 2L, 3L, 3L, 2L, 1L), .Label = c("a", "b", "c"), class = "factor"), 
    dept = structure(c(4L, 2L, 3L, 1L, 4L, 1L, 3L, 2L, 3L, 1L
    ), .Label = c("comp", "Hist", "math", "social"), class = "factor")), .Names = c("id", 
"empId", "dept"), class = "data.frame", row.names = c("1", "2", 
"3", "4", "5", "6", "7", "8", "9", "10"))

当我尝试这个时,出现了错误 - 错误:n必须是正整数 此外:警告信息: 在split_indices(.group, .n)中:强制转换引入了NA - RHelp
答案上面添加了另一个版本。 - rnso
1
在描述中,OP提到我使用了reshape2包中的dcast来获取所需的数据集(因此,转换后的数据将具有3+1100列和49k行)。但是当我在具有4700个唯一部门值的较大数据集上使用相同的函数时,我的R会因为内存问题而崩溃 - akrun
已删除该部分。但如何使用其他方法对错误进行排序?这似乎不是由于任何内存问题引起的,而且R也没有崩溃,可能是因为在dcast公式中仅使用了2个向量。 - rnso
关于这个错误,我不确定。或许,原帖作者能提供更多相关信息。 - akrun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接