从data.frame中提取列比从矩阵中提取列快-为什么?

时间:2019-01-02 11:56:05

标签: r performance dataframe matrix subset

我正在运行仿真,我需要从矩阵中重复提取1列,并根据某种条件(例如<10)检查其每个值。但是,使用矩阵执行此操作的速度比使用data.frame执行相同操作的速度慢3倍。为什么会这样?

我想使用矩阵存储模拟数据,因为对于其他一些操作(例如,通过添加/减去值来更新列),它们会更快。如何以更快的方式提取列/矩阵的子集?

从data.frame中提取列与矩阵:

df <- data.frame(a = 1:1e4)
m <- as.matrix(df)

library(microbenchmark)
microbenchmark(
  df$a, 
  m[ , "a"])

# Results; Unit: microseconds
#      expr    min      lq     mean median      uq     max neval cld
#      df$a  5.463  5.8315  8.03997  6.612  8.0275  57.637   100   a 
# m[ , "a"] 64.699 66.6265 72.43631 73.759 75.5595 117.922   100   b

从data.frame与矩阵中提取单个值:

microbenchmark(
  df[1, 1],
  df$a[1],
  m[1, 1], 
  m[ , "a"][1])  

# Results; Unit: nanoseconds
#         expr   min      lq     mean  median      uq    max neval  cld
#     df[1, 1]  8248  8753.0 10198.56  9818.5 10689.5  48159   100    c 
#      df$a[1]  4072  4416.0  5247.67  5057.5  5754.5  17993   100    b  
#      m[1, 1]   517   708.5   828.04   810.0   920.5   2732   100    a   
# m[ , "a"][1] 45745 47884.0 51861.90 49100.5 54831.5 105323   100    d

我希望基质柱的提取速度更快,但速度较慢。但是,从矩阵(即m[1, 1])中提取单个值比使用data.frame的两种方法都快。我不知道为什么会这样。

提取行与列,数据。帧与矩阵:

以上内容仅适用于选择列。选择行时,矩阵比data.frames快得多。还是不知道为什么。

microbenchmark(
  df[1, ],
  m[1, ],
  df[ , 1],
  m[ , 1])

# Result: Unit: nanoseconds
#     expr   min      lq     mean  median      uq   max neval  cld
#  df[1, ] 16359 17243.5 18766.93 17860.5 19849.5 42973   100    c 
#   m[1, ]   718   999.5  1175.95  1181.0  1327.0  3595   100    a   
# df[ , 1]  7664  8687.5  9888.57  9301.0 10535.5 42312   100    b  
#  m[ , 1] 64874 66218.5 72074.93 73717.5 74084.5 97827   100    d

2 个答案:

答案 0 :(得分:3)

data.frame

请考虑内置数据框BOD。数据帧存储为列列表,下面显示的inspect输出显示BOD两列中每一列的地址。然后,将其第二列分配给BOD2。请注意,BOD2的地址与inspect的{​​{1}}输出中显示的第二列的存储位置相同。也就是说,R所做的全部工作是BOD指向BOD2内的内存,以便创建BOD。根本没有数据移动。另一种查看方式是比较BOD2BOD和两者的大小,我们发现两者占用的内存量与BOD2相同,因此肯定没有复制。 (接在代码之后。)

BOD

矩阵

矩阵存储为一个带有维的长向量,而不是列的列表,因此提取列的策略有所不同。如果我们查看矩阵library(pryr) BOD2 <- BOD[[2]] inspect(BOD) ## <VECSXP 0x507c278> ## <REALSXP 0x4f81f48> ## <REALSXP 0x4f81ed8> <--- compare this address to address shown below ## ...snip... BOD2 <- BOD[,2] address(BOD2) ## [1] "0x4f81ed8" object_size(BOD) ## 1.18 kB object_size(BOD2) ## 96 B object_size(BOD, BOD2) # same as object_size(BOD) above ## 1.18 kB ,提取的列m所使用的内存,以及两者一起,我们将在下面看到,两者共同使用了单个对象的内存总和,表明存在数据复制。

m2

做什么

如果您的程序只能使用列提取功能,则可以对该部分使用数据框,然后一次转换为矩阵,然后像其余部分一样对其进行处理。

答案 1 :(得分:1)

我想这与内存中R的数据结构有关。 R中的矩阵是2维数组,与1维数组相同。变量是直接指向内存的点,因此提取单个值会非常快。要提取矩阵中的一列,需要进行一些计算,然后请求新的内存地址并将其保存。至于数据框,它实际上是列的列表,因此返回列会更快。 我猜就是那样,希望得到证明。