45

複数のメジャー変数を持っていく場合に、データをロング フォーマットからワイド フォーマットに切り替える最もエレガントで柔軟な方法を見つけるのに苦労しています。

たとえば、これは長い形式の単純なデータ フレームです。 IDは対象、TIMEは時間変数、 およびXはat でY作成された測定値です。IDTIME

> my.df <- data.frame(ID=rep(c("A","B","C"), 5), TIME=rep(1:5, each=3), X=1:15, Y=16:30)
> my.df

   ID TIME  X  Y
1   A    1  1 16
2   B    1  2 17
3   C    1  3 18
4   A    2  4 19
5   B    2  5 20
6   C    2  6 21
7   A    3  7 22
8   B    3  8 23
9   C    3  9 24
10  A    4 10 25
11  B    4 11 26
12  C    4 12 27
13  A    5 13 28
14  B    5 14 29
15  C    5 15 30

TIMEの値をinclude を含む列ヘッダーに変換したいだけの場合、パッケージ (または)からX使用できることがわかっています。cast()reshapedcast()reshape2

> cast(my.df, ID ~ TIME, value="X")
  ID 1 2 3  4  5
1  A 1 4 7 10 13
2  B 2 5 8 11 14
3  C 3 6 9 12 15

しかし、私が実際にやりたいことはY、別のメジャー変数として持ち込んで、列名にメジャー変数名と時間値の両方を反映させることです。

  ID X_1 X_2 X_3  X_4 X_5 Y_1 Y_2 Y_3 Y_4 Y_5
1  A   1   4   7   10  13  16  19  22  25  28
2  B   2   5   8   11  14  17  20  23  26  29
3  C   3   6   9   12  15  18  21  24  27  30

X(FWIW、すべての's の後に最初に 's が続くかどうか、またはそれらが, , ,などYのようにインターリーブされるかどうかはあまり気にしません。)X_1Y_1X_2Y_2

長いデータを 2 回キャストして結果をマージすることでこれに近づけることができますが、列名には多少の作業が必要であり、 and に加えて 3 番目または 4 番目の変数を追加する必要がある場合は微調整する必要がありXますY

merge(
cast(my.df, ID ~ TIME, value="X"),
cast(my.df, ID ~ TIME, value="Y"),
by="ID", suffixes=c("_X","_Y")
)

reshape2and/orの関数のいくつかの組み合わせは、plyr複数のメジャー変数をよりきれいに処理するだけでなく、私の試みよりもエレガントにこれを行うことができるはずです。のようなものcast(my.df, ID ~ TIME, value=c("X","Y"))で、有効ではありません。しかし、私はそれを理解することができませんでした。

4

6 に答える 6

23

必要に応じて複数の変数を処理するにmeltは、キャストする前にデータを取得する必要があります。

library("reshape2")

dcast(melt(my.df, id.vars=c("ID", "TIME")), ID~variable+TIME)

を与える

  ID X_1 X_2 X_3 X_4 X_5 Y_1 Y_2 Y_3 Y_4 Y_5
1  A   1   4   7  10  13  16  19  22  25  28
2  B   2   5   8  11  14  17  20  23  26  29
3  C   3   6   9  12  15  18  21  24  27  30

コメントに基づいて編集:

データフレーム

num.id = 10 
num.time=10 
my.df <- data.frame(ID=rep(LETTERS[1:num.id], num.time), 
                    TIME=rep(1:num.time, each=num.id), 
                    X=1:(num.id*num.time), 
                    Y=(num.id*num.time)+1:(2*length(1:(num.id*num.time))))

ID/のTIME組み合わせは一意の行を示していないため、異なる結果 (すべてのエントリが 2) になります。ID実際には、 /TIMEの組み合わせごとに 2 つの行があります。reshape2変数の可能な組み合わせごとに単一の値を想定し、複数のエントリがある場合は集計関数を適用して単一の変数を作成します。それが警告がある理由です

Aggregation function missing: defaulting to length

その冗長性を壊す別の変数を追加すると、機能するものを得ることができます。

my.df$cycle <- rep(1:2, each=num.id*num.time)
dcast(melt(my.df, id.vars=c("cycle", "ID", "TIME")), cycle+ID~variable+TIME)

これが機能するのは、cycle//が の行を一意に定義するようになったためです。IDtimemy.df

于 2012-05-14T19:17:43.563 に答える
23
   reshape(my.df,
           idvar = "ID",
           timevar = "TIME",
           direction = "wide")

与える

  ID X.1 Y.1 X.2 Y.2 X.3 Y.3 X.4 Y.4 X.5 Y.5
1  A   1  16   4  19   7  22  10  25  13  28
2  B   2  17   5  20   8  23  11  26  14  29
3  C   3  18   6  21   9  24  12  27  15  30
于 2012-05-14T19:18:55.373 に答える
15

を使用すると、複数の列を処理できるdata.table_1.9.5ため、 がなくても実行できます。からインストールできます。meltvalue.varhere

 library(data.table)
 dcast(setDT(my.df), ID~TIME, value.var=c('X', 'Y'))
 #   ID 1_X 2_X 3_X 4_X 5_X 1_Y 2_Y 3_Y 4_Y 5_Y
 #1:  A   1   4   7  10  13  16  19  22  25  28
 #2:  B   2   5   8  11  14  17  20  23  26  29
 #3:  C   3   6   9  12  15  18  21  24  27  30
于 2015-03-19T15:37:32.253 に答える
7

注 - 2019 年 9 月: tidyr内で、gather()+spread()アプローチ (この回答で説明) は多かれ少なかれpivot_wider()アプローチ (「この新しい tidyr 回答」で説明) に置き換えられました。移行に関する現在の情報については、ピボット ビネットを参照してください。


これは、本質的にreshapereshape2を置き換えたtidyrパッケージを使用したソリューションです。これら 2 つのパッケージと同様に、データセットを最初に長くし、次に広くするという戦略です。

library(magrittr); requireNamespace("tidyr"); requireNamespace("dplyr")
my.df %>%
  tidyr::gather(key=variable, value=value, c(X, Y)) %>%   # Make it even longer.
  dplyr::mutate(                                          # Create the spread key.
    time_by_variable   = paste0(variable, "_", TIME)
  ) %>%
  dplyr::select(ID, time_by_variable, value) %>%          # Retain these three.
  tidyr::spread(key=time_by_variable, value=value)        # Spread/widen.

呼び出し後tidyr::gather()の中間データセットは次のとおりです。

ID TIME variable value
1   A    1        X     1
2   B    1        X     2
3   C    1        X     3
...
28  A    5        Y    28
29  B    5        Y    29
30  C    5        Y    30

最終的な結果は次のとおりです。

  ID X_1 X_2 X_3 X_4 X_5 Y_1 Y_2 Y_3 Y_4 Y_5
1  A   1   4   7  10  13  16  19  22  25  28
2  B   2   5   8  11  14  17  20  23  26  29
3  C   3   6   9  12  15  18  21  24  27  30

tidyr::unite()@JWillimanによって提案された代替手段です。これは、パラメーターが true (デフォルト) の場合、上記のdplyr::mutate()andのdplyr::select()組み合わせと機能的に同等です。remove

このタイプの操作に慣れていない場合、tidyr::unite()学習して覚えなければならないもう 1 つの機能であるため、小さな障害になる可能性があります。ただし、(a) より簡潔なコード (つまり、4 行が 1 行に置き換えられる) と (b) 変数名を繰り返す場所が少ない (つまりdplyr::select()、句で変数を繰り返したり変更したりする必要がない) などの利点があります。

my.df %>%
  tidyr::gather(key=variable, value=value, c(X, Y)) %>%           # Make it even longer.
  tidyr::unite("time_by_variable", variable, TIME, remove=T) %>%  # Create the spread key `time_by_variable` while simultaneously dropping `variable` and `TIME`.
  tidyr::spread(key=time_by_variable, value=value)                # Spread/widen.
于 2016-12-13T16:42:05.367 に答える