長い形式からワイド形式にデータを再形成する方法


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          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
@フランク:これははるかに優れたタイトルです。ロングフォームワイドフォームが使用される標準的な用語です。これらの用語で検索しても、他の答えは見つかりません。
smci 2014

もう1つの質問:元に戻すには?
HappyLiang

回答:


257

reshape関数の使用:

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

13
+1 reshapeが付属しているため、外部パッケージに依存する必要はありませんstats。それはより速いことは言うまでもありません!=)
aL3xa、2011

@indra_patil-他の回答の1つに示されているように、おそらくreshape2パッケージを使用します。ユースケースに固有の新しい質問を作成し、理解できない場合は投稿することができます。
2016

5
reshape恐ろしい関数APIの優れた例です。それは役に立たないに非常に近いです。
NoBackingDown 2017年

14
reshapeコメントと同様の引数名は、すべてのことは役に立ちません。ただし、長いものから広いものまで、data =data.frame を提供する必要があることがわかりました。idvar=グループを識別する変数、v.names=ワイド形式で複数の列になるtimevar変数、=追加される値を含む変数v.namesワイドフォーマットでdirection = wide、とsep = "_"。十分にクリア?;)
ブライアンD

3
私はベースRが今でも約2対1の因数で投票
に関して勝つと思います

129

新しい(2014年)tidyrパッケージもして、単純にこれを行うgather()/ spread()ための条件であることmelt/ cast

編集:今、2019年にtidyr v 1.0がリリースおよび設定され、非推奨パスにspreadなりgatherました。代わりにpivot_widerand pivot_longerを使用してください。これ、この回答で説明されています。の簡単な生活を少し垣間見たい場合は、以下をお読みくださいspread/gather

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

githubから、

tidyrreshape2きちんとしたデータフレームワークに付属し、データ分析のための堅実なパイプラインmagrittrと連携して作業するために設計されたの再構成ですdplyr

reshape2再形成よりも少ないのと同じように、tidyrよりも少ないのですreshape2。データを整頓するために特別に設計されたもので、一般的な再形成reshape2や、再形成が行った一般的な集計ではありません。特に、組み込みメソッドはデータフレームに対してのみ機能tidyrし、マージンや集計は提供されません。


5
およびからのこれらの関数の使用について説明しているRクックブックページへのリンクを追加したかっただけです。良い例と説明を提供します。tidyrreshape2
ジェイク

71

これは、reshape()関数、またはreshapeパッケージのmelt()/ cast()関数を使用して行うことができます。2番目のオプションのコード例は次のとおりです。

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 2017年

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 2017

最大限に活用したい場合はどうなりますか?
T.Fung

@ T.Fung私はあなたが何を求めているのか理解できません。新しい質問を開くのが最善でしょうか?
SymbolixAU

opの質問「name」と「numbers」の@SymbolixAUは一意の組み合わせです。そうではなく、ピボット後に各組み合わせの最大値をフェッチしたい場合はどうなりますか?面倒な質問でも問題ありません。ただ考えのための食物。ありがとうございました。
T.Fung

すばらしい答えです。ありがとうございました。複数の列のために、私は「(X、私は、正確な=正確な).subset2でエラー」、およびdata.table dcastの使用を強制することでこの問題を解決することができました:見stackoverflow.com/a/44271092/190791
TimothéeHENRY

26

サンプルのデータフレームを使用して、次のことができます。

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

2
これは良いですが、結果はありませんので、簡単にハンドルにdata.frameとして、あるいはdata.tableかもしれない形式のテーブルであり、両方のパッケージをたくさん持っている
cloudscomputes

18

その他の2つのオプション:

基本パッケージ:

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

develのバージョンでtidyr ‘0.8.3.9000’あり、pivot_widerそしてpivot_longer複数の列に(>長い、それぞれ- - >ワイド、ワイド長い)1から整形を行うために一般化されます。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必要なことを覚えておいてください!timevarそしてv.names一部は簡単です。すべてが明示的に定義されているため、この関数の出力は他の関数よりも予測可能です。


7

ウィン・ベクトルの天才科学者のデータ(作られた人々から非常に強力な新しいパッケージがありますvtreatseplyrreplyr呼ばれる)がcdataこのドキュメントとこのブログの投稿で説明されている「調整データ」の原則を実装しています。データをどのように編成するかに関係なく、「データ座標」のシステムを使用して個々のデータポイントを識別できるはずです。以下は、John Mountによる最近のブログ投稿からの抜粋です。

システム全体は、2つのプリミティブまたは演算子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.