什么时候应该使用 data.frame,什么时候使用 matrix更好?
data.frame
matrix
两者都以矩形格式保存数据,因此有时数据不清楚。
对于何时使用哪种数据类型,是否有一般的经验法则?
答案的一部分已经包含在您的问题中: 如果列(变量)可以预期为不同类型(数字/字符/逻辑等) ,则使用数据框架。矩阵用于同一类型的数据。
因此,只有当您拥有相同类型的数据时,选择矩阵/data.frame 才有问题。
答案取决于您将如何处理 data.frame/Matrix 中的数据。如果要传递给其他函数,那么这些函数的参数的预期类型决定了选择。
另外:
矩阵的内存效率更高:
m = matrix(1:4, 2, 2) d = as.data.frame(m) object.size(m) # 216 bytes object.size(d) # 792 bytes
如果您计划执行任何线性代数类型的操作,则矩阵是必需的。
如果经常按名称引用数据框架的列(通过紧凑的 $运算符) ,则数据框架更为方便。
数据框架也更适合报告(打印)表格信息,因为您可以分别对每一列应用格式。
@ Michal 没有提到的是,矩阵不仅比等价的数据框架小,而且使用矩阵可以使代码比使用数据框架高效得多,而且往往是相当高效的。这就是为什么在内部,许多 R 函数会强制数据帧中的矩阵数据。
数据框架通常要方便得多; 并不总是只有原子数据块。
请注意,您可以有一个字符矩阵; 您不必只有数值数据才能在 R 中构建矩阵。
在将数据框架转换为矩阵时,请注意有一个 data.matrix()函数,它通过将因子转换为基于内部级别的数值来适当地处理因子。通过 as.matrix()强制将导致一个字符矩阵,如果任何因子标签是非数字的。比较:
data.matrix()
as.matrix()
> head(as.matrix(data.frame(a = factor(letters), B = factor(LETTERS)))) a B [1,] "a" "A" [2,] "b" "B" [3,] "c" "C" [4,] "d" "D" [5,] "e" "E" [6,] "f" "F" > head(data.matrix(data.frame(a = factor(letters), B = factor(LETTERS)))) a B [1,] 1 1 [2,] 2 2 [3,] 3 3 [4,] 4 4 [5,] 5 5 [6,] 6 6
对于数据分析任务,我几乎总是使用一个数据框架,因为我通常不仅仅拥有数值变量。当我为包编写函数时,我几乎总是强制使用矩阵,然后将结果格式化为数据框架。这是因为数据框架很方便。
矩阵实际上是一个带有附加方法的向量。 差别在于向量 VS 列表。为了提高计算效率,坚持使用矩阵。如果有必要,可以使用 data.frame。
@ Michal: 矩阵实际上并没有更高的内存效率:
m <- matrix(1:400000, 200000, 2) d <- data.frame(m) object.size(m) # 1600200 bytes object.size(d) # 1600776 bytes
除非你有很多专栏:
m <- matrix(1:400000, 2, 200000) d <- data.frame(m) object.size(m) # 1600200 bytes object.size(d) # 22400568 bytes
矩阵和数据帧是矩形的2D 数组,可以 通过行和列 实现异构 财产,但不是全部。 例子:
矩阵和数据帧是矩形的2D 数组,可以 通过行和列 实现异构 财产,但不是全部。
例子:
M <- list(3.14,TRUE,5L,c(2,3,5),"dog",1i) # a list dim(M) <- c(2,3) # set dimensions print(M) # print result # [,1] [,2] [,3] # [1,] 3.14 5 "dog" # [2,] TRUE Numeric,3 0+1i DF <- data.frame(M) # a data frame print(DF) # print result # X1 X2 X3 # 1 3.14 5 dog # 2 TRUE 2, 3, 5 0+1i M <- matrix(c(1,1,1,1,2,3,1,3,6),3) # a numeric matrix DF <- data.frame(M) # a all numeric data frame solve(M) # obtains inverse matrix solve(DF) # obtains inverse matrix det(M) # obtains determinant det(DF) # error
我再也不能强调两者之间的效率差异了!虽然在一些特别是数据分析的情况下 DFs 确实更方便,但是它们也允许异构数据,而且一些库只接受它们,除非您为特定任务编写一次性代码,否则这些都是次要的。
我给你举个例子。有一个函数可以计算 MCMC 方法的二维路径。基本上,这意味着我们取一个初始点(x,y) ,并在每一步迭代一个特定的算法来找到一个新点(x,y) ,以这种方式构造整个路径。该算法包括计算一个相当复杂的函数,并在每次迭代时生成一些随机变量,所以当它运行12秒钟时,我认为它是很好的,因为它在每一步做了多少东西。也就是说,该函数收集了构造路径中的所有点,以及一个3列 data.frame 中的目标函数的值。所以,3列并不是很大,步骤的数量也超过了合理的10,000(在这种问题中,长度为1,000,000的路径是典型的,所以10,000不算什么)。所以,我认为东风10,000 x3绝对不是一个问题。使用 DF 的原因很简单。在调用函数之后,调用 ggplot ()来绘制结果(x,y)-path。Ggplot ()不接受矩阵。
然后,出于好奇,我决定改变函数来收集矩阵中的路径。幸好 DF 和矩阵的语法相似,我所做的只是将指定 df 作为 data.frame 的代码行更改为将其初始化为矩阵的代码行。在这里我还需要提到,在初始代码中,DF 被初始化为具有最终的大小,所以在后面的函数代码中,只有新的值被记录到已经分配的空间中,并且没有向 DF 添加新行的开销。这使得比较更加公平,也使我的工作更加简单,因为我不需要在函数中进一步重写任何内容。从最初分配所需大小的 data.frame 到相同大小的矩阵,只需要改变一行。为了使函数的新版本适应 ggplot () ,我将现在返回的矩阵转换为 data.frame,以便在 ggplot ()中使用。
在我重新运行代码之后,我简直不敢相信结果。代码在几分之一秒内运行!而不是12秒。同样,在10,000次迭代期间,函数只读取和写入 DF 中已经分配的空间(现在是在矩阵中)中的值。这个差异也适用于合理(或相当小)的尺寸10000x3。
因此,如果使用 DF 的唯一原因是为了使其与 ggplot ()这样的库函数兼容,那么您总是可以在最后一刻将其转换为 DF ——只要您觉得方便,就可以使用矩阵。另一方面,如果你有更充分的理由使用 DF,比如你使用了一些数据分析软件包,这些软件包需要从矩阵到 DFs 再到 DFs 的不断转换,或者你自己不做任何深入的计算,只使用标准软件包(其中许多软件包实际上在内部将 DF 转换为矩阵,完成它们的工作,然后将结果转换回来——因此它们为你做所有的效率工作) ,或者做一次性的工作,这样你就不会在意并且对 DFs 感到更舒服,那么你就不应该担。
或者一个不同的更实用的规则: 如果你有一个问题,比如在 OP 中,使用矩阵,所以你只会在没有这样一个问题的时候使用 DFs (因为你已经知道你必须使用 DFs,或者因为你并不真正关心,因为代码是一次性的等等)。
但总的来说,要把这个效率点放在首位。