library(tidyr)
library(dplyr)
##
## Attaching package: 'dplyr'
##
## The following objects are masked from 'package:stats':
##
## filter, lag
##
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
reshape2::melt() に相当。複数列にまたがっていた値を、カテゴリ変数と値の列に変換することで、wide-formatな data.frameをlong-formatに変形する。
tidyr::gather(data, key, value, …, na.rm=FALSE, convert=FALSE)
data
%>% 越しに渡す
key, value
出力結果で使う列名 … 動かす列名を指定。コロンによる範囲指定、イナスによる除外指定も可。
convert =FALSE
iris %>% sample_n(10) %>% gather(variable, value, -Species)
#Examples
library(dplyr)
# From http://stackoverflow.com/questions/1181060
stocks <- data.frame(
time = as.Date('2009-01-01') + 0:9,
X = rnorm(10, 0, 1),
Y = rnorm(10, 0, 2),
Z = rnorm(10, 0, 4)
)
gather(stocks, stock, price, -time)
## time stock price
## 1 2009-01-01 X 0.8701680
## 2 2009-01-02 X -0.4715396
## 3 2009-01-03 X 0.7425510
## 4 2009-01-04 X 0.3955095
## 5 2009-01-05 X 1.7399036
## 6 2009-01-06 X 0.2122926
## 7 2009-01-07 X -0.8184215
## 8 2009-01-08 X 0.7429908
## 9 2009-01-09 X 0.1332028
## 10 2009-01-10 X -0.7154715
## 11 2009-01-01 Y 0.0004283
## 12 2009-01-02 Y 1.4190754
## 13 2009-01-03 Y -1.5719177
## 14 2009-01-04 Y 0.1841432
## 15 2009-01-05 Y -3.7587988
## 16 2009-01-06 Y 0.5095759
## 17 2009-01-07 Y 1.1228522
## 18 2009-01-08 Y 2.2184552
## 19 2009-01-09 Y 0.2273048
## 20 2009-01-10 Y 0.5906388
## 21 2009-01-01 Z 3.5581958
## 22 2009-01-02 Z -6.4034427
## 23 2009-01-03 Z 2.7504295
## 24 2009-01-04 Z -3.9741655
## 25 2009-01-05 Z 6.1476901
## 26 2009-01-06 Z 0.7757344
## 27 2009-01-07 Z -8.9307602
## 28 2009-01-08 Z 3.5011421
## 29 2009-01-09 Z -5.2705540
## 30 2009-01-10 Z 0.3586839
stocks %>% gather(stock, price, -time)
## time stock price
## 1 2009-01-01 X 0.8701680
## 2 2009-01-02 X -0.4715396
## 3 2009-01-03 X 0.7425510
## 4 2009-01-04 X 0.3955095
## 5 2009-01-05 X 1.7399036
## 6 2009-01-06 X 0.2122926
## 7 2009-01-07 X -0.8184215
## 8 2009-01-08 X 0.7429908
## 9 2009-01-09 X 0.1332028
## 10 2009-01-10 X -0.7154715
## 11 2009-01-01 Y 0.0004283
## 12 2009-01-02 Y 1.4190754
## 13 2009-01-03 Y -1.5719177
## 14 2009-01-04 Y 0.1841432
## 15 2009-01-05 Y -3.7587988
## 16 2009-01-06 Y 0.5095759
## 17 2009-01-07 Y 1.1228522
## 18 2009-01-08 Y 2.2184552
## 19 2009-01-09 Y 0.2273048
## 20 2009-01-10 Y 0.5906388
## 21 2009-01-01 Z 3.5581958
## 22 2009-01-02 Z -6.4034427
## 23 2009-01-03 Z 2.7504295
## 24 2009-01-04 Z -3.9741655
## 25 2009-01-05 Z 6.1476901
## 26 2009-01-06 Z 0.7757344
## 27 2009-01-07 Z -8.9307602
## 28 2009-01-08 Z 3.5011421
## 29 2009-01-09 Z -5.2705540
## 30 2009-01-10 Z 0.3586839
reshape2::colsplit() に相当。 “Sepal.Length”, “Petal.Width” のようなkey列を複数の列に切り分ける。
tidyr::separate(data, col, into, sep=‘[^[:alnum:]]’, remove=TRUE, convert=FALSE) data
%>% 越しに渡す
col
切り分けたい列の名前
into
切り分けたあとの新しい列名を文字列ベクタで
sep =‘[^[:alnum:]]’
セパレータを正規表現で。デフォルトはあらゆる非アルファベット。
remove =TRUE
切り分ける前の列を取り除くかどうか
convert =FALSE
iris %>% sample_n(10) %>%
gather(variable, value, -Species) %>%
separate(variable, c('part', 'variable'))
## Species part variable value
## 1 setosa Sepal Length 5.0
## 2 versicolor Sepal Length 6.0
## 3 setosa Sepal Length 4.3
## 4 setosa Sepal Length 4.6
## 5 versicolor Sepal Length 6.1
## 6 versicolor Sepal Length 6.8
## 7 virginica Sepal Length 6.3
## 8 versicolor Sepal Length 6.5
## 9 virginica Sepal Length 6.3
## 10 virginica Sepal Length 6.3
## 11 setosa Sepal Width 3.0
## 12 versicolor Sepal Width 3.4
## 13 setosa Sepal Width 3.0
## 14 setosa Sepal Width 3.6
## 15 versicolor Sepal Width 2.8
## 16 versicolor Sepal Width 2.8
## 17 virginica Sepal Width 2.5
## 18 versicolor Sepal Width 2.8
## 19 virginica Sepal Width 2.9
## 20 virginica Sepal Width 2.7
## 21 setosa Petal Length 1.6
## 22 versicolor Petal Length 4.5
## 23 setosa Petal Length 1.1
## 24 setosa Petal Length 1.0
## 25 versicolor Petal Length 4.0
## 26 versicolor Petal Length 4.8
## 27 virginica Petal Length 5.0
## 28 versicolor Petal Length 4.6
## 29 virginica Petal Length 5.6
## 30 virginica Petal Length 4.9
## 31 setosa Petal Width 0.2
## 32 versicolor Petal Width 1.6
## 33 setosa Petal Width 0.1
## 34 setosa Petal Width 0.2
## 35 versicolor Petal Width 1.3
## 36 versicolor Petal Width 1.4
## 37 virginica Petal Width 1.9
## 38 versicolor Petal Width 1.5
## 39 virginica Petal Width 1.8
## 40 virginica Petal Width 1.8
#Examples
library(dplyr)
df <- data.frame(x = c("a.b", "a.d", "b.c"))
df %>% separate(x, c("A", "B"))
## A B
## 1 a b
## 2 a d
## 3 b c
逆をやるのが tidyr::unite(data, col, …, sep=’_’, remove=TRUE) 。
library(dplyr)
unite_(mtcars, "vs_am", c("vs","am")) %>%
head(5)
## mpg cyl disp hp drat wt qsec vs_am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0_1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0_1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1_1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1_0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0_0 3 2
# Separate is the complement of unite
mtcars %>%
unite(vs_am, vs, am) %>%
separate(vs_am, c("vs", "am")) %>%
head(5)
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
tidyr::spread()
reshape2::dcast() に相当。 tidyr::gather() の逆で、long-formatの data.frame をwide-formatに変形する。 IDとなるような列がないと Error: Duplicate identifiers と怒られる。
tidyr::spread(data, key, value, fill=NA, convert=FALSE)
data
%>% 越しに渡す
key
ここに指定したカテゴリ変数が新しい列を作る
value
値が入ってる列
convert =FALSE
#iris %>% sample_n(10) %>% name_rows() %>%
# gather(variable, value, -Species, -.rownames) %>%
# separate(variable, c('part', 'variable')) %>%
# spread(variable, value)
#Examples
library(dplyr)
stocks <- data.frame(
time = as.Date('2009-01-01') + 0:9,
X = rnorm(10, 0, 1),
Y = rnorm(10, 0, 2),
Z = rnorm(10, 0, 4)
)
stocks
## time X Y Z
## 1 2009-01-01 -0.0616 2.7897 3.8792
## 2 2009-01-02 0.5699 -1.3631 -1.8997
## 3 2009-01-03 1.3068 1.5333 0.2136
## 4 2009-01-04 0.6306 2.1342 -2.5556
## 5 2009-01-05 -0.2069 3.5147 2.2942
## 6 2009-01-06 0.1009 0.1357 0.4382
## 7 2009-01-07 -0.7703 -2.5771 0.7573
## 8 2009-01-08 -0.8798 1.6904 3.5528
## 9 2009-01-09 -1.5516 0.9103 -0.1120
## 10 2009-01-10 -1.1114 4.2537 1.0562
stocksm <- stocks %>% gather(stock, price, -time)
stocksm %>% spread(stock, price)
## time X Y Z
## 1 2009-01-01 -0.0616 2.7897 3.8792
## 2 2009-01-02 0.5699 -1.3631 -1.8997
## 3 2009-01-03 1.3068 1.5333 0.2136
## 4 2009-01-04 0.6306 2.1342 -2.5556
## 5 2009-01-05 -0.2069 3.5147 2.2942
## 6 2009-01-06 0.1009 0.1357 0.4382
## 7 2009-01-07 -0.7703 -2.5771 0.7573
## 8 2009-01-08 -0.8798 1.6904 3.5528
## 9 2009-01-09 -1.5516 0.9103 -0.1120
## 10 2009-01-10 -1.1114 4.2537 1.0562
stocksm %>% spread(time, price)##!!!!!
## stock 2009-01-01 2009-01-02 2009-01-03 2009-01-04 2009-01-05 2009-01-06
## 1 X -0.0616 0.5699 1.3068 0.6306 -0.2069 0.1009
## 2 Y 2.7897 -1.3631 1.5333 2.1342 3.5147 0.1357
## 3 Z 3.8792 -1.8997 0.2136 -2.5556 2.2942 0.4382
## 2009-01-07 2009-01-08 2009-01-09 2009-01-10
## 1 -0.7703 -0.8798 -1.5516 -1.111
## 2 -2.5771 1.6904 0.9103 4.254
## 3 0.7573 3.5528 -0.1120 1.056
# Spread and gather are complements
df <- data.frame(x = c("a", "b"), y = c(3, 4), z = c(5, 6))
df
## x y z
## 1 a 3 5
## 2 b 4 6
df %>% spread(x, y) %>% gather(x, y, a:b, na.rm = TRUE)
## z x y
## 1 5 a 3
## 2 6 b 4
似て非なる関数 tidyr::extract(data, col, into, regex, …) もある。
library(dplyr)
df <- data.frame(x = c("a.b", "a.d", "b.c"))
df %>% extract(x, "A")
## A
## 1 a
## 2 a
## 3 b
df %>% extract(x, c("A", "B"),
"([[:alnum:]]+)\\.([[:alnum:]]+)")
## A B
## 1 a b
## 2 a d
## 3 b c
名前の似てる tidyr::extract_numeric(x) は文字列から数字部分を 抜き出して numeric で返す関数。
extract_numeric("$1,200.34")
## [1] 1200
•http://www.jstatsoft.org/v40/i01
•http://www.rdocumentation.org/packages/plyr
•http://cran.r-project.org/web/packages/plyr/index.html
Split, Apply, Combine特定の条件でデータを分割し、それぞれに関数を適用し、再びそれを統合する。 R標準 apply 系の関数よりも感的な使い方ができ、処理も高速。インストールはRの中から:
library(plyr)
## -------------------------------------------------------------------------
## You have loaded plyr after dplyr - this is likely to cause problems.
## If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
## library(plyr); library(dplyr)
## -------------------------------------------------------------------------
##
## Attaching package: 'plyr'
##
## The following objects are masked from 'package:dplyr':
##
## arrange, desc, failwith, id, mutate, summarise, summarize
library(dplyr)
row = input, column = output
array data.frame list nothing
For each slice of an array aaply adply alply a_ply
For each subset of a data.frame daply ddply dlply d_ply
For each element of a list or vector laply ldply llply l_ply
Replicates evaluation raply rdply rlply r_ply
Call a multi-argument function maply mdply mlply m_ply #——————————————————— e.g. 複数ファイルを読み込んでひとつの data.frame にまとめる。 list から data.frame を作るので ldply():
filenames = list.files(pattern=‘\.csv$’) raw_table = ldply(filenames, read.csv)
、グループ毎に数値の列の平均を取る。 data.frame から data.frame を作るので ddply():
ddply(iris, .(Species), numcolwise(mean))
ヘルパー関数 plyr::join(x, y, by=NULL, type=“left”, match=“all”) by で指定した列の値が等しいものを同じ行として、いい感じに cbind()。複数行がマッチした場合のデフォルトの挙動は base::merge() と同じく match=“all” だが match=“first” も 指定できて、そちらは高速らしい。
type=
“inner”: x と y の by がマッチする行のみ
“left”: x の全ての行を保持
“right”: y の全ての行を保持
“full”: “left” の結果の下に、y の残りの行を追加
plyr::join_all(dfs, by=NULL, type=“left”, match=“all”)list に入った複数の data.frame を再帰的に join() する。
plyr::rename(x, replace) data.frame 列名などを 部分的に 変更:
# replace引数には名前付き文字列vectorを与える # 古い名前が名前、新しい名前が値 plyr::rename(.data, c(col_a = “alpha”, col_b = “beta”))
plyr::count(.data, vars=NULL, wt_var=NULL)data.frame のなかで vars 列に関してユニークな行数をカウント。重み付けに使う列を wt_var に指定できる。
plyr::colwise(.fun, .cols=true, …),関数を列ごとに適用する ものに変換する。例えば colwise(mean)(.data) はcolMeans(.data) とほぼ同義。関数で使えない型が含まれている行 結果には NA が入る。
numcolwise(.fun, …) と catcolwisw(.fun, …) はそれぞれ 数値の行、カテゴリ変数の行だけに適用する関数を返してくれる。
plyr::each(func1, func2, …)同じ引数に対して複数の関数を並列 に作用させる。 e.g. each(min, max, mean)(1:10), each(head, tail)(.data, n=10)
plyr::splat(func) ひとつのリストや文字列ベクタでまとめて引数を受け取れるような 関数に変換する。 do.call() は list しか取らないがこちらは 名前付きベクタも可:
params = c(by=2, length=4)
splat(seq)(params)
## [1] 1 3 5 7
do.call(seq, as.list(params))
## [1] 1 3 5 7
doMC 越しに foreach をバックエンドとして使用する:
install.packages("doMC")
library(doMC)
doMC::registerDoMC(parallel::detectCores())
.data = plyr::ldply(lst, func, .parallel=TRUE)
dplyr — データフレームに特化した版 plyr
•https://github.com/hadley/dplyr
•http://cran.r-project.org/web/packages/dplyr/vignettes/introduction.html
plyr::ddply() 的な処理をもっと柔軟に、見やすく書ける:
# plyr
plyr::ddply(plyr::mutate(subset(iris, Species!='setosa',
select=-c(Sepal.Width, Sepal.Length)),
petal_area=Petal.Length*Petal.Width*0.5), .(Species), numcolwise(mean))
## Species Petal.Length Petal.Width petal_area
## 1 versicolor 4.260 1.326 2.860
## 2 virginica 5.552 2.026 5.648
# dplyr
iris %>%
dplyr::filter(Species!='setosa') %>%
dplyr::select(-starts_with('Sepal')) %>%
dplyr::mutate(petal_area=Petal.Length*Petal.Width*0.5) %>%
dplyr::group_by(Species) %>%
dplyr::summarise_each(funs(mean))
## Petal.Length Petal.Width petal_area
## 1 4.906 1.676 4.254
# どちらも結果は
%>% 左の値を右の関数に第一引数として渡す。 .data %>% func(arg1, arg2) は func(.data, arg1, arg2) になる。 処理する順に書けるので、次々と関数を適用していくときでも読み やすい。
Note: 現状 dplyr は magrittr パッケージのものを採用しているが、 pipeR パッケージの %>>% のほうが柔軟で高速。
dplyr::group_by(.data, col1, col2, …, add=FALSE) グループごとに区切って次の処理に渡す。 e.g. summarize(), tally(), do() など
dplyr::rowwise(.data)行 ごとに区切って次の処理に渡す
dplyr::do(.data, …)グループごとに処理する。 {} 内に長い処理を書いてもいいし、関数に渡してもよい。グループごとに切りだされた部分は . で参照できる。出力が data.frame じゃないと
Error: Results are not data frames at positions: 1 のように怒られるが、do(dummy=func(.)) のように名前付きにすると data.frame に入らないような型でも大丈夫になる。
library(dplyr)
dplyr::filter(.data, ...)
列の値で行を絞る
base::subset() と似たようなもの:
iris %>% dplyr::filter(Sepal.Length<6, Sepal.Width>4)
dplyr::slice(.data, ...)
行数を指定して行を絞る。 `[`(i,) の代わりに:
iris %>% dplyr::slice(2:4)
dplyr::select(.data, ...)
使う列を絞る。複数指定, 範囲指定、負の指定、パターン指定が可能
starts_with(x, ignore.case=FALSE)
ends_width(x, ignore.case=FALSE)
contains(x, ignore.case=FALSE)
matches(x, ignore.case=FALSE)
num_range('x', 1:5, width=2)
iris %>% dplyr::select(-(Sepal.Width:Petal.Length)) %>%
head(5)
iris %>% dplyr::select(ends_with('Length')) %>%
head(5)
library(dplyr)
data(iris)
iris %>% dplyr::filter(Sepal.Length<6, Sepal.Width>4)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.7 4.4 1.5 0.4 setosa
## 2 5.2 4.1 1.5 0.1 setosa
## 3 5.5 4.2 1.4 0.2 setosa
iris %>% dplyr::select(-(Sepal.Width:Petal.Length)) %>%
head(5)
## Sepal.Length Petal.Width Species
## 1 5.1 0.2 setosa
## 2 4.9 0.2 setosa
## 3 4.7 0.2 setosa
## 4 4.6 0.2 setosa
## 5 5.0 0.2 setosa
iris %>% dplyr::select(ends_with('Length')) %>%
head(5)
## Sepal.Length Petal.Length
## 1 5.1 1.4
## 2 4.9 1.4
## 3 4.7 1.3
## 4 4.6 1.5
## 5 5.0 1.4
dplyr::rename(.data, ...)列の改名:
iris %>% rename(sp=Species) %>% head(5)
dplyr::mutate(.data, ...)
既存の列を使って新しい列を作る。
base::transform() とほとんど同じだがそれよりも高速で高機能:
modify existing column
iris %>% dplyr::mutate(Sepal.Length = log(Sepal.Length)) %>%
head(5)
create new column
iris %>% dplyr::mutate(ln_sepal_length = log(Sepal.Length)) %>%
head(5)
dplyr::transmute(.data, ...)
指定した列以外を保持しない版の mutate()dplyr::distinct(.data, ...)
指定した列に関してユニークな行のみ返す:
iris %>% distinct(Species)
dplyr::arrange(.data, column1, column2, ...)
指定した列の昇順で data.frame の行を並べ替える。
arrange(desc(column)) で降順になる。
order() を使うよりもタイピングの繰り返しが少ないし直感的:
.data[with(.data, order(col_a, col_b)), ]
is equivalent to
.data %>% dplyr::arrange(col_a, col_b)
dplyr::summarise(.data, ...)
列に対する関数をグループごとに適用して1行にしたものをrbind() してまとめる:
iris %>% group_by(Species) %>%
summarise(minpl=min(Petal.Length), maxsw=max(Sepal.Width))
dplyr::summarise_each(.data, funs, ...),
dplyr::mutate_each(.data, funs, ...)
複数の列に複数の関数を適用する(dplyr::funs() と共に):
iris %>% group_by(Species) %>%
summarise_each(funs(min, mean, max), ends_with("Width"))
library(dplyr)
# modify existing column
iris %>% dplyr::mutate(Sepal.Length = log(Sepal.Length)) %>%
head(5)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 1.629 3.5 1.4 0.2 setosa
## 2 1.589 3.0 1.4 0.2 setosa
## 3 1.548 3.2 1.3 0.2 setosa
## 4 1.526 3.1 1.5 0.2 setosa
## 5 1.609 3.6 1.4 0.2 setosa
# create new column
iris %>% dplyr::mutate(ln_sepal_length = log(Sepal.Length)) %>% head(5)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5.0 3.6 1.4 0.2 setosa
## ln_sepal_length
## 1 1.629
## 2 1.589
## 3 1.548
## 4 1.526
## 5 1.609
iris %>% group_by(Species) %>%
summarise(minpl=min(Petal.Length), maxsw=max(Sepal.Width))
## minpl maxsw
## 1 1 4.4
#dplyr::summarise_each(.data, funs, ...),
#dplyr::mutate_each(.data, funs, ...)
iris %>% group_by(Species) %>%
summarise_each(funs(min, mean, max), ends_with("Width"))
## Sepal.Width_min Petal.Width_min Sepal.Width_mean Petal.Width_mean
## 1 2 0.1 3.057 1.199
## Sepal.Width_max Petal.Width_max
## 1 4.4 2.5
dplyr::data_frame(…) より便利でバグの混入しにくい方法で data.frame を作る。
•勝手に型変換しない (stringsAsFactors=FALSE) •勝手に列名を変えない
•長さ1の変数以外はリサイクルしない
•引数の評価がlazyに行われるので前の列を利用して後の列を作ったりできる
•tbl_df クラスを付加
•ただし matrix からの直接変換はサポートしなそう https://github.com/hadley/dplyr/issues/324
dplyr::***_join(x, y, by=NULL, copy=FALSE)
by で指定した列がマッチするように行を合わせて cbind()
inner_join(): x と y の by がマッチする行のみ
left_join(): x の全ての行を保持。y に複数マッチする行があったらすべて保持。
semi_join(): x の全ての行を保持。y に複数マッチする行があっても元の x の行だけ保持。
anti_join(): y にマッチしない x の行のみ。
列名が異なる場合は by を名前付きベクタにすればよい
dplyr::rbind_all(list_of_tables),
dplyr::rbind_list(table1, table2, …)data.frame を効率よく
rbind()dplyr::ntile(x, n)数値ベクトル x を順位によって n 個のクラスに均等分け
dplyr::n_distinct(x)高速で簡潔な length(unique(x))
dplyr::last(x, order_by=NULL, default=default_missing(x)) 最後の要素にアクセス。 x[length(x)] と書かなくて済む!
dplyr::glimpse(.data, width=getOption(‘width’))データの 中身をざっと見る。 print() とか str() のようなもの。
dplyr::lead(x n=1, default=NA, order_by=NULL),
dplyr::lag(…) x の中身を n だけずらして default で埋める。 lead() は前に 、lag() は後ろにずらす:
lag(seq_len(5), 2)
dplyr::top_n(.data, n, wt=NULL).
data %>% arrange(wt) %>% head(n) を一撃で、グループごとに 。 dplyr::tally(x, wt, sort=FALSE) summarise(x, n=n()) のショートカット。 wt にカラムを指定して重み付けすることもできる。
dplyr::count(x, …, wt=NULL, sort=FALSE) group_by(…) %>% tally() のショートカット。