The melt()
function from the reshape2
package has a convenient behavior where it will convert a matrix with named rows/columns into a three-column data frame with the matrix row/column names becoming the first two columns:
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
But it has the annoying behavior of making Var1 and Var2 factors, and it does not support a stringsAsFactors=F
option. The README for reshape2 says "reshape2 is retired: only changes necessary to keep it on CRAN will be made. We recommend using tidyr instead.", so it seems unlikely this behavior will ever be changed in melt()
.
I have experimented with alternatives, but haven't found something that works yet:
tidyr::pivot_longer()
will not take a matrix as input. Even if I force the matrix to become a data.frame with tidyr::pivot_longer(as.data.frame(testmat),cols=all_of(colnames(testmat)))
, the matrix row names are discarded instead of captured in a column in the result.data.table::melt()
just redirects to reshape2::melt()
.Main question: Is there some other function (tidyverse or non-tidyverse) that will convert a matrix to long form in a manner similar to reshape2::melt()
?
Second question: I've been experimenting with writing my own. Are there any hidden "gotchas" I haven't thought of that might make the function below produce unexpected/incorrect behaviors?
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)))
}
Nothing else but as.data.frame.table
from base R should help
> as.data.frame.table(testmat, stringsAsFactors = FALSE)
Var1 Var2 Freq
1 F A 1
2 G A 2
3 H A 3
4 I A 4
5 J A 5
6 F B 6
7 G B 7
8 H B 8
9 I B 9
10 J B 10
11 F C 11
12 G C 12
13 H C 13
14 I C 14
15 J C 15
16 F D 16
17 G D 17
18 H D 18
19 I D 19
20 J D 20
21 F E 21
22 G E 22
23 H E 23
24 I E 24
25 J E 25