r - xlab - text ggplot2




將數據幀從寬轉換為長格式 (4)

我有一些麻煩,將我的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()函數來完成它,因為它看起來好一點。


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)

三種替代方案:

1: reshape2

library(reshape2)
long <- melt(wide, id.vars = c("Code", "Country"))

贈送:

   Code     Country variable  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

一些替代符號給出了相同的結果:

# you can also define the id-variables by column number
melt(wide, id.vars = 1:2)

# as an alternative you can also specify the measure-variables
# all other variables will then be used as id-variables
melt(wide, measure.vars = 3:7)
melt(wide, measure.vars = as.character(1950:1954))

2:用data.table

您可以使用與reshape2包(這是一個擴展和改進的實現)相同的melt函數。 來自data.tablemelt也具有更多的參數,即meltreshape2 。 您可以為例如指定變量列的名稱:

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

一些替代符號:

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

3:隨著tidyr

library(tidyr)
long <- wide %>% gather(year, value, -c(Code, Country))

一些替代符號:

wide %>% gather(year, value, -Code, -Country)
wide %>% gather(year, value, -1:-2)
wide %>% gather(year, value, -(1:2))
wide %>% gather(year, value, -1, -2)
wide %>% gather(year, value, 3:7)
wide %>% gather(year, value, `1950`:`1954`)

如果要排除NA值,可以將na.rm = TRUE添加到melt函數以及gather函數。

數據的另一個問題是這些值將被R讀取為字符值(作為數字中的結果)。 你可以使用gsubas.numeric來修復它:

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

或者直接使用data.tabledplyr

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

# tidyr and dplyr
long <- wide %>% gather(year, value, -c(Code,Country)) %>% 
  mutate(value = as.numeric(gsub(",", "", value)))

數據:

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)

由於這個答案是用r-faq標記的,我覺得從基本R: stack分享另一個備選方案會很有用。

但是,請注意,該stack不適用於factor s - 只有在is.vectorTRUE時才起作用,並且從is.vector的文檔中,我們發現:

如果x是指定模式的向量,並且沒有名稱以外的其他屬性,則is.vector返回TRUE 。 否則返回FALSE

我使用@ Jaap答案中的樣本數據,其中年份列中的值為factor s。

這是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

這是另一個例子,展示了來自tidyrgather的使用。 您可以通過單獨刪除它們來選擇要gather的列(正如我在此處所做的那樣),或者通過包括明確指定的年份來gather這些列。

請注意,為了處理逗號(如果check.names = FALSE未設置,則添加X),我還使用dplyr的mutate和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




r-faq