次のデータフレームを並べ替えることができません。
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"変数が、その行に沿った観測値としての "values"と、colnamesとしての "numbers"とを含むような形になるように変形したいのです。このようなもの:
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
私はmelt
とcast
と他のいくつかを調べましたが、その仕事をしているようには見えません。
reshape
関数を使う:
reshape(dat1, idvar = "name", timevar = "numbers", direction = "wide")
新しい(2014年)tidyr
パッケージもこれを簡単に行います。gather()
/spread()
はmelt
/cast
の用語です。
library(tidyr)
spread(dat1, key = numbers, value = value)
github から、
tidyr
は、きちんとしたデータフレームワークに付随し、magrittr
およびdplyr
と連携してデータ分析のための強固なパイプラインを構築するように設計されたreshape2
の改装です。
reshape2
がreshapeよりも少なかったように、tidyr
はreshape2
よりも少なかった。これはデータを整理するために特別に設計されたもので、reshape2
が行う一般的な再整形、または再整形が行った一般的な集約ではありません。特に、組み込みメソッドはデータフレームに対してのみ機能し、tidyr
はマージンや集約を提供しません。
これはreshape()
関数、またはreshapeパッケージのmelt()
/cast()
関数で行うことができます。 2番目のオプションの場合、コード例は
library(reshape)
cast(dat1, name ~ numbers)
あるいはreshape2
を使う
library(reshape2)
dcast(dat1, name ~ numbers)
パフォーマンスが問題になる場合のもう1つの選択肢は、data.table
のmelt&dcast関数の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
サンプルのデータフレームを使用して、
xtabs(value ~ name + numbers, data = dat1)
他の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')
ベース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
Win-Vector(vtreat
、seplyr
およびreplyr
を作成した人々)の天才データ科学者による非常に強力な新しいパッケージがcdata
です。それは この文書 そしてまたこの ブログ記事 に記述されている「調整されたデータ」の原則を実行します。考え方は、データをどのように編成するかにかかわらず、「データ座標」のシステムを使用して個々のデータポイントを識別することが可能であるべきであるということです。これは、John Mountによる最近のブログ投稿からの抜粋です。
システム全体は、cdata :: moveValuesToRowsD()およびcdata :: moveValuesToColumnsD()の2つのプリミティブまたは演算子に基づいています。これらの演算子には、単純な特殊なケースとして、ピボット、アンピボット、ワンホットエンコード、転置、複数の行と列の移動、およびその他の多くの変換があります。
Cdataプリミティブに関しては、さまざまな操作を簡単に書くことができます。これらの演算子はメモリ内でもビッグデータスケールでも(データベースとApache Sparkを使って;ビッグデータのためにはcdata :: moveValuesToRowsN()とcdata :: moveValuesToColumnsN()を使うことができます)。変換は、それ自体が変換の図(またはピクチャ)である制御テーブルによって制御されます。
最初にコントロールテーブルを作成し(詳細については blog post を参照)、次に行から列へのデータの移動を実行します。
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
基本の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
の部分は簡単です。すべてが明示的に定義されているので、この関数の出力は他のものよりも予測可能です。
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
はるかに簡単な方法!
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