在R中重塑数据框

17

我在重塑一个大型数据框时遇到了困难。以往我相对幸运地避免了这类问题,但也意味着我在此方面表现非常不好。

我当前的数据框大致如下:

unique_id    seq   response    detailed.name    treatment 
a            N1     123.23     descr. of N1     T1
a            N2     231.12     descr. of N2     T1
a            N3     231.23     descr. of N3     T1
...
b            N1     343.23     descr. of N1     T2
b            N2     281.13     descr. of N2     T2
b            N3     901.23     descr. of N3     T2
...

And I'd like:

seq    detailed.name   T1           T2
N1     descr. of N1    123.23       343.23
N2     descr. of N2    231.12       281.13
N3     descr. of N3    231.23       901.23

我已经研究了reshape包,但是我不确定如何将治疗因素转换为单独的列名。

谢谢!

编辑:我在我的本地机器上尝试运行此操作(4GB双核iMac 3.06Ghz),但一直失败:

> d.tmp.2 <- cast(d.tmp, `SEQ_ID` + `GENE_INFO` ~ treatments)
Aggregation requires fun.aggregate: length used as default
R(5751) malloc: *** mmap(size=647168) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug

我有机会的时候会试着在我们更大的机器上运行这个程序。


哦,如果你遇到了内存问题,你可能需要在空间和速度之间做出权衡。由于你的df似乎是可预测的有序和分组的,没有长距离依赖关系,所以可能需要使用C风格的嵌套for循环。你将不得不在创建新的df时扩展它,但你不会像melt-cast那样复制和传递巨大的向量... - Harlan
就像Harlan所说的那样。以一个合并的子集结束可能会更容易/更干净地进行编程。或者,也许你只是希望我们说它“可以”,你真的“需要”一段时间考虑过的8GB内存来运行64位的R ;) - Eduardo Leoni
在R中,熔化和转换是可以有效地用于重塑数据的函数。用于执行此操作的函数称为melt()和cast()。该网址http://datasciencemadesimple.com/melting-casting-r/进行了示例说明。 - karaimadai
5个回答

22

对我来说,reshape似乎总是很棘手,但只要试错一下,它似乎总是有效的。这是我最终找到的:

> x
  unique_id seq response detailed.name treatment
1         a  N1   123.23           dN1        T1
2         a  N2   231.12           dN2        T1
3         a  N3   231.23           dN3        T1
4         b  N1   343.23           dN1        T2
5         b  N2   281.13           dN2        T2
6         b  N3   901.23           dN3        T2

> x2 <- melt(x, c("seq", "detailed.name", "treatment"), "response")
> x2
  seq detailed.name treatment variable  value
1  N1           dN1        T1 response 123.23
2  N2           dN2        T1 response 231.12
3  N3           dN3        T1 response 231.23
4  N1           dN1        T2 response 343.23
5  N2           dN2        T2 response 281.13
6  N3           dN3        T2 response 901.23

> cast(x2, seq + detailed.name ~ treatment)
  seq detailed.name     T1     T2
1  N1           dN1 123.23 343.23
2  N2           dN2 231.12 281.13
3  N3           dN3 231.23 901.23

你的原始数据已经是长格式,但不是melt/cast使用的长格式。因此我重新进行了melt操作。第二个参数(id.vars)是不需要melt的项目列表。第三个参数(measure.vars)是变量列表。

然后,cast使用一个公式。波浪线左侧的是保持不变的内容,波浪线右侧的是用于条件化值列的列。

大体上就是这样...!


1
伙计,你真快,哈兰。文斯,我总是试着记住,在cast()右侧的任何内容都将成为最终数据框中具有值的列。 - Matt Parker

6

在Harlan的答案基础上 - 如果数据已经处于长格式中,并且在cast调用中指定了保存值的列,则可以避免重新熔化步骤。

> x <- read.table(textConnection("  unique_id seq response detailed.name treatment
+ 1         a  N1   123.23           dN1        T1
+ 2         a  N2   231.12           dN2        T1
+ 3         a  N3   231.23           dN3        T1
+ 4         b  N1   343.23           dN1        T2
+ 5         b  N2   281.13           dN2        T2
+ 6         b  N3   901.23           dN3        T2"))
> 
> cast(x, seq + detailed.name ~ treatment, value = "response")
  seq detailed.name     T1     T2
1  N1           dN1 123.23 343.23
2  N2           dN2 231.12 281.13
3  N3           dN3 231.23 901.23

3

另一个选择是使用tidyr中的spread

library(tidyr) 
Wide1 <- spread(x[-1], treatment, response)
Wide1
#  seq detailed.name     T1     T2
#1  N1           dN1 123.23 343.23
#2  N2           dN2 231.12 281.13
#3  N3           dN3 231.23 901.23

相反的操作由gather执行。
gather(Wide1, detailed.name, response, T1:T2)
#  seq detailed.name detailed.name response
#1  N1           dN1            T1   123.23
#2  N2           dN2            T1   231.12
#3  N3           dN3            T1   231.23
#4  N1           dN1            T2   343.23
#5  N2           dN2            T2   281.13
#6  N3           dN3            T2   901.23

此外,还有来自data.tabledcast.data.table
library(data.table)
dcast.data.table(setDT(x), seq + detailed.name~treatment,
                                          value.var='response')
#   seq detailed.name     T1     T2
#1:  N1           dN1 123.23 343.23
#2:  N2           dN2 231.12 281.13
#3:  N3           dN3 231.23 901.23

数据

x <- structure(list(unique_id = structure(c(1L, 1L, 1L, 2L, 2L, 2L
), .Label = c("a", "b"), class = "factor"), seq = structure(c(1L, 
2L, 3L, 1L, 2L, 3L), .Label = c("N1", "N2", "N3"), class = "factor"), 
response = c(123.23, 231.12, 231.23, 343.23, 281.13, 901.23
), detailed.name = structure(c(1L, 2L, 3L, 1L, 2L, 3L), .Label = c("dN1", 
"dN2", "dN3"), class = "factor"), treatment = structure(c(1L, 
1L, 1L, 2L, 2L, 2L), .Label = c("T1", "T2"), class = "factor")), .Names =
c("unique_id", "seq", "response", "detailed.name", "treatment"), class = 
"data.frame", row.names = c(NA, -6L))

2
您也可以使用 stats 软件包中的 reshape 函数。我没有您的样本数据集,但它应该类似于以下内容:
reshape(x, idvar=c("seq","detailed.name"), timevar="treatment", direction="wide")

1
如果你想使用更快、更省内存的 reshape2 重新编写 reshape 包,以获得相同的结果,则可以使用以下代码:
主要更改是在输出为 data.frame 的情况下使用 dcast 函数来进行 cast 操作。这替代了 reshapecast 函数。
library(reshape2)

x = read.table(text = "unique_id seq   response  detailed.name treatment
                           a      N1    123.23         dN1        T1
                           a      N2    231.12         dN2        T1
                           a      N3    231.23         dN3        T1
                           b      N1    343.23         dN1        T2
                           b      N2    281.13         dN2        T2
                           b      N3    901.23         dN3        T2", 
sep = "", header = TRUE)

x

y <- dcast(x, seq + detailed.name ~ treatment, value.var = "response")
y
#   seq detailed.name     T1     T2
# 1  N1           dN1 123.23 343.23
# 2  N2           dN2 231.12 281.13
# 3  N3           dN3 231.23 901.23

# EDIT to show how to return to the original data set:

melt(y, id.vars=c('seq', 'detailed.name'), variable.name='T', value.name='response')

#   seq detailed.name  T response
# 1  N1           dN1 T1   123.23
# 2  N2           dN2 T1   231.12
# 3  N3           dN3 T1   231.23
# 4  N1           dN1 T2   343.23
# 5  N2           dN2 T2   281.13
# 6  N3           dN3 T2   901.23

reshape2是对reshape的重写,以实现更快速和更高效的内存使用。它与reshape不兼容,因此需要新的包而不是旧包的新版本。 - mnel
@Mark Miller:你用这个工具处理过最大的数据框是多少? - andilabs

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