2012-03-08 8 views
96

Tôi có một số data.frame trông giống như thế này.Định hình lại ba khung dữ liệu cột thành ma trận (định dạng "dài" thành "rộng")

x a 1 
x b 2 
x c 3 
y a 3 
y b 3 
y c 2 

Tôi muốn điều này ở dạng ma trận để tôi có thể nạp bản đồ để tạo bản đồ. Kết quả sẽ giống như thế:

a b c 
x 1 2 3 
y 3 3 2 

Tôi đã thử cast từ gói Reshape và tôi đã cố gắng viết một chức năng hướng dẫn để thực hiện điều này nhưng tôi dường như không thể làm cho nó đúng.

+1

@AnandaMahto cũng có một câu trả lời tuyệt vời về điều này ở đây: http : //stackoverflow.com/a/14515736/210673 – Aaron

Trả lời

146

Có nhiều cách để thực hiện việc này. Câu trả lời này bắt đầu với những cách yêu thích của tôi, nhưng cũng thu thập nhiều cách khác nhau từ câu trả lời cho các câu hỏi tương tự nằm rải rác xung quanh trang web này.

tmp <- data.frame(x=gl(2,3, labels=letters[24:25]), 
        y=gl(3,1,6, labels=letters[1:3]), 
        z=c(1,2,3,3,3,2)) 

Sử dụng reshape2:

library(reshape2) 
acast(tmp, x~y, value.var="z") 

Sử dụng ma trận lập chỉ mục:

with(tmp, { 
    out <- matrix(nrow=nlevels(x), ncol=nlevels(y), 
       dimnames=list(levels(x), levels(y))) 
    out[cbind(x, y)] <- z 
    out 
}) 

Sử dụng xtabs:

xtabs(z~x+y, data=tmp) 

Bạn cũng có thể sử dụng reshape, theo đề nghị của mình e: Convert table into matrix by column names, mặc dù bạn phải thực hiện một thao tác nhỏ sau đó để xóa một cột phụ và lấy tên đúng (không được hiển thị).

> reshape(tmp, idvar="x", timevar="y", direction="wide") 
    x z.a z.b z.c 
1 x 1 2 3 
4 y 3 3 2 

Ngoài ra còn có sparseMatrix trong gói Matrix, như đã thấy ở đây: R - convert BIG table into matrix by column names

> with(tmp, sparseMatrix(i = as.numeric(x), j=as.numeric(y), x=z, 
+      dimnames=list(levels(x), levels(y)))) 
2 x 3 sparse Matrix of class "dgCMatrix" 
    a b c 
x 1 2 3 
y 3 3 2 

Các daply chức năng từ thư viện plyr cũng có thể được sử dụng, như ở đây: https://stackoverflow.com/a/7020101/210673

> library(plyr) 
> daply(tmp, .(x, y), function(x) x$z) 
    y 
x a b c 
    x 1 2 3 
    y 3 3 2 

dcast từ reshape2 cũng hoạt động, như ở đây: Reshape data for values in one column, nhưng bạn nhận được một data.frame với một cột cho giá trị x.

> dcast(tmp, x~y, value.var="z") 
    x a b c 
1 x 1 2 3 
2 y 3 3 2 

Tương tự, spread từ "tidyr" cũng sẽ làm việc cho một sự chuyển hóa như:

library(tidyr) 
spread(tmp, y, z) 
# x a b c 
# 1 x 1 2 3 
# 2 y 3 3 2 
+2

'acast (tmp, x ~ y, value.var =" z ")' sẽ cung cấp cho một đầu ra ma trận, với 'x' là row.names – mnel

2

Câu hỏi đặt ra là số tuổi nhưng có lẽ một số người vẫn còn quan tâm đến câu trả lời khác.

Nếu bạn không muốn tải bất kỳ gói, bạn có thể sử dụng chức năng này:

#' Converts three columns of a data.frame into a matrix -- e.g. to plot 
#' the data via image() later on. Two of the columns form the row and 
#' col dimensions of the matrix. The third column provides values for 
#' the matrix. 
#' 
#' @param data data.frame: input data 
#' @param rowtitle string: row-dimension; name of the column in data, which distinct values should be used as row names in the output matrix 
#' @param coltitle string: col-dimension; name of the column in data, which distinct values should be used as column names in the output matrix 
#' @param datatitle string: name of the column in data, which values should be filled into the output matrix 
#' @param rowdecreasing logical: should the row names be in ascending (FALSE) or in descending (TRUE) order? 
#' @param coldecreasing logical: should the col names be in ascending (FALSE) or in descending (TRUE) order? 
#' @param default_value numeric: default value of matrix entries if no value exists in data.frame for the entries 
#' @return matrix: matrix containing values of data[[datatitle]] with rownames data[[rowtitle]] and colnames data[coltitle] 
#' @author Daniel Neumann 
#' @date 2017-08-29 
data.frame2matrix = function(data, rowtitle, coltitle, datatitle, 
          rowdecreasing = FALSE, coldecreasing = FALSE, 
          default_value = NA) { 

    # check, whether titles exist as columns names in the data.frame data 
    if ((!(rowtitle%in%names(data))) 
     || (!(coltitle%in%names(data))) 
     || (!(datatitle%in%names(data)))) { 
    stop('data.frame2matrix: bad row-, col-, or datatitle.') 
    } 

    # get number of rows in data 
    ndata = dim(data)[1] 

    # extract rownames and colnames for the matrix from the data.frame 
    rownames = sort(unique(data[[rowtitle]]), decreasing = rowdecreasing) 
    nrows = length(rownames) 
    colnames = sort(unique(data[[coltitle]]), decreasing = coldecreasing) 
    ncols = length(colnames) 

    # initialize the matrix 
    out_matrix = matrix(NA, 
         nrow = nrows, ncol = ncols, 
         dimnames=list(rownames, colnames)) 

    # iterate rows of data 
    for (i1 in 1:ndata) { 
    # get matrix-row and matrix-column indices for the current data-row 
    iR = which(rownames==data[[rowtitle]][i1]) 
    iC = which(colnames==data[[coltitle]][i1]) 

    # throw an error if the matrix entry (iR,iC) is already filled. 
    if (!is.na(out_matrix[iR, iC])) stop('data.frame2matrix: double entry in data.frame') 
    out_matrix[iR, iC] = data[[datatitle]][i1] 
    } 

    # set empty matrix entries to the default value 
    out_matrix[is.na(out_matrix)] = default_value 

    # return matrix 
    return(out_matrix) 

} 

Cách hoạt động:

myData = as.data.frame(list('dim1'=c('x', 'x', 'x', 'y','y','y'), 
          'dim2'=c('a','b','c','a','b','c'), 
          'values'=c(1,2,3,3,3,2))) 

myMatrix = data.frame2matrix(myData, 'dim1', 'dim2', 'values') 

myMatrix 
> a b c 
> x 1 2 3 
> y 3 3 2