持ちたいメジャー変数が複数ある場合、データをロングフォーマットからワイドフォーマットに切り替える最もエレガントで柔軟な方法を理解するのに苦労しています。
たとえば、次は長い形式の単純なデータフレームです。 ID
は主語、TIME
は時間変数、X
とY
はID
のTIME
:
_> 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
の値をインクルードX
を含む列ヘッダーに変換したいだけの場合は、reshape
パッケージからcast()
を使用できることを知っています(またはdcast()
from _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
_
(FWIW、すべてのX
の後にY
が続いているかどうか、または_X_1
_、_Y_1
_、_X_2
_、_Y_2
_など)
cast-長いデータを2回実行して結果をマージすることでこれに近づくことができますが、列名にはいくつかの作業が必要であり、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")
)
_
_reshape2
_およびplyr
の関数のいくつかの組み合わせは、私の試みよりもエレガントにこれを実行でき、複数のメジャー変数をよりきれいに処理できるようです。 cast(my.df, ID ~ TIME, value=c("X","Y"))
のようなものは無効です。しかし、私はそれを理解することができませんでした。
必要に応じて複数の変数を処理するには、キャストする前に、データを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
/ID
/time
がmy.df
の行を一意に定義するようになったため、これは機能します。
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
data.table_1.9.5
を使用すると、複数のvalue.var
列を処理できるため、melt
なしでこれを実行できます。 here
からインストールできます
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
注-2019年9月: tidyr 内で、gather()
+ spread()
アプローチ(この回答で説明)は、多かれ少なかれpivot_wider()
アプローチに置き換えられました( ` この新しいtidyr回答 で説明されています)。遷移に関する現在の情報については、 ピボットビネット を参照してください。
tidyr パッケージを使用したソリューションは、基本的に reshape と reshape2 を置き換えたものです。これらの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によって提案された代替手段です。これは、remove
パラメーターがtrueの場合、機能的に上記の dplyr::mutate()
および dplyr::select()
の組み合わせと同等です(これがデフォルトです)。
このタイプの操作に慣れていない場合、tidyr::unite()
は、覚えておく必要があるもう1つの関数であるため、小さな障害になる可能性があります。ただし、利点は、(a)より簡潔なコード(ie、4行が1つに置き換えられる)、および(b)変数名を繰り返す場所が少ない( ie、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.
_
pivot_wider()
関数は tidyr の第2世代アプローチです(tidyr 1.0.0でリリース)。
_library(magrittr); requireNamespace("tidyr");
my.df %>%
tidyr::pivot_wider(
names_from = c(TIME), # Can accommodate more variables, if needed.
values_from = c(X, Y)
)
_
結果:
_# A tibble: 3 x 11
ID X_1 X_2 X_3 X_4 X_5 Y_1 Y_2 Y_3 Y_4 Y_5
<fct> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
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アプローチ よりも望ましい(これは gather()
と spread()
の組み合わせを使用します=)。
その他の機能は ピボットビネット で説明されています。この例は、目的の仕様が_id_cols
_および_names_sep
_のデフォルトと一致するため、特に簡潔です。