tidyr 0.4が出たと風の噂で聞いたので触ってみました。
ネストしたdata.frame
nest()andunnest()have been overhauled to support a useful way of structuring data frames: the nested data frame. In a grouped data frame, you have one row per observation, and additional metadata define the groups. In a nested data frame, you have one row per group, and the individual observations are stored in a column that is a list of data frames. This is a useful structure when you have lists of other objects (like models) with one element per group.
この変更むずいです。。when you have lists of other objects (like models) with one element per groupというのの具体例が思いつかないので、この辺の解説はRStudioのブログ記事を待ちます。とりあえずここでは、どういう動作をするかだけ追ってみました。
nest()
nest()now produces a single list of data frames
以前は各列ごとにネストしていたのが、
iris %>% nest(-Species) #> Source: local data frame [3 x 5] #> Groups: <by row> #> #> Species Sepal.Length Sepal.Width Petal.Length Petal.Width #> (fctr) (chr) (chr) (chr) (chr) #> 1 setosa <dbl[50]> <dbl[50]> <dbl[50]> <dbl[50]> #> 2 versicolor <dbl[50]> <dbl[50]> <dbl[50]> <dbl[50]> #> 3 virginica <dbl[50]> <dbl[50]> <dbl[50]> <dbl[50]>
0.4からは、data.frameとしてネストされます。
iris %>% nest(-Species) #> Species #> 1 setosa #> 2 versicolor #> 3 virginica #> data #> 1 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.8, 4.8, 4.3, 5.8, 5.7, 5.4, 5.1, 5.7, 5.1, 5.4, 5.1, 4.6, 5.1, 4.8, 5.0, 5.0, 5.2, 5.2, 4.7, 4.8, 5.4, 5.2, 5.5, 4.9, 5.0, 5.5, 4.9, 4.4, 5.1, 5.0, 4.5, 4.4, 5.0, 5.1, 4.8, 5.1, 4.6, 5.3, 5.0, 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.4, 3.0, 3.0, 4.0, 4.4, 3.9, 3.5, 3.8, 3.8, 3.4, 3.7, 3.6, 3.3, 3.4, 3.0, 3.4, 3.5, 3.4, 3.2, 3.1, 3.4, 4.1, 4.2, 3.1, 3.2, 3.5, 3.6, 3.0, 3.4, 3.5, 2.3, 3.2, 3.5, 3.8, 3.0, 3.8, 3.2, 3.7, 3.3, 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.6, 1.4, 1.1, 1.2, 1.5, 1.3, 1.4, 1.7, 1.5, 1.7, 1.5, 1.0, 1.7, 1.9, 1.6, 1.6, 1.5, 1.4, 1.6, 1.6, 1.5, 1.5, 1.4, 1.5, 1.2, 1.3, 1.4, 1.3, 1.5, 1.3, 1.3, 1.3, 1.6, 1.9, 1.4, 1.6, 1.4, 1.5, 1.4, 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.2, 0.5, 0.2, 0.2, 0.4, 0.2, 0.2, 0.2, 0.2, 0.4, 0.1, 0.2, 0.2, 0.2, 0.2, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2, 0.6, 0.4, 0.3, 0.2, 0.2, 0.2, 0.2 #> 2 7.0, 6.4, 6.9, 5.5, 6.5, 5.7, 6.3, 4.9, 6.6, 5.2, 5.0, 5.9, 6.0, 6.1, 5.6, 6.7, 5.6, 5.8, 6.2, 5.6, 5.9, 6.1, 6.3, 6.1, 6.4, 6.6, 6.8, 6.7, 6.0, 5.7, 5.5, 5.5, 5.8, 6.0, 5.4, 6.0, 6.7, 6.3, 5.6, 5.5, 5.5, 6.1, 5.8, 5.0, 5.6, 5.7, 5.7, 6.2, 5.1, 5.7, 3.2, 3.2, 3.1, 2.3, 2.8, 2.8, 3.3, 2.4, 2.9, 2.7, 2.0, 3.0, 2.2, 2.9, 2.9, 3.1, 3.0, 2.7, 2.2, 2.5, 3.2, 2.8, 2.5, 2.8, 2.9, 3.0, 2.8, 3.0, 2.9, 2.6, 2.4, 2.4, 2.7, 2.7, 3.0, 3.4, 3.1, 2.3, 3.0, 2.5, 2.6, 3.0, 2.6, 2.3, 2.7, 3.0, 2.9, 2.9, 2.5, 2.8, 4.7, 4.5, 4.9, 4.0, 4.6, 4.5, 4.7, 3.3, 4.6, 3.9, 3.5, 4.2, 4.0, 4.7, 3.6, 4.4, 4.5, 4.1, 4.5, 3.9, 4.8, 4.0, 4.9, 4.7, 4.3, 4.4, 4.8, 5.0, 4.5, 3.5, 3.8, 3.7, 3.9, 5.1, 4.5, 4.5, 4.7, 4.4, 4.1, 4.0, 4.4, 4.6, 4.0, 3.3, 4.2, 4.2, 4.2, 4.3, 3.0, 4.1, 1.4, 1.5, 1.5, 1.3, 1.5, 1.3, 1.6, 1.0, 1.3, 1.4, 1.0, 1.5, 1.0, 1.4, 1.3, 1.4, 1.5, 1.0, 1.5, 1.1, 1.8, 1.3, 1.5, 1.2, 1.3, 1.4, 1.4, 1.7, 1.5, 1.0, 1.1, 1.0, 1.2, 1.6, 1.5, 1.6, 1.5, 1.3, 1.3, 1.3, 1.2, 1.4, 1.2, 1.0, 1.3, 1.2, 1.3, 1.3, 1.1, 1.3 #> 3 6.3, 5.8, 7.1, 6.3, 6.5, 7.6, 4.9, 7.3, 6.7, 7.2, 6.5, 6.4, 6.8, 5.7, 5.8, 6.4, 6.5, 7.7, 7.7, 6.0, 6.9, 5.6, 7.7, 6.3, 6.7, 7.2, 6.2, 6.1, 6.4, 7.2, 7.4, 7.9, 6.4, 6.3, 6.1, 7.7, 6.3, 6.4, 6.0, 6.9, 6.7, 6.9, 5.8, 6.8, 6.7, 6.7, 6.3, 6.5, 6.2, 5.9, 3.3, 2.7, 3.0, 2.9, 3.0, 3.0, 2.5, 2.9, 2.5, 3.6, 3.2, 2.7, 3.0, 2.5, 2.8, 3.2, 3.0, 3.8, 2.6, 2.2, 3.2, 2.8, 2.8, 2.7, 3.3, 3.2, 2.8, 3.0, 2.8, 3.0, 2.8, 3.8, 2.8, 2.8, 2.6, 3.0, 3.4, 3.1, 3.0, 3.1, 3.1, 3.1, 2.7, 3.2, 3.3, 3.0, 2.5, 3.0, 3.4, 3.0, 6.0, 5.1, 5.9, 5.6, 5.8, 6.6, 4.5, 6.3, 5.8, 6.1, 5.1, 5.3, 5.5, 5.0, 5.1, 5.3, 5.5, 6.7, 6.9, 5.0, 5.7, 4.9, 6.7, 4.9, 5.7, 6.0, 4.8, 4.9, 5.6, 5.8, 6.1, 6.4, 5.6, 5.1, 5.6, 6.1, 5.6, 5.5, 4.8, 5.4, 5.6, 5.1, 5.1, 5.9, 5.7, 5.2, 5.0, 5.2, 5.4, 5.1, 2.5, 1.9, 2.1, 1.8, 2.2, 2.1, 1.7, 1.8, 1.8, 2.5, 2.0, 1.9, 2.1, 2.0, 2.4, 2.3, 1.8, 2.2, 2.3, 1.5, 2.3, 2.0, 2.0, 1.8, 2.1, 1.8, 1.8, 1.8, 2.1, 1.6, 1.9, 2.0, 2.2, 1.5, 1.4, 2.3, 2.4, 1.8, 1.8, 2.1, 2.4, 2.3, 1.9, 2.3, 2.5, 2.3, 1.9, 2.0, 2.3, 1.8
表示の問題でベクトルみたいに見えますが、ちゃんとdata.frameのlistがdataという列に入っています(この列名は.keyという引数で変えられます)
iris %>% nest(-Species) %>% str(max.level = 2L) 'data.frame': 3 obs. of 2 variables: $ Species: Factor w/ 3 levels "setosa","versicolor",..: 1 2 3 $ data :List of 3 ..$ :'data.frame': 50 obs. of 4 variables: ..$ :'data.frame': 50 obs. of 4 variables: ..$ :'data.frame': 50 obs. of 4 variables:
あと、grouped_df(dplyr::group_by()されたdata.frame)に対してnest()すると、キーにしている変数以外をネストしてくれます。ドキュメントに載っている例は以下です。
library(gapminder) gapminder %>% group_by(country, continent) %>% nest() #> Source: local data frame [142 x 3] #> #> country continent data #> (fctr) (fctr) (list) #> 1 Afghanistan Asia <tbl_df [12,4]> #> 2 Albania Europe <tbl_df [12,4]> #> 3 Algeria Africa <tbl_df [12,4]> #> 4 Angola Africa <tbl_df [12,4]> #> 5 Argentina Americas <tbl_df [12,4]> #> .. ... ... ...
↑と↓は同じです。
gapminder %>% nest(-country, -continent)
unnest()
unnest()gains a.dropargument which controls what happens to other list columns.
unnest()は、二つ以上ネストされている値があったとき、指定しなかった列は削除するというのがデフォルトの挙動です。.drop = FALSEを指定すると、指定しなかったネストした列もそのまま残してくれます。
ドキュメントの例だとこんな感じ。
df <- data_frame( a = list(c("a", "b"), "c"), b = list(1:2, 3), c = c(11, 22) ) # bを指定しないとbは消える df %>% unnest(a) #> Source: local data frame [3 x 2] #> #> c a #> (dbl) (chr) #> 1 11 a #> 2 11 b #> 3 22 c # .drop = FALSEだとbが残る df %>% unnest(a, .drop = FALSE) #> df %>% unnest(a, .drop = FALSE) #> Source: local data frame [3 x 3] #> #> b c a #> (list) (dbl) (chr) #> 1 <int[2]> 11 a #> 2 <int[2]> 11 b #> 3 <dbl[1]> 22 c
ちなみに、当たり前といえば当たり前ですが、変数の組み合わせの仕方が変わるので、以下ふたつは同じではないことに注意しましょう。
df %>% unnest(a, b) df %>% unnest(a, .drop = FALSE) %>% unnest(b)
直積集合
expand()
expand()once again allows you to evaluate arbitrary expressions likefull_seq(year).
expand()の中で任意の表現を使えるようになりました。そのかわり、↓のnesting()の意味でc()を使うことはできなくなりました。
nesting()、crossing()
nesting()andcrossing()allow you to create nested and crossed data frames from individual vectors.crossing()is similar tobase::expand.grid()
nesting()は単純に各引数の組み合わせを返します。crossing()の方はexpand.grid()と同じく直積集合を返します。expand()との違いは何かというと、引数に取るのがdata.frameではなくベクトルなことです。
nesting(x = 1:3, y = 3:1) #> Source: local data frame [3 x 2] #> #> x y #> (int) (int) #> 1 1 3 #> 2 2 2 #> 3 3 1 # expand(data.frame(x = 1:3, y = 3:1), x, y) と同じ crossing(x = 1:3, y = 3:1) #> Source: local data frame [9 x 2] #> #> x y #> (int) (int) #> 1 1 1 #> 2 1 2 #> 3 1 3 #> 4 2 1 #> 5 2 2 #> 6 2 3 #> 7 3 1 #> 8 3 2 #> 9 3 3
nesting()はexpand()の中で使うと便利です。たとえば、xとyは実際のデータに含まれる組み合わせだけにしたいときはnesting(x, y)を指定します。
d <- data.frame(x = 1:3, y = 3:1, z = c(1, 2, 1)) expand(d, x, y , z) #> Source: local data frame [18 x 3] #> #> x y z #> (int) (int) (dbl) #> 1 1 1 1 #> 2 1 1 2 #> 3 1 2 1 #> 4 1 2 2 #> 5 1 3 1 #> 6 1 3 2 #> 7 2 1 1 #> 8 2 1 2 #> 9 2 2 1 #> 10 2 2 2 #> ... expand(d, nesting(x, y) , z) #> Source: local data frame [6 x 3] #> #> x y z #> (int) (int) (dbl) #> 1 1 3 1 #> 2 1 3 2 #> 3 2 2 1 #> 4 2 2 2 #> 5 3 1 1 #> 6 3 1 2
seq_full()
full_seq(x, period)creates the full sequence of values frommin(x)tomax(x)everyperiodvalues.
xの最大値と最小値の間のシーケンスをつくってくれます。
full_seq(c(1, 2, 4, 5, 10), period = 1) #> [1] 1 2 3 4 5 6 7 8 9 10
バグフィックス・その他の変更
(大きな変更はなさそうなので省略)
感想
他は大した変化はないとはいえ、nest()/unnest()はまたがっつり変えてきましたね…。
Issuesを覗いてみると、purrrでよく見るタンタンの人がちらほら出てきます。どうやら、purrrをいろいろいじくっているうちに閃いたとかいう雰囲気を感じます。dplyrにもこんな感じでbreaking changeが出たりしそうな…。