1 今回の内容

1.1 Rのポイントはデータハンドリング

  • 変数(列)の選択
  • 変数(列)を新規で作成、更新
  • レコード(行)を条件により抽出、並べ替え
  • データを集計(要約)
  • データをグループ化
  • 複数のデータセットを結合
  • wide型(横型)とlong型(縦型)を変換
  • 列の結合と分離

1.2 みなさんどうやってます?

2 具体例_1

2.1 具体例_1: ほしいもの

このような結果がほしいとします:

## `summarise_each()` is deprecated.
## Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead.
## To map `funs` over all variables, use `summarise_all()`
Species Sepal.Length Sepal.Width
versicolor 5.936 2.770
virginica 6.588 2.974
setosa 5.006 3.428

2.2 具体例_1: コード

iris %>% 
  dplyr::select(starts_with("sepal"),Species) %>% 
  dplyr::group_by(Species) %>% 
  dplyr::summarize_each(funs(mean)) %>% 
  dplyr::arrange(Sepal.Width) 
## `summarise_each()` is deprecated.
## Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead.
## To map `funs` over all variables, use `summarise_all()`
## # A tibble: 3 x 3
##      Species Sepal.Length Sepal.Width
##       <fctr>        <dbl>       <dbl>
## 1 versicolor        5.936       2.770
## 2  virginica        6.588       2.974
## 3     setosa        5.006       3.428

2.3 具体例_1: 内容

iris %>% 
  dplyr::select(starts_with("sepal"),Species) %>% 
  dplyr::group_by(Species) %>% 
  dplyr::summarize_each(funs(mean)) %>% 
  dplyr::arrange(Sepal.Width) 
irisデータを…
  "sepal"で始まる変数と"Species"を取り出して…
  "Species"の値でグループ化して…
  各列に対して"平均"で要約して…
  "Sepal.Width"の昇順でソート

3 具体例_2

3.1 具体例_2: ほしいもの

このような結果がほしいとします:

var_name value
Sepal.Length 5.1
Sepal.Length 4.9
Sepal.Length 4.7
Sepal.Length 4.6
Sepal.Length 5.0
Sepal.Length 5.4

3.2 具体例_2: コード

iris %>% 
  dplyr::select(-Species) %>% 
  tidyr::gather(key = var_name, value = value) %>% 
  head
## # A tibble: 6 x 2
##       var_name value
## *        <chr> <dbl>
## 1 Sepal.Length   5.1
## 2 Sepal.Length   4.9
## 3 Sepal.Length   4.7
## 4 Sepal.Length   4.6
## 5 Sepal.Length   5.0
## 6 Sepal.Length   5.4

3.3 具体例_2: 内容

iris %>% 
  dplyr::select(-Species) %>% 
  tidyr::gather(key = var_name, value = value) %>% 
  head
irisデータを…
  "Species"以外の変数を取り出して…
  4つの変数を縦型のデータに整形して…
  上6つのデータを表示

4 補足: %>% について

4.1 %>% はpipe演算子

  • “%>%”は、前のコマンドでのoutputを、次のコマンドの第一引数に放り込む
  • dplyrを読み込むと利用可能
# 使わない書き方
df <- subset(iris, Species == "setosa")
df2 <- subset(df, select = c(Sepal.Length, Sepal.Width))
head(df2, 2)
## # A tibble: 2 x 2
##   Sepal.Length Sepal.Width
## *        <dbl>       <dbl>
## 1          5.1         3.5
## 2          4.9         3.0
# 使った書き方
(df <- subset(iris, Species == "setosa") %>% 
  subset(select = c(Sepal.Length, Sepal.Width)) %>% 
  head(2))
## # A tibble: 2 x 2
##   Sepal.Length Sepal.Width
## *        <dbl>       <dbl>
## 1          5.1         3.5
## 2          4.9         3.0

4.2 ポイント

4.2.1 メリット

  • 流れるようにコードがかける
  • 引き渡しのためにわざわざオブジェクトを作る必要がない
    混乱やメモリを抑制できる
  • RStudioにショートカットがある(Ctrl/Cmd + Shift + M)
  • dplyrやtidyrとの相性が非常にいい

4.2.2 デメリット

  • 第一引数に投入されるため、使用できる関数に制限あり
    明示的に放り込む方法はあるが割愛
  • (人によっては)掴みづらい

5 前準備

5.1 パッケージインストール

必要なパッケージをインストール&読み込み

install.packages("dplyr")
install.packages("tidyr")
library(dplyr)
library(tidyr)
  • CRANにあります
  • 今回は以下のバージョンで実行しています
    • 詳細なsessioninfoはトップページをご覧ください
installed.packages() %>%
  as.data.frame() %>%
  select_("Package"," Version") %>%
  filter(Package %in% c("dplyr", "tidyr"))
## # A tibble: 2 x 2
##   Package Version
##    <fctr>  <fctr>
## 1   dplyr   0.7.2
## 2   tidyr   0.7.1

6 変数(列)の選択

6.1 dplyr::select

df <- dplyr::select(iris, c(Sepal.Width,Species))
head(df, 3)
## # A tibble: 3 x 2
##   Sepal.Width Species
## *       <dbl>  <fctr>
## 1         3.5  setosa
## 2         3.0  setosa
## 3         3.2  setosa
  • dplyr::select(データフレーム, 列の指定, …)
  • 列の指定方法は、基本subsetと同様
  • 列の指定については、さらに特別な関数が利用可能

6.2 列選択用関数: starts_with()

df <- dplyr::select(iris, starts_with("sepal"))
head(df, 3)
## # A tibble: 3 x 2
##   Sepal.Length Sepal.Width
## *        <dbl>       <dbl>
## 1          5.1         3.5
## 2          4.9         3.0
## 3          4.7         3.2
  • start_with(x, ignore.case = TRUE)
  • 前方一致で変数を検索してもってくる
  • なおignore.case = FALSEにすると、大文字と小文字を区別してくれる

6.3 列選択用関数: ends_with()

df <- dplyr::select(iris, ends_with("width"))
head(df, 3)
## # A tibble: 3 x 2
##   Sepal.Width Petal.Width
## *       <dbl>       <dbl>
## 1         3.5         0.2
## 2         3.0         0.2
## 3         3.2         0.2
  • ends_with(x, ignore.case = TRUE)
  • 後方一致で変数を検索して持ってくる

6.4 列選択用関数: contains()

df <- dplyr::select(iris, contains("pe"))
head(df, 3)
## # A tibble: 3 x 3
##   Petal.Length Petal.Width Species
## *        <dbl>       <dbl>  <fctr>
## 1          1.4         0.2  setosa
## 2          1.4         0.2  setosa
## 3          1.3         0.2  setosa
  • contains(x, ignore.case = TRUE)
  • 部分一致で変数を検索して持ってくる

6.5 列選択用関数: matches()

df <- dplyr::select(iris, matches(".t."))
head(df, 3)
## # A tibble: 3 x 4
##   Sepal.Length Sepal.Width Petal.Length Petal.Width
## *        <dbl>       <dbl>        <dbl>       <dbl>
## 1          5.1         3.5          1.4         0.2
## 2          4.9         3.0          1.4         0.2
## 3          4.7         3.2          1.3         0.2
  • matches(x, ignore.case = TRUE)
  • 正規表現で指定してマッチする変数を持ってくる

6.6 列選択用関数: num_range()

df <- as.data.frame(matrix(1:30, nrow = 3, ncol = 10))
colnames(df) <- c(paste0("beer", 1:5), paste0("sake0", 1:5))
ls(df)
##  [1] "beer1"  "beer2"  "beer3"  "beer4"  "beer5"  "sake01" "sake02"
##  [8] "sake03" "sake04" "sake05"
dplyr::select(df, num_range("beer", 1:3, 1))
## # A tibble: 3 x 3
##   beer1 beer2 beer3
##   <int> <int> <int>
## 1     1     4     7
## 2     2     5     8
## 3     3     6     9
dplyr::select(df, num_range("sake", 2:4, 2))
## # A tibble: 3 x 3
##   sake02 sake03 sake04
##    <int>  <int>  <int>
## 1     19     22     25
## 2     20     23     26
## 3     21     24     27
  • num_range(“文字列”, 対象の数値, 桁数)
  • “beer1からbeer3まで”といった指定方法。桁数があるのがGood!

6.7 列選択用関数: one_of()

vname <- c("Petal.Length", "Sepal.Width")
df <- dplyr::select(iris, one_of(vname))
head(df, 3)
## # A tibble: 3 x 2
##   Petal.Length Sepal.Width
## *        <dbl>       <dbl>
## 1          1.4         3.5
## 2          1.4         3.0
## 3          1.3         3.2
  • 変数名を文字列ベクトルでまとめて渡す時に使用。
  • これで挟み込まずにそのままベクトルを指定してもエラーが出る

6.8 列選択用関数: everything()

df <- as.data.frame(matrix(1:15, nrow = 3, ncol = 5))
colnames(df) <- c("touyama", "hanazawa", "komatsu", "asumi", "sakura")
dplyr::select(df, everything())
## # A tibble: 3 x 5
##   touyama hanazawa komatsu asumi sakura
##     <int>    <int>   <int> <int>  <int>
## 1       1        4       7    10     13
## 2       2        5       8    11     14
## 3       3        6       9    12     15
dplyr::select(df, hanazawa, touyama, everything())
## # A tibble: 3 x 5
##   hanazawa touyama komatsu asumi sakura
##      <int>   <int>   <int> <int>  <int>
## 1        4       1       7    10     13
## 2        5       2       8    11     14
## 3        6       3       9    12     15
  • 全部持ってくる

こういう使い方も。

head(dplyr::select(iris, kosaki=starts_with("Petal"), everything()))
## # A tibble: 6 x 5
##   kosaki1 kosaki2 Sepal.Length Sepal.Width Species
## *   <dbl>   <dbl>        <dbl>       <dbl>  <fctr>
## 1     1.4     0.2          5.1         3.5  setosa
## 2     1.4     0.2          4.9         3.0  setosa
## 3     1.3     0.2          4.7         3.2  setosa
## 4     1.5     0.2          4.6         3.1  setosa
## 5     1.4     0.2          5.0         3.6  setosa
## 6     1.7     0.4          5.4         3.9  setosa

7 変数(列)を新規で作成、更新

7.1 dplyr::mutate()

df <- dplyr::mutate(iris, beer=Sepal.Width*2)
head(df, 2)
## # A tibble: 2 x 6
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species  beer
## *        <dbl>       <dbl>        <dbl>       <dbl>  <fctr> <dbl>
## 1          5.1         3.5          1.4         0.2  setosa     7
## 2          4.9         3.0          1.4         0.2  setosa     6
df <- dplyr::mutate(df, beer=Sepal.Width*3)
head(df, 2)
## # A tibble: 2 x 6
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species  beer
## *        <dbl>       <dbl>        <dbl>       <dbl>  <fctr> <dbl>
## 1          5.1         3.5          1.4         0.2  setosa  10.5
## 2          4.9         3.0          1.4         0.2  setosa   9.0
  • dplyr::mutate(データフレーム、変数名=処理内容)
  • データフレームに新たに列を追加します
  • 変数名に既存の変数を指定すると上書きします

7.2 dplyr::mutate_each()

df <- dplyr::mutate_each(iris, funs(. * 2), -Species)
## `mutate_each()` is deprecated.
## Use `mutate_all()`, `mutate_at()` or `mutate_if()` instead.
## To map `funs` over a selection of variables, use `mutate_at()`
kable(head(df,2))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
10.2 7 2.8 0.4 setosa
9.8 6 2.8 0.4 setosa
  • dplyr::mutate_each(データフレーム、関数, …)
  • 複数の列に、関数の内容を一気にあてます
  • …のところで変数を指定します
    • select()と同様に指定可能

7.3 (参考)その他のmutate関連関数

  • mutate_if(), mutate_at(), mutate_all()が追加されています
  • dplyrを最新にして,ヘルプで確認してみてください

8 レコード(行)を条件により抽出、並べ替え

8.1 dplyr::filter()

df <- dplyr::filter(iris, Species=='virginica')
head(df, 3)
## # A tibble: 3 x 5
##   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
## *        <dbl>       <dbl>        <dbl>       <dbl>    <fctr>
## 1          6.3         3.3          6.0         2.5 virginica
## 2          5.8         2.7          5.1         1.9 virginica
## 3          7.1         3.0          5.9         2.1 virginica
  • dplyr::filter(データフレーム, 条件式)
  • 使い方はsubset()と同様

8.2 dplyr::arrange()

df <- dplyr::arrange(iris, Sepal.Length)
head(df, 3)
## # A tibble: 3 x 5
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## *        <dbl>       <dbl>        <dbl>       <dbl>  <fctr>
## 1          4.3         3.0          1.1         0.1  setosa
## 2          4.4         2.9          1.4         0.2  setosa
## 3          4.4         3.0          1.3         0.2  setosa
df <- dplyr::arrange(df, desc(Sepal.Length))
head(df, 3)
## # A tibble: 3 x 5
##   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
## *        <dbl>       <dbl>        <dbl>       <dbl>    <fctr>
## 1          7.9         3.8          6.4         2.0 virginica
## 2          7.7         3.8          6.7         2.2 virginica
## 3          7.7         2.6          6.9         2.3 virginica
  • dplyr::arrange(データフレーム, キー列)で昇順
  • dplyr::arrange(データフレーム, desc(キー列))で降順

9 データを集計(要約)

9.1 dplyr::summarize()

df <- dplyr::summarize(iris, varmean=mean(Sepal.Length))
df
## # A tibble: 1 x 1
##    varmean
##      <dbl>
## 1 5.843333
  • dplyr::summarize(データフレーム, 新変数名=関数(処理対象の変数名))
  • 列の集計を算出
  • 使える関数はsum,sd,meanなど

9.2 dplyr::summarize_each()

df <- dplyr::summarize_each(iris, funs(min, mean, max, sd), ends_with("Length"))
## `summarise_each()` is deprecated.
## Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead.
## To map `funs` over a selection of variables, use `summarise_at()`
df
## # A tibble: 1 x 8
##   Sepal.Length_min Petal.Length_min Sepal.Length_mean Petal.Length_mean
##              <dbl>            <dbl>             <dbl>             <dbl>
## 1              4.3                1          5.843333             3.758
## # ... with 4 more variables: Sepal.Length_max <dbl>,
## #   Petal.Length_max <dbl>, Sepal.Length_sd <dbl>, Petal.Length_sd <dbl>
  • dplyr::summarize_each(データフレーム, funs(関数), 変数)
  • 変数で指定した各変数に対して、関数で集計した結果を返します
  • 変数の指定には、dplyr::select()での方法がそのまま使えます

9.3 (参考)その他のsummarize関連関数

  • summarize_if(), summarize_at(), summarize_all()が追加されています
  • dplyrを最新にして,ヘルプで確認してみてください

10 データをグループ化

10.1 dplyr::group_by()

df <- dplyr::group_by(iris, Species) %>% 
  dplyr::summarize(cmean=mean(Sepal.Length))
df
## # A tibble: 3 x 2
##      Species cmean
##       <fctr> <dbl>
## 1     setosa 5.006
## 2 versicolor 5.936
## 3  virginica 6.588
  • dplyr::group_by(データフレーム、グループ化に使う変数)
  • これを当てると、データがグループ化されます
  • この後にグループごとにやりたい処理を実行すると、このようになります

11 複数のデータセットを結合

11.1 データセットの準備

  • 例として、以下のデータフレームを使います
a <- data.frame(x1=c("A","B","C"),x2=1:3)
b <- data.frame(x1=c("A","B","D"),x3=c(TRUE, FALSE, TRUE))
y <- data.frame(x1=c("A","B","C"),x2=1:3)
z <- data.frame(x1=c("B","C","D"),x2=2:4)
  • aとbを結合する場合、共通する変数はx1
    x1をキーにして、mergeします
  • yとzを結合する場合、変数は共通です 行を追加してまとめる、あるいは列を追加してまとめます

11.2 dplyr::full_join()

df <- dplyr::full_join(a,b,by="x1")
## Warning: Column `x1` joining factors with different levels, coercing to
## character vector
kable(df)
x1 x2 x3
A 1 TRUE
B 2 FALSE
C 3 NA
D NA TRUE
  • dplyr::full_join(データフレーム1, データフレーム2, by=キー変数)
  • 全ての行と列を結合します
  • 該当するものがない場合、NAがはいります

11.3 dplyr::inner_join()

df <- dplyr::inner_join(a,b,by="x1")
## Warning: Column `x1` joining factors with different levels, coercing to
## character vector
kable(df)
x1 x2 x3
A 1 TRUE
B 2 FALSE
  • dplyr::full_join(データフレーム1, データフレーム2, by=キー変数)
  • 両方のデータフレームに存在する行のみを残して結合します

11.4 dplyr::bind_cols()

df <- dplyr::bind_cols(y, z)
kable(df)
x1 x2 x11 x21
A 1 B 2
B 2 C 3
C 3 D 4
  • 左のデータフレームに右のデータフレームの列を追加します
  • 行数が一致してないとエラーになります

11.5 dplyr::bind_rows()

df <- dplyr::bind_rows(y, z)
## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
## Warning in bind_rows_(x, .id): binding character and factor vector,
## coercing into character vector

## Warning in bind_rows_(x, .id): binding character and factor vector,
## coercing into character vector
kable(df)
x1 x2
A 1
B 2
C 3
B 2
C 3
D 4
  • 左のデータフレームに右のデータフレームの行を追加します
  • 列数が一致してないとエラーになります

11.6 dplyr::bind_row(…, .id=)

df <- dplyr::bind_rows(y, z, .id = "df_id")
## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
## Warning in bind_rows_(x, .id): binding character and factor vector,
## coercing into character vector

## Warning in bind_rows_(x, .id): binding character and factor vector,
## coercing into character vector
kable(df)
df_id x1 x2
1 A 1
1 B 2
1 C 3
2 B 2
2 C 3
2 D 4
  • 引数として.id=**を指定すると、テーブルidを変数として作成してくれます
  • これ、めっちゃ便利です

12 wide型(横型)とlong型(縦型)を変換

12.1 tidyr::gather()

df <- tidyr::gather(data=iris, key = keykey, value = valuevalue, -Species)
kable(head(df, 4))
Species keykey valuevalue
setosa Sepal.Length 5.1
setosa Sepal.Length 4.9
setosa Sepal.Length 4.7
setosa Sepal.Length 4.6
  • data: 使用するデータフレーム
  • key: まとめた時に、「この行の値はどの変数に入ってたものか」を示す変数。
  • value: まとめた変数の値。
  • …: まとめる変数を指定します。dplyr::select()のテクニックがそのまま使えます

12.2 tidyr::spread()

# irisにID列を追加して、gatherでまとめている
df <- dplyr::mutate(iris, id=rownames(iris)) %>% 
  tidyr::gather(key = keykey, value = valuevalue, contains("l."))
knitr::kable(head(df,2))
Species id keykey valuevalue
setosa 1 Sepal.Length 5.1
setosa 2 Sepal.Length 4.9
# ひっつけたけどspreadでバラします
df_2 <- tidyr::spread(df, key = keykey, value = valuevalue)
knitr::kable(head(df_2,2))
Species id Petal.Length Petal.Width Sepal.Length Sepal.Width
setosa 1 1.4 0.2 5.1 3.5
setosa 10 1.5 0.1 4.9 3.1
  • gatherと逆の動きをします
  • ただし、spreadを実行した後に、主キーとなるような変数が存在する必要があります
  • データベース的なものがあるんだと思います

13 列の結合・分離

13.1 tidyr::unite

df <- tidyr::unite(data = iris, col = colll, starts_with("Sepal"), sep = "-")
knitr::kable(head(df))
colll Petal.Length Petal.Width Species
5.1-3.5 1.4 0.2 setosa
4.9-3 1.4 0.2 setosa
4.7-3.2 1.3 0.2 setosa
4.6-3.1 1.5 0.2 setosa
5-3.6 1.4 0.2 setosa
5.4-3.9 1.7 0.4 setosa
  • 複数の列をひっつけて一つの列にします

13.2 tidyr::separate

# 一旦ひっつけます(uniteのコードと同一)
df <- tidyr::unite(data = iris, col = colll, starts_with("Sepal"), sep = "-")

# separateを実行
df2 <- tidyr::separate(data = df, col = colll, into = c("Sepal.Length","Sepal.Width"), sep = "-")
knitr::kable(head(df2))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
5.1 3.5 1.4 0.2 setosa
4.9 3 1.4 0.2 setosa
4.7 3.2 1.3 0.2 setosa
4.6 3.1 1.5 0.2 setosa
5 3.6 1.4 0.2 setosa
5.4 3.9 1.7 0.4 setosa
  • 一つの列を、指定した文字で分割して別々の列にします

14 参考資料

14.1 RStudio謹製チートシート

https://www.rstudio.com/resources/cheatsheets/

  • 「Data Wrangling Cheat Sheet」というのがdplyr&tidyrのチートシート
  • 正直、これ1枚あれば今日の説明は不要です
  • 英語がいやなら、日本語もあります(Data Wranglingのみ, pdf)

https://www.rstudio.com/wp-content/uploads/2015/09/data-wrangling-japanese.pdf

14.2 その他のWeb上にある資料

14.3 Enjoy!