R语言中data.frame创建快于matrix的原因探究(非同质数据场景)
问题解答:混合类型场景下创建data.frame为何比matrix更快?
问题背景
我在R中执行计算密集型操作,正寻找最高效的实现方式,但遇到一个疑惑:为什么创建data.frame的速度看起来比创建matrix更快? 按常规认知,当所有数据类型相同时,matrix的性能优于data.frame,但本次场景中数据类型并不一致。
测试代码
library(dplyr) library(igraph) library(bench) set.seed(123) edgelist <- data.frame( node1 = sample(1:2000, 11000, replace = T), node2 = sample(1:2000, 11000, replace = T), weight = runif(11000, min = 0, max = 5) ) g <- graph_from_data_frame(edgelist, directed = F) # 创建data.frame的函数 dat <- function() { dm <- distances(g, weight = E(g)$weight) UTIndex <- which(upper.tri(dm), arr.ind = T) df1 <- data.frame( verticeA = as.numeric(rownames(dm)[UTIndex[, 1]]), verticeB = as.numeric(colnames(dm)[UTIndex[, 2]]), path_length = as.numeric(dm[UTIndex]) ) } # 创建matrix的函数 mat <- function() { dm <- distances(g, weight = E(g)$weight) UTIndex <- which(upper.tri(dm), arr.ind = T) df1 <- cbind( verticeA = as.numeric(rownames(dm)[UTIndex[, 1]]), verticeB = as.numeric(colnames(dm)[UTIndex[, 2]]), path_length = as.numeric(dm[UTIndex]) ) } # 基准测试 results <- bench::mark( dat = dat(), mat = mat(), check = F ) # 单独计时 t1 <- system.time({ df1 <- dat() }) rm(df1) t2 <- system.time({ df1 <- mat() }) rm(df1)
测试结果
> results # A tibble: 2 × 13 expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm> 1 dat 2.89s 2.89s 0.346 269MB 1.39 1 4 2.89s 2 mat 2.83s 2.83s 0.353 315MB 1.41 1 4 2.83s # ℹ 4 more variables: result <list>, memory <list>, time <list>, gc <list> > t1 user system elapsed 2.78 0.04 2.81 > t2 user system elapsed 3.12 0.08 3.21
核心原因分析
- 类型强制统一的额外开销:matrix要求所有元素类型完全一致,即便传入的是同属numeric的不同子类型,
cbind创建matrix时仍会触发隐式的类型检查与统一转换流程,这会消耗额外时间。而data.frame允许列类型独立,无需全局类型统一,节省了这部分开销。 - 内存分配机制差异:从测试结果可见,matrix版本的内存占用(315MB)明显高于data.frame(269MB)。matrix是连续的内存块,处理多来源数据时可能产生临时复制或过度内存预留;而data.frame的列是独立向量,内存分配更灵活,减少了不必要的内存消耗,间接提升了速度。
- 核心操作的占比影响:
distances(g)是本次测试中最耗时的操作,占总时间的绝大部分,后续的data.frame/matrix创建仅为小部分步骤。但即便如此,matrix的额外类型转换与内存开销仍让它在这一步的表现落后于data.frame。
优化建议
如果最终目标是得到表格型数据,直接使用data.frame(或tibble)更适配,尤其是列类型不同的场景;若必须使用matrix,建议提前统一所有输入数据的类型,避免隐式转换带来的额外开销。
内容的提问来源于stack exchange,提问作者EmilA
相关产品推荐
相关产品推荐

