data.frameをワイドフォーマットからロングフォーマットに変形


164

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()関数の方が処理が少し見栄えが良いので、関数でそれを実行したいと思います。


2
それが問題だった場合は知っているが、リシェイプパッケージの機能が溶融し、キャストしているしないでください(とリキャスト。)
エドゥアルド・レオーニ

1
また、reshapeパッケージはreshape2に置き換えられました。
IRTFM

5
そして、reshape2はtidyrに置き換えられました。
drhagen 2016

回答:


93

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)

153

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

1)あり

パッケージと同じmelt関数を使用できreshape2ます(拡張および改善された実装です)。meltfromにdata.tableは、melt-function from よりも多くのパラメーターがありますreshape2。たとえば、変数列の名前を指定することもできます。

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

2)あり

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

3)あり

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

同じ結果をもたらすいくつかの代替表記:

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

ノート:

  • 引退しました。CRANに保持するために必要な変更のみが行われます。(ソース
  • 除外したい場合はNA値を、あなたは追加することができますna.rm = TRUEmeltだけでなく、gather機能しています。

データのもう1つの問題は、値がRによって(数値の結果として)文字値として読み取られることです,。あなたがそれを修復することができますgsubし、as.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)

偉大な答えは、ちょうど1より小さなリマインダー:以外の変数は入れないidtime、あなたのデータフレーム内をmelt、あなたがこのケースで何をしたいのかわかりませんでした。
Jasonゴール

1
@JasonGoalそれについて詳しく説明してもらえますか?私はあなたのコメントを解釈しているので、それは問題にはなりません。ただ、両方を指定id.varsしてmeasure.vars
Jaap

、その後、私にとっての良いが、知らないことid.varsmeasure.vars最初の選択肢、申し訳ありません混乱のために、その私のせいで指定することができます。
Jasonゴール

この投稿をネクロしてごめんなさい- なぜ 3が機能するのか誰かに説明してくれませんか 私はそれをテストしました、そして、それは機能します、しかし、それが見るとき、dplyrが何をしているのか分かりません-c(var1, var2)...

1
@ReputableMisnomer tidyr-c(var1, var2)、データをワイドフォーマットからロングフォーマットに変換するときに、これらの変数を省略します。
ヤープ

35

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

18

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

1
これにはもっと賛成票が必要です。Tidyverseブログに よると、ブログgatherは廃止されており、pivot_longer現在これを達成するための正しい方法です。
エヴァンロシカ

16

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

注意は、しかし、それはstack動作しませんfactorSを-する場合のみ機能is.vectorであるTRUE、とのドキュメントからis.vector、私たちはそれを見つけます:

is.vectorTRUExが名前以外の属性を持たない指定されたモードのベクトルである場合に返されます。それFALSE以外の場合は戻ります。

年の列の値がs である@Jaapの回答のサンプルデータを使用していますfactor

ここに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

gatherfrom の使用法を示す別の例を次に示しますtidyrgather(ここで行うように)個別に削除するか、必要な年を明示的に含めることで、列を選択できます。

カンマ(およびcheck.names = FALSE設定されていない場合はXが追加される)を処理するために、from を使用したdplyrsのmutate を使用して、テキスト値を数値に戻すことに注意してください。これらはすべての一部なので、一緒にロードできますparse_numberreadrtidyverselibrary(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

4

ここにあります 解決:

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

残念ながら、私はそれを考えていないPIVOTUNPIVOTのために働くだろうR SQLite。より洗練された方法でクエリを作成したい場合は、次の投稿もご覧ください。

sprintfSQLクエリの記述の使用   または    変数の受け渡しsqldf


0

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)

私は現在、そのパッケージを調査しており、非常にアクセスしやすいと感じています。はるかに複雑な変換用に設計されており、逆変換が含まれています。あるチュートリアルもご用意しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.