应该何时使用data.frame
,何时使用matrix
会更好?
两者都以矩形格式保存数据,因此有时候还不清楚。
关于何时使用哪种数据类型,是否有任何一般的经验法则?
答案 0 :(得分:172)
部分答案已包含在您的问题中:如果可以预期列(变量)具有不同类型(数字/字符/逻辑等),则使用数据框。矩阵用于相同类型的数据。
因此,如果您拥有相同类型的数据,则选择矩阵/ 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
如果您计划进行任何线性代数类型的操作,则矩阵是必需的。
如果您经常按名称(通过紧凑的$运算符)引用其列,则数据框更方便。
数据框也更适合报告(打印)表格信息,因为您可以单独对每列应用格式。
答案 1 :(得分:73)
@Michal没有提到的一点是,不仅矩阵小于等效数据帧,使用矩阵可以使代码比使用数据帧更有效,通常是相当的。这就是为什么在内部,许多R函数将强制转换为数据帧中的矩阵数据的原因之一。
数据框通常更方便;一个人并不总是只有原子数据块。
请注意,您可以使用字符矩阵;你不必只需要数字数据来构建R中的矩阵。
在将数据帧转换为矩阵时,请注意存在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
我几乎总是将数据框用于我的数据分析任务,因为我经常拥有的不仅仅是数字变量。当我为包编写函数时,我几乎总是强制使用矩阵,然后将结果格式化为数据帧。这是因为数据框很方便。
答案 2 :(得分:46)
@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
答案 3 :(得分:9)
矩阵实际上是一个带有其他方法的向量。而data.frame是一个列表。 差异在于向量与列表。为了计算效率,坚持使用矩阵。如果必须,请使用data.frame。
答案 4 :(得分:0)
矩阵和数据帧是矩形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
答案 5 :(得分:0)
我无法再强调两者之间的效率差异!尽管在某些特定的数据分析情况下DF确实是更方便的,但是它们也允许异构数据,并且某些库仅接受它们,除非您为特定任务编写一次性代码,否则所有这些实际上都是次要的。
让我给你一个例子。有一个函数可以计算MCMC方法的2D路径。基本上,这意味着我们采用一个初始点(x,y),并在每个步骤中迭代某种算法以找到一个新点(x,y),以此方式构建整个路径。该算法涉及计算一个非常复杂的函数,并在每次迭代时生成一些随机变量,因此当它运行12秒时,考虑到每个步骤要执行多少工作,我认为这很好。就是说,该函数在3列data.frame中收集了构造路径中的所有点以及目标函数的值。因此,3列不是那么大,步数也超过了合理的10,000(在这种问题中,长度为1,000,000的路径是典型的,因此10,000算不上什么)。因此,我认为DF 10,000x3绝对不是问题。使用DF的原因很简单。调用函数后,调用ggplot()绘制生成的(x,y)路径。 ggplot()不接受矩阵。
然后,出于好奇,我决定更改函数以将路径收集到矩阵中。很高兴DF和矩阵的语法相似,我所做的就是将指定df作为data.frame的行更改为将其初始化为矩阵的行。在这里,我还需要提及的是,在初始代码中,DF已初始化为具有最终大小,因此,在该函数的代码中,稍后仅将新值记录到已分配的空间中,并且没有向新的行添加新行的开销。 DF。这使得比较更加公平,并且也使我的工作更加简单,因为我不需要在函数中进一步重写任何内容。从所需大小的data.frame的初始分配到相同大小的矩阵只有一行更改。为了使函数的新版本适应ggplot(),我将现在返回的矩阵转换为data.frame以用于ggplot()。
重新运行代码后,我不敢相信结果。代码只需几分之一秒就可以运行!而不是大约12秒。再一次,该函数在10,000次迭代期间仅将值读取和写入到DF中已经分配的空间(现在在矩阵中)。而且这种差异也适用于合理(或较小)的10000x3尺寸。
因此,如果您使用DF的唯一原因是使其与ggplot()之类的库函数兼容,则始终可以在最后一刻将其转换为DF-尽可能地使用矩阵方便。另一方面,如果还有更多实质性的理由使用DF,例如您使用某些数据分析包,而这需要从矩阵到DF的不断转换,或者您自己不做任何密集的计算,而仅使用标准软件包(许多软件包实际上是在内部将DF转换为矩阵,执行其工作,然后将结果转换回-这样它们就可以为您完成所有效率工作),或者只做一次工作,这样您就不会在乎和感到更适合使用DF,那么您不必担心效率。
或另一个更实际的规则:如果您有一个问题(例如在OP中),请使用矩阵,因此仅在没有此类问题时才使用DF(因为您已经知道必须使用DF,或者因为您并不在乎,因为代码是一次性的,等等。)
但是一般来说,始终牢记效率点是优先事项。