programing

data.frame을 와이드 형식에서 롱 형식으로 재구성

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

data.frame을 와이드 형식에서 롱 형식으로 재구성

변환하는 데 문제가 있습니다.data.frame넓은 테이블에서 긴 테이블까지현재 상태는 다음과 같습니다.

Code Country        1950    1951    1952    1953    1954
AFG  Afghanistan    20,249  21,352  22,532  23,557  24,555
ALB  Albania        8,097   8,986   10,058  11,123  12,246

이제 저는 이것을 변형시키고 싶습니다.data.frame결국data.frame이와 같은 것:

Code Country        Year    Value
AFG  Afghanistan    1950    20,249
AFG  Afghanistan    1951    21,352
AFG  Afghanistan    1952    22,532
AFG  Afghanistan    1953    23,557
AFG  Afghanistan    1954    24,555
ALB  Albania        1950    8,097
ALB  Albania        1951    8,986
ALB  Albania        1952    10,058
ALB  Albania        1953    11,123
ALB  Albania        1954    12,246

이미 살펴보았고 이미 사용을 시도했습니다.melt()그리고reshape()몇몇 사람들이 비슷한 질문에서 제안했던 기능들.하지만, 지금까지 저는 엉망인 결과만 얻었습니다.

가능하다면 저는 그것을 함께 하고 싶습니다.reshape()처리하기에 조금 더 좋아 보이기 때문에 기능.

두 가지 대안 솔루션:

data:

다음 기능을 사용할 수 있습니다.

library(data.table)
long <- melt(setDT(wide), id.vars = c("Code","Country"), variable.name = "year")

이는 다음을 제공합니다.

> long
    Code     Country year  value
 1:  AFG Afghanistan 1950 20,249
 2:  ALB     Albania 1950  8,097
 3:  AFG Afghanistan 1951 21,352
 4:  ALB     Albania 1951  8,986
 5:  AFG Afghanistan 1952 22,532
 6:  ALB     Albania 1952 10,058
 7:  AFG Afghanistan 1953 23,557
 8:  ALB     Albania 1953 11,123
 9:  AFG Afghanistan 1954 24,555
10:  ALB     Albania 1954 12,246

몇 가지 대체 표기법:

melt(setDT(wide), id.vars = 1:2, variable.name = "year")
melt(setDT(wide), measure.vars = 3:7, variable.name = "year")
melt(setDT(wide), measure.vars = as.character(1950:1954), variable.name = "year")

를 사용한 경우:

사용:

library(tidyr)

long <- wide %>% 
  pivot_longer(
    cols = `1950`:`1954`, 
    names_to = "year",
    values_to = "value"
)

참고:

  • names_to그리고.values_to에 결석한."name"그리고."value"각각, 그래서 당신은 이것을 특별히 명확하게 쓸 수 있습니다.wide %>% pivot_longer(`1950`:`1954`).
  • cols인수는 매우 유연한 깔끔한 선택 DSL을 사용하므로, 음의 선택을 사용하여 동일한 열을 선택할 수 있습니다.!c(Code, Country)), 선택 도우미(starts_with("19");matches("^\\d{4}$")), 숫자 인덱스(3:7) 등을 참조하십시오.
  • tidyr::pivot_longer()의 후속 제품입니다.tidyr::gather()그리고.reshape2::melt()더 이상 개발 중이 아닌.

값 변환

데이터의 또 다른 문제는 값이 R에 의해 문자 값으로 읽혀진다는 것입니다.,숫자로)으로 복구할 수 있습니다.gsub그리고.as.numeric모양을 바꾸기 전에:

long$value <- as.numeric(gsub(",", "", long$value))

또는 모양을 바꾸는 동안,data.table또는tidyr:

# data.table
long <- melt(setDT(wide),
             id.vars = c("Code","Country"),
             variable.name = "year")[, value := as.numeric(gsub(",", "", value))]

# tidyr
long <- wide %>%
  pivot_longer(
    cols = `1950`:`1954`, 
    names_to = "year",
    values_to = "value",
    values_transform = ~ as.numeric(gsub(",", "", .x))
  )

데이터:

wide <- read.table(text="Code Country        1950    1951    1952    1953    1954
AFG  Afghanistan    20,249  21,352  22,532  23,557  24,555
ALB  Albania        8,097   8,986   10,058  11,123  12,246", header=TRUE, check.names=FALSE)

reshape()익숙해지는 데 시간이 좀 걸립니다.melt/cast다음은 데이터 프레임을 다음과 같이 부르는 경우를 가정하여 재구성한 솔루션입니다.d:

reshape(d, 
        direction = "long",
        varying = list(names(d)[3:7]),
        v.names = "Value",
        idvar = c("Code", "Country"),
        timevar = "Year",
        times = 1950:1954)

와 함께tidyr_1.0.0또 다른 선택은pivot_longer

library(tidyr)
pivot_longer(df1, -c(Code, Country), values_to = "Value", names_to = "Year")
# A tibble: 10 x 4
#   Code  Country     Year  Value 
#   <fct> <fct>       <chr> <fct> 
# 1 AFG   Afghanistan 1950  20,249
# 2 AFG   Afghanistan 1951  21,352
# 3 AFG   Afghanistan 1952  22,532
# 4 AFG   Afghanistan 1953  23,557
# 5 AFG   Afghanistan 1954  24,555
# 6 ALB   Albania     1950  8,097 
# 7 ALB   Albania     1951  8,986 
# 8 ALB   Albania     1952  10,058
# 9 ALB   Albania     1953  11,123
#10 ALB   Albania     1954  12,246

데이터.

df1 <- structure(list(Code = structure(1:2, .Label = c("AFG", "ALB"), class = "factor"), 
    Country = structure(1:2, .Label = c("Afghanistan", "Albania"
    ), class = "factor"), `1950` = structure(1:2, .Label = c("20,249", 
    "8,097"), class = "factor"), `1951` = structure(1:2, .Label = c("21,352", 
    "8,986"), class = "factor"), `1952` = structure(2:1, .Label = c("10,058", 
    "22,532"), class = "factor"), `1953` = structure(2:1, .Label = c("11,123", 
    "23,557"), class = "factor"), `1954` = structure(2:1, .Label = c("12,246", 
    "24,555"), class = "factor")), class = "data.frame", row.names = c(NA, 
-2L))

모양 바꾸기 패키지 사용:

#data
x <- read.table(textConnection(
"Code Country        1950    1951    1952    1953    1954
AFG  Afghanistan    20,249  21,352  22,532  23,557  24,555
ALB  Albania        8,097   8,986   10,058  11,123  12,246"), header=TRUE)

library(reshape)

x2 <- melt(x, id = c("Code", "Country"), variable_name = "Year")
x2[,"Year"] <- as.numeric(gsub("X", "" , x2[,"Year"]))

이 답변에는 태그가 붙어 있기 때문에, 저는 기본 R의 다른 대안을 공유하는 것이 유용할 것이라고 느꼈습니다.stack.

그러나 참고:stack에서 작동하지 않음factors--이 경우에만 작동합니다.is.vector이라TRUE그리고 다음의 문서에서.is.vector다음과 같은 것을(를)

is.vector돌아온다TRUEx가 이름 이외의 속성이 없는 지정된 모드의 벡터인 경우.돌아옵니다FALSE그렇지않으면.

저는 @Jaap의 답변에서 나온 샘플 데이터를 사용하고 있습니다. 여기서 연도 열의 값은factors.

여기 있습니다.stack접근:

cbind(wide[1:2], stack(lapply(wide[-c(1, 2)], as.character)))
##    Code     Country values  ind
## 1   AFG Afghanistan 20,249 1950
## 2   ALB     Albania  8,097 1950
## 3   AFG Afghanistan 21,352 1951
## 4   ALB     Albania  8,986 1951
## 5   AFG Afghanistan 22,532 1952
## 6   ALB     Albania 10,058 1952
## 7   AFG Afghanistan 23,557 1953
## 8   ALB     Albania 11,123 1953
## 9   AFG Afghanistan 24,555 1954
## 10  ALB     Albania 12,246 1954

다음은 의 사용을 보여주는 또 다른 예입니다.gather부터tidyr다음 열을 선택할 수 있습니다.gather개별적으로 제거하거나(여기서 하는 것처럼) 원하는 연도를 명시적으로 포함하여 제거합니다.

쉼표를 처리하려면 다음과 같이 X를 추가합니다.check.names = FALSE설정되지 않음), 저도 사용 중입니다.dplyr의 변이는 변로하 다으다와 함께 합니다parse_numberreadr텍스트 값을 숫자로 다시 변환합니다. 이들은모일다니입부두의 입니다.tidyverse따라서 함께 로드할 수 있습니다.library(tidyverse)

wide %>%
  gather(Year, Value, -Code, -Country) %>%
  mutate(Year = parse_number(Year)
         , Value = parse_number(Value))

반환:

   Code     Country Year Value
1   AFG Afghanistan 1950 20249
2   ALB     Albania 1950  8097
3   AFG Afghanistan 1951 21352
4   ALB     Albania 1951  8986
5   AFG Afghanistan 1952 22532
6   ALB     Albania 1952 10058
7   AFG Afghanistan 1953 23557
8   ALB     Albania 1953 11123
9   AFG Afghanistan 1954 24555
10  ALB     Albania 1954 12246

다음은 솔루션입니다.

sqldf("Select Code, Country, '1950' As Year, `1950` As Value From wide
        Union All
       Select Code, Country, '1951' As Year, `1951` As Value From wide
        Union All
       Select Code, Country, '1952' As Year, `1952` As Value From wide
        Union All
       Select Code, Country, '1953' As Year, `1953` As Value From wide
        Union All
       Select Code, Country, '1954' As Year, `1954` As Value From wide;")

모든 항목을 입력하지 않고 쿼리를 수행하려면 다음을 사용할 수 있습니다.

G. 그로텐디크가 그것을 실행해 준 것에 감사드립니다.

ValCol <- tail(names(wide), -2)

s <- sprintf("Select Code, Country, '%s' As Year, `%s` As Value from wide", ValCol, ValCol)
mquery <- paste(s, collapse = "\n Union All\n")

cat(mquery) #just to show the query
 #> Select Code, Country, '1950' As Year, `1950` As Value from wide
 #>  Union All
 #> Select Code, Country, '1951' As Year, `1951` As Value from wide
 #>  Union All
 #> Select Code, Country, '1952' As Year, `1952` As Value from wide
 #>  Union All
 #> Select Code, Country, '1953' As Year, `1953` As Value from wide
 #>  Union All
 #> Select Code, Country, '1954' As Year, `1954` As Value from wide

sqldf(mquery)
 #>    Code     Country Year  Value
 #> 1   AFG Afghanistan 1950 20,249
 #> 2   ALB     Albania 1950  8,097
 #> 3   AFG Afghanistan 1951 21,352
 #> 4   ALB     Albania 1951  8,986
 #> 5   AFG Afghanistan 1952 22,532
 #> 6   ALB     Albania 1952 10,058
 #> 7   AFG Afghanistan 1953 23,557
 #> 8   ALB     Albania 1953 11,123
 #> 9   AFG Afghanistan 1954 24,555
 #> 10  ALB     Albania 1954 12,246

유감스럽게도, 저는 그렇게 생각하지 않습니다.PIVOT그리고.UNPIVOT에 효과가 있을 것입니다.R SQLite보다 정교한 방식으로 쿼리를 작성하려면 다음 게시물도 확인할 수 있습니다.

은 또한 있다니습수도를 할 수 .cdata(테이블의 (으)ㄹ 수 있습니다.

# data
wide <- read.table(text="Code Country        1950    1951    1952    1953    1954
AFG  Afghanistan    20,249  21,352  22,532  23,557  24,555
ALB  Albania        8,097   8,986   10,058  11,123  12,246", header=TRUE, check.names=FALSE)

library(cdata)
# build control table
drec <- data.frame(
    Year=as.character(1950:1954),
    Value=as.character(1950:1954),
    stringsAsFactors=FALSE
)
drec <- cdata::rowrecs_to_blocks_spec(drec, recordKeys=c("Code", "Country"))

# apply control table
cdata::layout_by(drec, wide)

저는 현재 그 패키지를 탐색하고 있으며 꽤 접근성이 좋은 것으로 알고 있습니다.훨씬 더 복잡한 변환을 위해 설계되었으며 역변환을 포함합니다.사용 가능한 자습서가 있습니다.

언급URL : https://stackoverflow.com/questions/2185252/reshaping-data-frame-from-wide-to-long-format

반응형