web-dev-qa-db-ja.com

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()関数を使用して処理したいと思います。

131
mropa

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

3つの代替ソリューション:

1:With 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関数を使用できます。 melt from data.tableには、reshape2からのmelt- functionよりも多くのパラメーターもあります。たとえば、変数列の名前を指定することもできます。

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

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値を除外する場合、melt関数とgather関数にna.rm = TRUEを追加できます。


データに関する別の問題は、Rが値を文字値として読み取ることです(数字の,の結果)。 gsubas.numericで修復できます:

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

または、data.tableまたはdplyrで直接:

# 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)
119
Jaap

reshapeパッケージを使用:

#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"]))
33
Shane

この回答には r-faq のタグが付けられているため、ベースRから別の代替案を共有すると便利だと感じました:stack

ただし、stackfactorsでは機能しないことに注意してください。is.vectorTRUEである場合にのみ機能し、is.vectorのドキュメントから、それ:

is.vectorは、xが属性を持たない指定されたモードのベクトルである場合、TRUEを返します名前以外。それ以外の場合は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
11

gatherからのtidyrの使用を示す別の例です。 gatherの列を選択するには、個別に削除するか(ここで行うように)、必要な年を明示的に含めます。

コンマ(およびcheck.names = FALSEが設定されていない場合はXを追加)を処理するために、dplyrのmutateをparse_numberからreadrに変換して、テキスト値を元に戻すことに注意してください数字に。これらはすべて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
10
Mark Peterson

sqldf のソリューションは次のとおりです。

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。Grothendieck を実装してくれてありがとう。

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

残念ながら、PIVOTUNPIVOTRSQLiteに対して機能するとは思わない。クエリをより洗練された方法で作成する場合は、次の投稿もご覧ください。

sprintfを使用してSQLクエリを作成するOr- 変数をsqldfに渡す

2
M--