r - 转置数据框时对象大小会大幅增加

标签 r dataframe memory transpose

我有一个 ca 的数据框。行中有 50,000 个 RNA 转录本,列中有 10,000 个不同的样本。数据框的大小为 4.9GB。

然后我必须转置数据以便稍后对其进行正确的子集化:

df <- data.frame(t(df))

转置后,对象大小膨胀到 70GB。为什么会这样?转置数据真的会改变文件大小吗?

str()前 20 列中的:

str(df[1:20])
Classes 'tbl_df', 'tbl' and 'data.frame':   56202 obs. of  20 variables:
 $ X1                      : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Name                    : chr  "ENSG00000223972.4" "ENSG00000227232.4" "ENSG00000243485.2" "ENSG00000237613.2" ...
 $ Description             : chr  "DDX11L1" "WASH7P" "MIR1302-11" "FAM138A" ...
 $ GTEX-1117F-0226-SM-5GZZ7: num  0.1082 21.4 0.1602 0.0505 0 ...
 $ GTEX-111CU-1826-SM-5GZYN: num  0.1158 11.03 0.0643 0 0 ...
 $ GTEX-111FC-0226-SM-5N9B8: num  0.021 16.75 0.0467 0.0295 0 ...
 $ GTEX-111VG-2326-SM-5N9BK: num  0.0233 8.172 0 0.0326 0 ...
 $ GTEX-111YS-2426-SM-5GZZQ: num  0 7.658 0.0586 0 0 ...
 $ GTEX-1122O-2026-SM-5NQ91: num  0.0464 9.372 0 0 0 ...
 $ GTEX-1128S-2126-SM-5H12U: num  0.0308 10.08 0.1367 0.0861 0.1108 ...
 $ GTEX-113IC-0226-SM-5HL5C: num  0.0936 13.56 0.2079 0.131 0.0562 ...
 $ GTEX-117YX-2226-SM-5EGJJ: num  0.121 9.889 0.0537 0.0677 0 ...
 $ GTEX-11DXW-0326-SM-5H11W: num  0.0286 9.121 0.0635 0 0 ...
 $ GTEX-11DXX-2326-SM-5Q5A2: num  0 6.698 0.0508 0.032 0 ...
 $ GTEX-11DZ1-0226-SM-5A5KF: num  0.0237 9.835 0 0.0664 0 ...
 $ GTEX-11EI6-0226-SM-5EQ64: num  0.0802 13.1 0 0 0 ...
 $ GTEX-11EM3-2326-SM-5H12B: num  0.0223 8.904 0.0496 0.0625 0.0402 ...
 $ GTEX-11EMC-2826-SM-5PNY6: num  0.0189 16.59 0 0.0265 0.034 ...
 $ GTEX-11EQ8-0226-SM-5EQ5G: num  0.0931 15.1 0.0689 0.0869 0 ...
 $ GTEX-11EQ9-2526-SM-5HL66: num  0.0777 9.838 0 0 0 ...

最佳答案

首先,你写下:

I then have to transpose this dataset in order to subset it properly later,

老实说,我怀疑你必须这么做。因此,这可能是一个 XY 问题。也就是说,我认为剖析这个问题可能会引起普遍兴趣。


对象大小的增加很可能是由于转置前后对象的发生了变化,以及不同类的对象大小不同。

我将尝试用一些例子来说明这一点。我们从类(class)的变化开始。

创建一个玩具数据框,其结构与您的结构类似,包含几个字符列和几个数字列:

# set number of rows and columns
nr <- 5
nc <- 5

set.seed(1)
d <- data.frame(x = sample(letters, nr, replace = TRUE),
                y = sample(letters, nr, replace = TRUE),
                matrix(runif(nr * nc), nrow = nr),
                stringsAsFactors = FALSE)

转置它:

d_t <- t(d)

检查原始数据及其转置兄弟的str结构:

str(d)
# 'data.frame': 5 obs. of  7 variables:
# $ x : chr  "g" "j" "o" "x" ...
# $ y : chr  "x" "y" "r" "q" ...
# $ X1: num  0.206 0.177 0.687 0.384 0.77
# $ X2: num  0.498 0.718 0.992 0.38 0.777
# $ X3: num  0.935 0.212 0.652 0.126 0.267
# $ X4: num  0.3861 0.0134 0.3824 0.8697 0.3403
# $ X5: num  0.482 0.6 0.494 0.186 0.827

str(d_t)
# chr [1:7, 1:5] "g" "x" "0.2059746" "0.4976992" ...
# - attr(*, "dimnames")=List of 2
#  ..$ : chr [1:7] "x" "y" "X1" "X2" ...
#  ..$ : NULL

数据框变成了字符矩阵。这怎么发生的?好吧,查看数据框转置方法的帮助文本:?t.data.frame:

A data frame is first coerced to a matrix: see as.matrix.

好的,请参阅?as.matrix:

The method for data frames will return a character matrix if there is only atomic columns and any non-(numeric/logical/complex) column [...]

虽然数据框是一个列表,其中每一列都可以属于不同类,但矩阵只是一个具有维度的向量,它只能包含一个类。因此,因为您至少有一个字符列,即一个非(数字/逻辑/复杂)列,您的数据框会由于 t 转置而被强制转换为字符矩阵。然后将矩阵强制转换为数据框,其中所有列都是字符(或 factor,具体取决于您的 stringsAsFactors 设置)- 检查 str(data.frame(d_t ))


第二步,比较不同对象的大小。从上面创建的数据框及其转置开始:

# original data frame
object.size(d)
# 2360 bytes

# transposed df - a character matrix
object.size(d_t)
# 3280 bytes

转置后的物体明显变大了。如果我们增加行数和数字列数以更好地模拟您的数据,则相对差异会更大:

nr <- 56202
nc <- 20 

object.size(d)
# 9897712 bytes
object.size(d_t)
# 78299656 bytes

因为原始数据和转置数据中的元素数量相同,所以每个单独元素的(内存)大小必须不同。让我们检查相同长度的 integernumericcharacter 向量的大小。首先,具有一位数值的向量和一个对应的单字符元素向量:

onedigit_int <- sample(1:9, 1e4, replace = TRUE)
onedigit_num <- as.numeric(onedigit_int)
onedigit_char <- as.character(onedigit_int)    

object.size(onedigit_int)
# 40048 bytes

object.size(onedigit_num)
# 80048 bytes

object.size(onedigit_char)
# 80552 bytes

对于单个数字/字符,integer 向量每个元素占用 4 个字节,numericcharacter 向量每个元素占用 8 个字节。单字符向量需要比数字向量更多的内存。这是否意味着我们可以拒绝总大小的增加是由大量数字变量强制转换为字符来解释的想法?好吧,我们需要检查具有多位数字的向量(您似乎拥有)及其对应的多字符串向量会发生什么情况:

multidigit_int <- sample(1:1e6, 1e4, replace = TRUE)
multidigit_num <- as.numeric(multidigit_int)
multidigit_char <- as.character(multidigit_int)

object.size(multidigit_int)
# 40048 bytes

object.size(multidigit_num)
# 80048 bytes

object.size(multidigit_char)
# 637360 bytes  

整数向量仍然为每个元素占用 4 个字节,数值向量仍然为每个元素占用 8 个字节。但是,对于较大的字符串,字符向量中每个元素的大小越大

因此,转置将您的数据框强制转换为字符矩阵,并且每个字符元素的大小都大于其对应的数字元素。

不同 类的列转置数据框很少是明智的。如果所有列属于相同类,那么我们也可以从一开始就使用矩阵。


Advanced R by Hadley Wickham 中阅读更多关于使用多少内存存储不同对象的信息

关于r - 转置数据框时对象大小会大幅增加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53409246/

相关文章:

arrays - 在 MATLAB 中预分配数组的替代方法是什么?

c++ - 除了使用 new 之外,还有什么会导致内存泄漏? (c++)

java - 如何获取已启动进程的内存使用情况

用 R 中的 NA 替换数据帧中的 -Inf

python - 当您知道列和行引用时如何更改数据框中的字段值

python - 如何将 pd.Series 添加到多索引 DataFrame 的子集?

sorting - 根据DateTime字段对 Pandas 数据框进行排序

r - 如何快速绘制小标题的一列与所有其他列的图表?

r - R中的错误栏?

RCurl 不检索网站的完整源文本 - 链接丢失?