Convert a matrix with dimnames into a long format data.frame

49,020

Solution 1

Use melt from reshape2:

library(reshape2)
#Fake data
x <- matrix(1:12, ncol = 3)
colnames(x) <- letters[1:3]
rownames(x) <- 1:4
x.m <- melt(x)
x.m

   Var1 Var2 value
1     1    a     1
2     2    a     2
3     3    a     3
4     4    a     4
...

Solution 2

The as.table and as.data.frame functions together will do this:

> m <- matrix( sample(1:12), nrow=4 )
> dimnames(m) <- list( One=letters[1:4], Two=LETTERS[1:3] )
> as.data.frame( as.table(m) )
   One Two Freq
1    a   A    7
2    b   A    2
3    c   A    1
4    d   A    5
5    a   B    9
6    b   B    6
7    c   B    8
8    d   B   10
9    a   C   11
10   b   C   12
11   c   C    3
12   d   C    4

Solution 3

Assuming 'm' is your matrix...

data.frame(col = rep(colnames(m), each = nrow(m)), 
           row = rep(rownames(m), ncol(m)), 
           value = as.vector(m))

This executes extremely fast on a large matrix and also shows you a bit about how a matrix is made, how to access things in it, and how to construct your own vectors.

Solution 4

A modification that doesn't require you to know anything about the storage structure, and that easily extends to high dimensional arrays if you use the dimnames, and slice.index functions:

data.frame(row=rownames(m)[as.vector(row(m))],
           col=colnames(m)[as.vector(col(m))],
           value=as.vector(m))
Share:
49,020
Ina
Author by

Ina

@tiedyeina

Updated on February 22, 2021

Comments

  • Ina
    Ina about 3 years

    Hoping there's a simple answer here but I can't find it anywhere.

    I have a numeric matrix with row names and column names:

    #      1    2    3    4
    # a    6    7    8    9
    # b    8    7    5    7
    # c    8    5    4    1
    # d    1    6    3    2
    

    I want to melt the matrix to a long format, with the values in one column and matrix row and column names in one column each. The result could be a data.table or data.frame like this:

    #  col  row  value
    #    1    a      6
    #    1    b      8
    #    1    c      8
    #    1    d      1
    #    2    a      7
    #    2    c      5
    #    2    d      6
        ...
    

    Any tips appreciated.

  • Chase
    Chase almost 12 years
    This is quite interesting, thank you. All three solutions posted are within 2% on my machine for a 1k x 1k matrix.
  • John
    John almost 12 years
    OK +1, that's a new one on me... and that's kind rare.
  • Mox
    Mox over 5 years
    Error in as.data.frame.default(x[[i]], optional = TRUE) : cannot coerce class ‘structure("dpoMatrix", package = "Matrix")’ to a data.frame