寻找reshape2::melt()替代方案:处理带行列名的矩阵
矩阵转长格式的替代方案及自制函数验证
背景
reshape2::melt()能够将带行列名的矩阵转换为三列数据框,行列名自动作为前两列,示例如下:
testmat <- matrix(1:25,nrow=5,dimnames=list(LETTERS[6:10],LETTERS[1:5])) # A B C D E # F 1 6 11 16 21 # G 2 7 12 17 22 # H 3 8 13 18 23 # I 4 9 14 19 24 # J 5 10 15 20 25 longmat <- reshape2::melt(testmat) head(longmat) # Var1 Var2 value # F A 1 # G A 2 # H A 3 # I A 4 # J A 5 # F B 6
但该函数存在两个明显问题:会自动将Var1和Var2转为因子,且不支持stringsAsFactors=F参数;同时reshape2已停止维护,官方推荐使用tidyr。
尝试过的替代方案均有缺陷:tidyr::pivot_longer()不支持直接输入矩阵,转成数据框后会丢失行名;data.table::melt()会自动重定向到reshape2::melt(),无法解决原有问题。
核心问题
是否存在其他函数(tidyverse或非tidyverse)可实现类似reshape2::melt()的矩阵转长格式功能?
次要问题
自制的melt_by_hand函数是否存在未考虑到的潜在问题?
melt_by_hand <- function(mat) { return(data.frame(row=rep(rownames(mat),ncol(mat)), col=rep(colnames(mat),each=nrow(mat)), value=as.vector(mat))) }
解决方案
替代函数推荐
- tidyverse方案:结合
tibble与pivot_longer
先将矩阵转为保留行名的tibble,再用pivot_longer转长格式,既不会丢失行名,输出列也为字符型而非因子:
library(tidyverse) # 默认按行展开的结果 testmat %>% as_tibble(rownames = "row") %>% pivot_longer(cols = -row, names_to = "col", values_to = "value") %>% head() # # A tibble: 6 × 3 # row col value # <chr> <chr> <int> # 1 F A 1 # 2 F B 6 # 3 F C 11 # 4 F D 16 # 5 F E 21 # 6 G A 2 # 若需匹配reshape2::melt()按列展开的顺序,可添加排序 testmat %>% as_tibble(rownames = "row") %>% pivot_longer(cols = -row, names_to = "col", values_to = "value") %>% arrange(col, row) %>% head() # # A tibble: 6 × 3 # row col value # <chr> <chr> <int> # 1 F A 1 # 2 G A 2 # 3 H A 3 # 4 I A 4 # 5 J A 5 # 6 F B 6
- base R方案:
as.data.frame.table()
base R内置的as.data.frame.table()可直接将矩阵转为长格式数据框,R 4.0+版本默认输出字符型列(无需额外设置stringsAsFactors=FALSE),输出格式与reshape2::melt()几乎一致:
long_mat_base <- as.data.frame.table(testmat, responseName = "value") head(long_mat_base) # Var1 Var2 value # 1 F A 1 # 2 G A 2 # 3 H A 3 # 4 I A 4 # 5 J A 5 # 6 F B 6 # 查看列类型 sapply(long_mat_base, class) # Var1 Var2 value # "character" "character" "integer"
该方法无需额外安装包,适配性更强。
自制函数melt_by_hand的潜在问题分析
- 列名固定化:输出列名被固定为
row/col,无法像标准函数那样通过参数自定义列名(如as.data.frame.table()的responseName参数)。 - 无行列名场景兼容差:若输入矩阵没有
rownames或colnames,rep(rownames(mat), ...)会生成NA,而标准函数会自动生成序列型标识(如1,2,3...)。 - 旧版本R兼容性问题:R 4.0以下版本中
data.frame()默认会将字符列转为因子,函数未设置stringsAsFactors=FALSE参数,会导致列类型不符合预期。 - 扩展性不足:仅支持二维矩阵,无法处理
reshape2::melt()支持的多维数组。 - 效率劣势:针对超大矩阵,
rep()结合as.vector()的纯R实现效率远低于内置函数的底层优化(如as.data.frame.table()基于C级别的处理)。
内容的提问来源于stack exchange,提问作者TiredSquirrel
相关产品推荐
相关产品推荐

