programing

긴 형식에서 넓은 형식으로 데이터를 재구성하는 방법

goodsources 2023. 6. 30. 22:19
반응형

긴 형식에서 넓은 형식으로 데이터를 재구성하는 방법

다음 데이터 프레임을 다시 정렬하는 데 문제가 있습니다.

set.seed(45)
dat1 <- data.frame(
    name = rep(c("firstName", "secondName"), each=4),
    numbers = rep(1:4, 2),
    value = rnorm(8)
    )

dat1
       name  numbers      value
1  firstName       1  0.3407997
2  firstName       2 -0.7033403
3  firstName       3 -0.3795377
4  firstName       4 -0.7460474
5 secondName       1 -0.8981073
6 secondName       2 -0.3347941
7 secondName       3 -0.5013782
8 secondName       4 -0.1745357

각 고유한 "이름" 변수가 행 이름이 되도록 모양을 변경하고, 행을 따라 "값"을 관측치로, "숫자"를 열 이름으로 지정합니다.이런 식입니다.

     name          1          2          3         4
1  firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
5 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

본적있습다니이▁at다니습▁i'를 살펴봤습니다.melt그리고.cast그리고 몇 가지 다른 것들도 있지만, 아무도 그 일을 할 수 없을 것 같습니다.

용사를 합니다.reshape함수:

reshape(dat1, idvar = "name", timevar = "numbers", direction = "wide")

새로운것년2014 (2014년)tidyr패키지는 또한 이것을 간단하게 합니다.gather()/spread()의 용어가 것melt/cast.

편집: 이제 2019년에 tidyr v 1.0이 시작되어 설정되었습니다.spread그리고.gather하지 않는 경로에서 사되지않경서에로는선, 대신호용▁instead를 합니다.pivot_wider그리고.pivot_longer 답변에 설명된 내용을 확인할 수 있습니다.의 짧은 삶을 잠깐 들여다보고 싶다면 계속 읽어보세요.spread/gather.

library(tidyr)
spread(dat1, key = numbers, value = value)

기트허브에서,

tidyr는 의재입니다성구aming의 입니다.reshape2정돈된 데이터 프레임워크와 함께 제공되며, 함께 작업할 수 있도록 설계되었습니다.magrittr그리고.dplyr데이터 분석을 위한 견고한 파이프라인 구축

럼처입니다.reshape2모양을 바꾸는 것보다 덜 했습니다.tidyr 적은 수작행보다 적게 합니다.reshape2데이터 정리를 위해 특별히 설계되었으며 일반적인 재구성이 아닙니다.reshape2또는 재구성된 일반적인 집계가 수행했습니다.되며, 특히, 내장방식데프만적용며되에레임이터은,▁only▁in,적며되용,tidyr마진이나 집계를 제공하지 않습니다.

은 이것을 을수수다있니습으로 할 수.reshape()함수또사여와 melt()/cast()재구성 패키지의 함수입니다.두 코드는 " "입니다."입니다.

library(reshape)
cast(dat1, name ~ numbers)

는사용을 사용합니다.reshape2

library(reshape2)
dcast(dat1, name ~ numbers)

성능이 문제인 경우 다른 옵션은 다음을 사용하는 것은data.table인 의장확.reshape2의 멜트 & d캐스트 기능

(참조: data.table을 사용한 효율적인 재구성)

library(data.table)

setDT(dat1)
dcast(dat1, name ~ numbers, value.var = "value")

#          name          1          2         3         4
# 1:  firstName  0.1836433 -0.8356286 1.5952808 0.3295078
# 2: secondName -0.8204684  0.4874291 0.7383247 0.5757814

그리고 data.table v1.9.6 기준으로 여러 열에 캐스트할 수 있습니다.

## add an extra column
dat1[, value2 := value * 2]

## cast multiple value columns
dcast(dat1, name ~ numbers, value.var = c("value", "value2"))

#          name    value_1    value_2   value_3   value_4   value2_1   value2_2 value2_3  value2_4
# 1:  firstName  0.1836433 -0.8356286 1.5952808 0.3295078  0.3672866 -1.6712572 3.190562 0.6590155
# 2: secondName -0.8204684  0.4874291 0.7383247 0.5757814 -1.6409368  0.9748581 1.476649 1.1515627

tidyr과함, 있다니께가 .pivot_wider()그리고.pivot_longer()그것들은 각각 긴 -> 넓은 또는 넓은 -> 긴 형태로 재구성하도록 일반화됩니다.OP의 데이터 사용:

단일 열 long -> wide

library(tidyr)

dat1 %>% 
    pivot_wider(names_from = numbers, values_from = value)

# # A tibble: 2 x 5
#   name          `1`    `2`    `3`    `4`
#   <fct>       <dbl>  <dbl>  <dbl>  <dbl>
# 1 firstName   0.341 -0.703 -0.380 -0.746
# 2 secondName -0.898 -0.335 -0.501 -0.175

여러 열 길이 -> 너비

pivot_wider()또한 보다 복잡한 피벗 작업도 수행할 수 있습니다.예를 들어, 여러 열을 동시에 피벗할 수 있습니다.

# create another column for showing the functionality
dat2 <- dat1 %>% 
    dplyr::rename(valA = value) %>%
    dplyr::mutate(valB = valA * 2) 

dat2 %>% 
    pivot_wider(names_from = numbers, values_from = c(valA, valB))

# # A tibble: 2 × 9
#   name       valA_1 valA_2 valA_3 valA_4 valB_1 valB_2 valB_3 valB_4
#   <chr>       <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
#  1 firstName   0.341 -0.703 -0.380 -0.746  0.682 -1.41  -0.759 -1.49 
#  2 secondName -0.898 -0.335 -0.501 -0.175 -1.80  -0.670 -1.00  -0.349

문서에는 훨씬 더 많은 기능이 있습니다.

예제 데이터 프레임을 사용하면 다음과 같은 이점을 얻을 수 있습니다.

xtabs(value ~ name + numbers, data = dat1)

기타 두 가지 옵션:

기본 패키지:

df <- unstack(dat1, form = value ~ numbers)
rownames(df) <- unique(dat1$name)
df

sqldf패키지:

library(sqldf)
sqldf('SELECT name,
      MAX(CASE WHEN numbers = 1 THEN value ELSE NULL END) x1, 
      MAX(CASE WHEN numbers = 2 THEN value ELSE NULL END) x2,
      MAX(CASE WHEN numbers = 3 THEN value ELSE NULL END) x3,
      MAX(CASE WHEN numbers = 4 THEN value ELSE NULL END) x4
      FROM dat1
      GROUP BY name')

R 사용하기 R 준용 R 사aggregate함수:

aggregate(value ~ name, dat1, I)

# name           value.1  value.2  value.3  value.4
#1 firstName      0.4145  -0.4747   0.0659   -0.5024
#2 secondName    -0.8259   0.1669  -0.8962    0.1681

베스이reshape기능이 완벽하게 정상적으로 작동합니다.

df <- data.frame(
  year   = c(rep(2000, 12), rep(2001, 12)),
  month  = rep(1:12, 2),
  values = rnorm(24)
)
df_wide <- reshape(df, idvar="year", timevar="month", v.names="values", direction="wide", sep="_")
df_wide

어디에

  • idvar입니다.
  • timevar 캐스팅할 입니다.
  • v.names는 숫자 있는 입니다.
  • direction long 합니다.
  • 사항인 택사항sep는 사이사구기다니분호입는용 사이에 입니다.timevar 및 클래스 이름v.names됩니다.data.frame.

안되면idvar를 사용하기 전에reshape()함수:

df$id   <- c(rep("year1", 12), rep("year2", 12))
df_wide <- reshape(df, idvar="id", timevar="month", v.names="values", direction="wide", sep="_")
df_wide

.idvar필수 항목입니다!timevar그리고.v.names부분은 쉽습니다.모든 것이 명시적으로 정의되어 있기 때문에 이 함수의 출력은 다른 함수보다 더 예측 가능합니다.

Win-Vector를 만든 )의 이 보낸 vtreat,seplyr그리고.replyr라는 이름의cdata 문서와 블로그 게시물에 설명된 "조정된 데이터" 원칙을 구현합니다.데이터를 어떻게 구성하든 "데이터 좌표" 시스템을 사용하여 개별 데이터 지점을 식별할 수 있어야 합니다.다음은 John Mount의 최근 블로그 게시물에서 발췌한 내용입니다.

전체 시스템은 두 개의 원시 또는 연산자 cdata:moveValuesToRowsD()와 cdata::moveValuesToColumnsD()를 기반으로 합니다.이러한 연산자는 피벗, 피벗, 원핫 인코딩, 전치, 여러 행 및 열 이동 및 기타 많은 변환을 단순한 특수한 경우로 사용합니다.

cdata 프리미티브 측면에서 다양한 연산을 작성하는 것은 쉽습니다.이러한 연산자는 메모리 또는 빅데이터 규모로 작업할 수 있습니다(데이터베이스 및 Apache Spark 사용). 빅데이터의 경우 cdata::moveValuesToRowsN() 및 cdata:::moveValuesToColumnsN() 변형을 사용합니다.변환은 변환의 다이어그램(또는 그림)인 제어 테이블에 의해 제어됩니다.

먼저 제어 테이블을 작성한 다음(자세한 내용은 블로그 게시물 참조) 행에서 열로 데이터 이동을 수행합니다.

library(cdata)
# first build the control table
pivotControlTable <- buildPivotControlTableD(table = dat1, # reference to dataset
                        columnToTakeKeysFrom = 'numbers', # this will become column headers
                        columnToTakeValuesFrom = 'value', # this contains data
                        sep="_")                          # optional for making column names

# perform the move of data to columns
dat_wide <- moveValuesToColumnsD(tallTable =  dat1, # reference to dataset
                    keyColumns = c('name'),         # this(these) column(s) should stay untouched 
                    controlTable = pivotControlTable# control table above
                    ) 
dat_wide

#>         name  numbers_1  numbers_2  numbers_3  numbers_4
#> 1  firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
#> 2 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

훨씬 쉬운 방법!

devtools::install_github("yikeshu0611/onetree") #install onetree package

library(onetree)
widedata=reshape_toWide(data = dat1,id = "name",j = "numbers",value.var.prefix = "value")
widedata

        name     value1     value2     value3     value4
   firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
  secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

와이드에서 롱으로 되돌리려면 와이드만 롱으로 변경하고 오브젝트는 변경하지 마십시오.

reshape_toLong(data = widedata,id = "name",j = "numbers",value.var.prefix = "value")

        name numbers      value
   firstName       1  0.3407997
  secondName       1 -0.8981073
   firstName       2 -0.7033403
  secondName       2 -0.3347941
   firstName       3 -0.3795377
  secondName       3 -0.5013782
   firstName       4 -0.7460474
  secondName       4 -0.1745357

정렬이하지 않은 합니다.as.matrix(dat1)[,1:2]는 대할수있니다습체로 할 수 있습니다.cbind(dat1[,1],dat1[,2])):

> set.seed(45);dat1=data.frame(name=rep(c("firstName","secondName"),each=4),numbers=rep(1:4,2),value=rnorm(8))
> u1=unique(dat1[,1]);u2=unique(dat1[,2])
> m=matrix(nrow=length(u1),ncol=length(u2),dimnames=list(u1,u2))
> m[as.matrix(dat1)[,1:2]]=dat1[,3]
> m
                    1          2          3          4
firstName   0.3407997 -0.7033403 -0.3795377 -0.7460474
secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

누락된 쌍이 있고 정렬이 필요한 경우에는 이 방법이 작동하지 않지만, 쌍이 이미 정렬된 경우에는 이 방법이 조금 더 짧습니다.

> u1=unique(dat1[,1]);u2=unique(dat1[,2])
> dat1=dat1[order(dat1[,1],dat1[,2]),] # not actually needed in this case
> matrix(dat1[,3],length(u1),,T,list(u1,u2))
                    1          2          3          4
firstName   0.3407997 -0.7033403 -0.3795377 -0.7460474
secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

번째as.data.frame경골과 함께 작동하도록 하기 위해):

l2w=function(x,row=1,col=2,val=3,sort=F){
  u1=unique(x[,row])
  u2=unique(x[,col])
  if(sort){u1=sort(u1);u2=sort(u2)}
  out=matrix(nrow=length(u1),ncol=length(u2),dimnames=list(u1,u2))
  out[cbind(x[,row],x[,col])]=x[,val]
  out
}

또는 아래쪽 삼각형 값만 있는 경우 다음 작업을 수행할 수 있습니다.

> euro=as.matrix(eurodist)[1:3,1:3]
> lower=data.frame(V1=rownames(euro)[row(euro)[lower.tri(euro)]],V2=colnames(euro)[col(euro)[lower.tri(euro)]],V3=euro[lower.tri(euro)])
> lower
         V1        V2   V3
1 Barcelona    Athens 3313
2  Brussels    Athens 2963
3  Brussels Barcelona 1318
> n=unique(c(lower[,1],lower[,2]))
> full=rbind(lower,setNames(lower[,c(2,1,3)],names(lower)),data.frame(V1=n,V2=n,V3=0))
> full
         V1        V2   V3
1 Barcelona    Athens 3313
2  Brussels    Athens 2963
3  Brussels Barcelona 1318
4    Athens Barcelona 3313
5    Athens  Brussels 2963
6 Barcelona  Brussels 1318
7    Athens    Athens    0
8 Barcelona Barcelona    0
9  Brussels  Brussels    0
> l2w(full,sort=T)
          Athens Barcelona Brussels
Athens         0      3313     2963
Barcelona   3313         0     1318
Brussels    2963      1318        0

또는 다른 접근 방식이 있습니다.

> rc=as.matrix(lower[-3])
> n=sort(unique(c(rc)))
> m=matrix(0,length(n),length(n),,list(n,n))
> m[rc]=lower[,3]
> m[rc[,2:1]]=lower[,3]
> m
          Athens Barcelona Brussels
Athens         0      3313     2963
Barcelona   3313         0     1318
Brussels    2963      1318        0

또은 기의본또간방다같법습다니음과은한단른다다▁another▁in같니습▁to▁use▁r를 사용하는 것입니다.xtabs의 결과xtabs기본적으로 화려한 클래스 이름을 가진 행렬이지만, 당신은 그것을 정규 행렬처럼 만들 수 있습니다.class(x)=NULL;attr(x,"call")=NULL;dimnames(x)=unname(dimnames(x)):

> x=xtabs(value~name+numbers,dat1);x
            numbers
name                  1          2          3          4
  firstName   0.3407997 -0.7033403 -0.3795377 -0.7460474
  secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357
> str(x)
 'xtabs' num [1:2, 1:4] 0.341 -0.898 -0.703 -0.335 -0.38 ...
 - attr(*, "dimnames")=List of 2
  ..$ name   : chr [1:2] "firstName" "secondName"
  ..$ numbers: chr [1:4] "1" "2" "3" "4"
 - attr(*, "call")= language xtabs(formula = value ~ name + numbers, data = dat1)
> class(x)
[1] "xtabs" "table"
> class(as.matrix(x)) # `as.matrix` has no effect because `x` is already a matrix
[1] "xtabs" "table"
> class(x)=NULL;class(x)
[1] "matrix" "array"
> attr(x,"call")=NULL;dimnames(x)=unname(dimnames(x))
> x # now it looks like a regular matrix
                    1          2          3          4
firstName   0.3407997 -0.7033403 -0.3795377 -0.7460474
secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357
> str(x)
 num [1:2, 1:4] 0.341 -0.898 -0.703 -0.335 -0.38 ...
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:2] "firstName" "secondName"
  ..$ : chr [1:4] "1" "2" "3" "4"

은 통보.as.data.frame(x) 변다환의 결과를 합니다.xtabs형식으로 , 긴형으돌지만아사, 는이수있다피니습할를가자용으로 피할 수 .class(x)=NULL:

> x=xtabs(value~name+numbers,dat1);as.data.frame(x)
        name numbers       Freq
1  firstName       1  0.3407997
2 secondName       1 -0.8981073
3  firstName       2 -0.7033403
4 secondName       2 -0.3347941
5  firstName       3 -0.3795377
6 secondName       3 -0.5013782
7  firstName       4 -0.7460474
8 secondName       4 -0.1745357
> class(x)=NULL;as.data.frame(x)
                    1          2          3          4
firstName   0.3407997 -0.7033403 -0.3795377 -0.7460474
secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

형식으로가 변환됩니다.unlist로 변환합니다.c행렬을 벡터로 변환):

w2l=function(x)data.frame(V1=rownames(x)[row(x)],V2=colnames(x)[col(x)],V3=unname(c(unlist(x))))

세 개의 열 데이터 프레임을 행렬로 재구성("긴"에서 "넓은" 형식)하는 링크된 질문을 통해 여기에 왔습니다.그 질문은 종결되었으므로 저는 여기에 대안을 작성합니다.

저는 세 개의 열을 행렬로 변환하려는 사람에게 유용한 대안을 찾았습니다.디커플R(2.3.2) 패키지를 말하는 것입니다.아래는 해당 사이트에서 복사한 것입니다.


행이 id_cols, 열이 names_from 및 값이 values_from인 테이블 종류를 생성합니다.

사용.

pivot_wider_profile(
data,
id_cols,
names_from,
values_from,
values_fill = NA,
to_matrix = FALSE,
to_sparse = FALSE,
...
)

만 사용dplyr그리고.map.

library(dplyr)
library(purrr)
set.seed(45)
dat1 <- data.frame(
  name = rep(c("firstName", "secondName"), each=4),
  numbers = rep(1:4, 2), value = rnorm(8)
)
longer_to_wider <- function(data, name_from, value_from){
  group <- colnames(data)[!(colnames(data) %in% c(name_from,value_from))]
  data %>% group_by(.data[[group]]) %>%
    summarise( name = list(.data[[name_from]]), 
               value = list(.data[[value_from]])) %>%
    {
      d <- data.frame(
        name = .[[name_from]] %>% unlist() %>% unique()
      )
      e <- map_dfc(.[[group]],function(x){
          y <- data_frame(
            x = data %>% filter(.data[[group]] == x) %>% pull(value_from)
          )
          colnames(y) <- x
          y
      })
      cbind(d,e)
    }
}
longer_to_wider(dat1, "name", "value")
#    name          1          2          3          4
# 1  firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
# 2 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

언급URL : https://stackoverflow.com/questions/5890584/how-to-reshape-data-from-long-to-wide-format

반응형