programing

세 개의 열 데이터 프레임을 행렬("긴"에서 "넓은" 형식)로 재구성

abcjava 2023. 6. 5. 23:30
반응형

세 개의 열 데이터 프레임을 행렬("긴"에서 "넓은" 형식)로 재구성

나는 있습니다data.frame이렇게 생겼어요.

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

저는 이것을 매트릭스 형태로 만들어서 히트맵에 넣어 플롯을 만들 수 있게 하고 싶습니다.결과는 다음과 같습니다.

    a    b    c
x   1    2    3
y   3    3    2

는 난시다했을 요.cast리쉐이프 패키지에서 이것을 하기 위해 수동 기능을 작성하려고 시도했지만 제대로 할 수 없는 것 같습니다.

이렇게 하는 방법은 여러 가지가 있습니다.이 답변은 빠르게 표준 방법이 되고 있는 것으로 시작하지만, 이 사이트에 흩어져 있는 답변에서 유사한 질문에 이르기까지 이전의 방법과 다양한 다른 방법도 포함합니다.

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))

정돈된 버전 사용:

이를 위한 새로운 멋지고 새로운 방법은pivot_widertidyr 1.0.0데이터 프레임을 반환하는데, 이는 아마도 이 답변의 대부분의 독자가 원하는 것일 것입니다.그러나 열 지도의 경우 이 값을 실제 행렬로 변환해야 합니다.

library(tidyr)
pivot_wider(tmp, names_from = y, values_from = z)
## # A tibble: 2 x 4
## x         a     b     c
## <fct> <dbl> <dbl> <dbl>
## 1 x       1     2     3
## 2 y       3     3     2

이를 위한 오래된 멋지고 새로운 방법은spreadtidyr마찬가지로 데이터 프레임을 반환합니다.

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

모양 바꾸기2 사용:

깔끔한 버전을 향한 첫 번째 단계 중 하나는 reshape2 패키지였습니다.

행렬사방법을 합니다.acast:

library(reshape2)
acast(tmp, x~y, value.var="z")
##   a b c
## x 1 2 3
## y 3 3 2

또는 데이터 프레임을 가져오려면 다음을 사용합니다.dcast여기서: 한 열에 있는 값의 데이터 모양을 변경합니다.

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

플라이어 사용:

에 모양와바을 2정된돈 version 이에사가 .plyrdaply여기에 표시된 기능: 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

행렬 인덱싱 사용:

이것은 오래된 학교이지만 매트릭스 인덱싱에 대한 좋은 시연입니다. 특정 상황에서 정말 유용할 수 있습니다.

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

용사를 합니다.xtabs:

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

희소 행렬 사용:

sparseMatrix의내의 범위 에서.Matrix패키지, 여기에 표시됨: R - 열 이름으로 BIG 테이블을 행렬로 변환

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

용사를 합니다.reshape:

R 을 사용할 수도 .reshape여기서 제안하는 대로: 테이블을 열 이름으로 행렬로 변환합니다. 그러나 추가 열을 제거하고 이름을 올바르게 지정하려면 나중에 약간의 조작을 수행해야 합니다(표시되지 않음).

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

이 질문은 몇 년 전의 것이지만 일부 사람들은 여전히 대안적인 답변에 관심이 있을 수 있습니다.

패키지를 로드하지 않으려면 다음 기능을 사용할 수 있습니다.

#' 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)

}

작동 방식:

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

기본 R,unstack

unstack(df, V3 ~ V2)
#   a b c
# 1 1 2 3
# 2 3 3 2

일반적인 해결책은 아닐 수 있지만 이 경우에는 잘 작동합니다.

데이터.

df<-structure(list(V1 = structure(c(1L, 1L, 1L, 2L, 2L, 2L), .Label = c("x", 
"y"), class = "factor"), V2 = structure(c(1L, 2L, 3L, 1L, 2L, 
3L), .Label = c("a", "b", "c"), class = "factor"), V3 = c(1L, 
2L, 3L, 3L, 3L, 2L)), .Names = c("V1", "V2", "V3"), class = "data.frame", row.names = c(NA, 
-6L))

완전성을 위해, 다음과 같은 것이 있습니다.tapply()주위의 해결책

with(d, tapply(z, list(x, y), sum))
#   a b c
# x 1 2 3
# y 3 3 2

데이터.

d <- structure(list(x = structure(c(1L, 1L, 1L, 2L, 2L, 2L), .Label = c("x", 
"y"), class = "factor"), y = structure(c(1L, 2L, 3L, 1L, 2L, 
3L), .Label = c("a", "b", "c"), class = "factor"), z = c(1, 2, 
3, 3, 3, 2)), class = "data.frame", row.names = c(NA, -6L))

부터tidyr 0.8.3.9000라고 불리는 새로운 기능pivot_wider()소개합니다.기본적으로 이전 버전의 업그레이드된 버전입니다.spread()기능(게다가 이상 활성화되지 않은 기능).피벗 비그넷에서:

이 Vignett에서는 새로운 pivot_longer() 및 pivot_wider() 함수의 사용에 대해 설명합니다.그들의 목표는 gather()와 spread()의 유용성을 향상시키고 다른 패키지에서 발견되는 최첨단 기능을 통합하는 것입니다.

한동안, 스프레드()와 수집()의 설계에 근본적으로 문제가 있는 것이 분명했습니다.많은 사람들은 그 이름들을 직관적으로 생각하지 않고 어떤 방향이 확산되고 어떤 방향이 모여야 하는지 기억하는 것을 어려워합니다.또한 이러한 기능에 대한 인수를 기억하는 것은 의외로 어려워 보입니다. 즉, 저를 포함한 많은 사람들이 매번 설명서를 참조해야 합니다.

사용 방법(@Aaron의 데이터 사용):

pivot_wider(data = tmp, names_from = y, values_from = z)

  x         a     b     c
  <fct> <dbl> <dbl> <dbl>
1 x         1     2     3
2 y         3     3     2

또는 "전체"로 표시됩니다.tidyverse패션:

tmp %>% 
 pivot_wider(names_from = y, values_from = z)

정갈한 역에서 온 조물주 패키지는 이를 수행하는 탁월한 기능을 가지고 있습니다.

변수의 이름은 v1, v2 및 v3이고 데이터 프레임의 이름은 dat라고 가정합니다.

dat %>% 
spread(key = v2,
       value = v3)

타다!

언급URL : https://stackoverflow.com/questions/9617348/reshape-three-column-data-frame-to-matrix-long-to-wide-format

반응형