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


263

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

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"변수가 행 이름이되도록 행 이름을 바꾸고 싶습니다. "values"는 해당 행을 따라 관측 값이되고 "numbers"는 colnames입니다. 이런 종류의 :

     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

내가 검토 한 meltcast및 몇 가지 다른 것들, 그러나 아무도이 일을 할 것 없습니다.



4
@ Frank : 이것은 훨씬 더 나은 제목입니다. 긴 형식넓은 형식 이 사용되는 표준 용어입니다. 다른 용어는 해당 용어를 검색하여 찾을 수 없습니다.
smci

질문 하나 더 : 다시 바꾸는 방법?
HappyLiang

답변:


255

reshape기능 사용하기 :

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

13
+1이며 reshape와 함께 제공 되므로 외부 패키지에 의존 할 필요가 없습니다 stats. 더 빠르다는 것은 말할 것도 없습니다! =)
aL3xa 0:07에

@indra_patil-다른 답변 중 하나에 표시된 것처럼 reshape2 패키지를 사용할 것입니다. 유스 케이스에 특정한 새 질문을 작성하고 파악할 수없는 경우 게시 할 수 있습니다.
체이스

5
reshape끔찍한 함수 API의 뛰어난 예입니다. 그것은 쓸모없는 것에 매우 가깝습니다.
NoBackingDown

14
reshape의 의견과 유사한 인수 이름이 모두 도움이되지 않습니다. 그러나 오랫동안 광범위하게 data =data.frame, idvar= 그룹을 식별 v.names하는 변수, timevar= 넓은 형식의 여러 열이 될 변수 , 추가 될 값을 포함하는 변수를 제공해야한다는 것을 알았습니다. 에 v.names다양한 형식으로, direction = wide그리고 sep = "_". 충분히 클리어? ;)
Brian D

3
나는 기본 R 여전히 약 2 대 1의 비율로 투표 현명한 승리 말할 것
vonjd

129

새로운 (2014 년) tidyr패키지도 함께 간단하게이 작업을 수행 gather()/ spread()에 대한 조항 인 melt/을 cast.

편집 : 자, 2019 년, tidyr V 1.0이 출시 설정 한 spreadgather더 이상 사용되지 경로 대신 선호 pivot_wider하고 pivot_longer당신이 설명 찾을 수있는 이 답변에 . 의 짧은 인생을 간략하게 살펴보고 싶다면 계속 읽으십시오 spread/gather.

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

에서 github에 ,

tidyr의 프레이밍입니다 reshape2깔끔한 데이터 프레임 워크를 동반하도록 설계, 작업 손으로 손에로 magrittrdplyr데이터 분석을위한 견고한 파이프 라인을 구축하는.

그냥 같은 reshape2모양 변경보다 덜했다, tidyr이하 않습니다 reshape2. 일반적인 형태 변경 reshape2이나 형태 변경이 이루어진 일반적인 집계가 아닌 데이터 정리를 위해 특별히 설계되었습니다 . 특히 기본 제공 방법은 데이터 프레임에서만 작동하며 tidyr여백이나 집계를 제공하지 않습니다.


5
그냥 링크를 추가하고 싶었 R 요리 책 에서 이러한 기능의 사용에 대해 설명 페이지 tidyrreshape2. 좋은 예와 설명을 제공합니다.
Jake

71

reshape()기능 또는 형태 변경 패키지 의 melt()/ cast()기능을 사용 하여이 작업을 수행 할 수 있습니다 . 두 번째 옵션의 경우 예제 코드는

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

또는 사용 reshape2

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

2
명확한 "값"열이 없으면 그냥 사용 cast하거나 dcast제대로 작동하지 않을 수도 있습니다. 시도 dat <- data.frame(id=c(1,1,2,2),blah=c(8,4,7,6),index=c(1,2,1,2)); dcast(dat, id ~ index); cast(dat, id ~ index)하고 당신은 당신이 기대하는 것을 얻지 못할 것입니다. 당신은 명시 적으로주의 할 필요가 value/value.var- cast(dat, id ~ index, value="blah")그리고 dcast(dat, id ~ index, value.var="blah")예를 들어.
thelatemail

45

성능이 문제가 될 경우 또 다른 옵션은 data.table의 확장 reshape2기능을 사용하는 것입니다.

( 참조 : data.tables를 사용하여 효율적인 재 형성 )

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

5
data.table접근이 최고입니다! 매우 효율적입니다 ... name30-40 열의 조합이 있을 때 차이를 볼 수 있습니다!
joel.wilson

최대치를 원한다면 어떻게해야합니까?
T.Fung

@ T.Fung 나는 당신이 무엇을 요구하는지 이해하지 못합니다. 새로운 질문을 여는 것이 가장 좋을까요?
SymbolixAU

op의 질문 'name'과 'numbers'의 @SymbolixAU는 고유 한 조합입니다. 그렇지 않은 경우 피벗 후 각 조합의 최대 값을 가져 오려면 어떻게합니까? 너무 어리석은 질문이라면 문제가되지 않습니다. 생각을위한 음식. 감사합니다.
T.Fung

좋은 대답입니다. 감사합니다. 여러 열의 경우 ".subset2 (x, i, 정확한 = 정확한) 오류"가 발생하여 data.table dcast를 사용하여이 문제를 해결할 수 있습니다. stackoverflow.com/a/44271092/190791
Timothée HENRY

26

예제 데이터 프레임을 사용하여 다음을 수행 할 수 있습니다.

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

2
이 사람이 좋은,하지만 결과는 data.frame 또는 data.table로 핸들 그리 쉽지 않을 수도 포맷 테이블이다, 두 패키지의 많음이있다
cloudscomputes

18

다른 두 가지 옵션 :

기본 패키지 :

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

1
숫자를 하드 코딩하는 대신 다음과 같이 쿼리를 설정할 수 있습니다.ValCol <- unique(dat1$numbers);s <- sprintf("MAX(CASE WHEN numbers = %s THEN value ELSE NULL END) `%s`,", ValCol, ValCol);mquerym <- gsub('.{1}$','',paste(s, collapse = "\n"));mquery <- paste("SELECT name,", mquerym, "FROM dat1", "GROUP BY name", sep = "\n");sqldf(mquery)
M--

13

기본 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

11

(STABLE)의 버전 tidyr ‘0.8.3.9000’이 있고, pivot_wider그리고 pivot_longer다수의 컬럼 (> 긴 각각 - -> 폭 넓은 긴) 하나의 재 형성을 수행하는 일반화된다. OP의 데이터 사용

-단일 열-> 넓음

library(dplyr)
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

-> 기능을 보여주기 위해 다른 열을 만들었습니다.

dat1 %>% 
    mutate(value2 = value * 2) %>% 
    pivot_wider(names_from = numbers, values_from = c("value", "value2"))
# A tibble: 2 x 9
#  name       value_1 value_2 value_3 value_4 value2_1 value2_2 value2_3 value2_4
#  <fct>        <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

8

기본 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 넓거나 긴 형식을 지정합니다
  • 선택적 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필요 하다는 것을 기억하십시오 ! timevarv.names부분은 간단합니다. 이 함수의 출력은 모든 것이 명시 적으로 정의되어 있기 때문에 다른 것보다 더 예측 가능합니다.


7

윈 - 벡터에서 천재 데이터 과학자 (만든 사람에서 매우 강력한 새로운 패키지있다 vtreat, seplyrreplyr이라가) 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

1

훨씬 쉬운 방법!

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.