← 授業トップへ戻る


本日の目標

  1. dplyr の基本動詞(filter, select, mutate, arrange)を使える
  2. パイプ演算子 |> を使って処理を連結できる
  3. 実際のデータを整形できる

0. 今日の進め方

第4回では,グラフの見た目を整えて ggsave() で保存しました。 今日からは,グラフではなくデータそのものを加工します。

  1. RStudioを起動する
  2. File → New File → R Script で新しいファイルを作る
  3. 資料のコードを写して,全選択(Ctrl + A)してから Ctrl + Enter (Mac は Cmd + A → Cmd + Enter)で,まとめて実行する
  4. 結果は図ではなく表で出ます。Plots タブではなく Console を見てください

今日は図を作りません。 Macの人が第4回で行った ragg / AGG の設定は, そのままにしておいてください。次回以降また使います。

前回の宿題(kadai_02.png が開けるか)は,できていなくても 今日の内容には影響しません。


準備:パッケージの読み込み

この回のコードは,すべて tidyverse を読み込んだ状態で動きます。 RStudioを起動したら,まずこれを実行してください。

library(tidyverse)

毎回必要です。今日使う msleep は tidyverse(ggplot2)に入っているデータなので, 読み込まないと,関数より先にデータのほうが見つかりません。

出るエラー 原因
オブジェクト 'msleep' がありません library(tidyverse) を実行していない
関数 "select" を見つけることができませんでした 同上

なお filter() は,読み込まなくても「関数が見つかりません」とは言われません。 R本体に別の filter()(stats::filter)があるためです。 エラーの文面が違っても,まず library(tidyverse) を疑ってください。


1. dplyrとは

dplyr は,データフレームを操作するための強力なパッケージです。

dplyrの6つの基本動詞

動詞 意味 Excelで例えると
filter() 行を絞り込む フィルタ機能
select() 列を選ぶ 列の選択・非表示
mutate() 新しい列を追加・変換 数式で新列作成
arrange() 並び替え 昇順・降順ソート
summarise() 集計(次回) AVERAGE・SUM関数
group_by() グループ化(次回) ピボットテーブル

2. 練習用データ

今日は msleep(哺乳類の睡眠データ,83種)を使います。

msleep は tidyverse を読み込むと使えるようになります(ggplot2に付属しています)。 第3・4回で使った iris はR本体に入っていたので読み込み不要でしたが,msleep は違います。

# データの確認
glimpse(msleep)
## Rows: 83
## Columns: 11
## $ name         <chr> "Cheetah", "Owl monkey", "Mountain beaver", "Greater shor…
## $ genus        <chr> "Acinonyx", "Aotus", "Aplodontia", "Blarina", "Bos", "Bra…
## $ vore         <chr> "carni", "omni", "herbi", "omni", "herbi", "herbi", "carn…
## $ order        <chr> "Carnivora", "Primates", "Rodentia", "Soricomorpha", "Art…
## $ conservation <chr> "lc", NA, "nt", "lc", "domesticated", NA, "vu", NA, "dome…
## $ sleep_total  <dbl> 12.1, 17.0, 14.4, 14.9, 4.0, 14.4, 8.7, 7.0, 10.1, 3.0, 5…
## $ sleep_rem    <dbl> NA, 1.8, 2.4, 2.3, 0.7, 2.2, 1.4, NA, 2.9, NA, 0.6, 0.8, …
## $ sleep_cycle  <dbl> NA, NA, NA, 0.1333333, 0.6666667, 0.7666667, 0.3833333, N…
## $ awake        <dbl> 11.9, 7.0, 9.6, 9.1, 20.0, 9.6, 15.3, 17.0, 13.9, 21.0, 1…
## $ brainwt      <dbl> NA, 0.01550, NA, 0.00029, 0.42300, NA, NA, NA, 0.07000, 0…
## $ bodywt       <dbl> 50.000, 0.480, 1.350, 0.019, 600.000, 3.850, 20.490, 0.04…
列名 説明
name 動物名
genus 属
vore 食性(herbi, omni, carni, insecti)7件が欠損
order 目
conservation 保全状況(絶滅危惧の区分など)
sleep_total 1日の総睡眠時間(時間)
sleep_rem REM睡眠時間(時間)
sleep_cycle 睡眠サイクル(時間)
awake 覚醒時間(時間)
brainwt 脳の重さ(kg)
bodywt 体重(kg)

3. パイプ演算子 |>

パイプ演算子 |> は,処理を連続して書くための道具です。

# パイプなし
result <- arrange(filter(msleep, vore == "carni"), sleep_total)

# パイプあり(読みやすい!)
result <- msleep |>
  filter(vore == "carni") |>
  arrange(sleep_total)

読み方:|> は「それを〇〇に渡す」と読みます。 データ |> 処理 → 「データを処理にかける」

%>% という別のパイプも見かけます。 教科書やインターネットの記事では %>%(magrittr のパイプ)がよく使われています。 今日の範囲では |> と同じ結果になるので,見かけたら |> に読み替えて構いません。 |> はR本体の機能で,R 4.1以降なら何も読み込まずに使えます。


4. filter():行の絞り込み

# 肉食動物だけ抽出
msleep |>
  filter(vore == "carni")
# 睡眠時間が12時間以上の動物
msleep |>
  filter(sleep_total >= 12)
# 複数条件:肉食で睡眠10時間以上
msleep |>
  filter(vore == "carni", sleep_total >= 10)

比較演算子と論理演算子

記号 意味
== 等しい
!= 等しくない
> / < より大きい / より小さい
>= / <= 以上 / 以下
& または , かつ(AND)
\| または(OR)
is.na() 欠損値である
!is.na() 欠損値でない

欠損値(NA)のある行は落ちます

vore には7件の欠損があります。filter() は,条件の判定が NA になる行を 結果から落とします。

# 草食「以外」を取り出したつもりでも……
msleep |>
  filter(vore != "herbi") |>
  nrow()
## [1] 44

全83件のうち草食は32件なので 51件になりそうですが,44件です。 vore が欠損している7件は,「herbiである」とも「herbiでない」とも判定できないため, != でも拾われません(83 − 32 − 7 = 44)。

欠損のある行を扱うには is.na() を使います。

msleep |> filter(is.na(vore))    # 欠損している7件だけ
msleep |> filter(!is.na(vore))   # 欠損していない76件だけ

次回グループごとに集計すると,この7件が NA というグループとして表に現れます。


5. select():列の選択

# 動物名・食性・睡眠時間だけ選ぶ
msleep |>
  select(name, vore, sleep_total)
# 特定の列を除外する
msleep |>
  select(-genus, -order, -conservation)

msleep の列 order(目)は,R本体の関数 order() と同じ名前です。 select() や filter() の中では列として扱われるので問題ありませんが, 単独で order と書くと関数のほうを指します。

# 列名のパターンで選択
msleep |>
  select(name, starts_with("sleep"))

6. mutate():新しい列の作成・変換

# 睡眠時間を分に変換した列を追加
msleep |>
  select(name, sleep_total) |>
  mutate(sleep_min = sleep_total * 60)
# 脳の割合(脳重量 / 体重)を計算
msleep |>
  select(name, brainwt, bodywt) |>
  mutate(brain_ratio = brainwt / bodywt) |>
  filter(!is.na(brain_ratio)) |>
  arrange(desc(brain_ratio))

7. arrange():並び替え

# 睡眠時間の短い順(昇順)
msleep |>
  select(name, sleep_total) |>
  arrange(sleep_total)
# 睡眠時間の長い順(降順)
msleep |>
  select(name, sleep_total) |>
  arrange(desc(sleep_total))

8. 複数の動詞を組み合わせる

# 草食動物の中で睡眠時間が長い上位5種を表示
msleep |>
  filter(vore == "herbi") |>
  select(name, sleep_total, bodywt) |>
  arrange(desc(sleep_total)) |>
  head(5)

演習

演習1:filter()の練習

msleep から以下の条件に合う動物を抽出してください。

  1. 雑食動物(vore == "omni")だけ抽出
  2. 体重(bodywt)が 100 kg 以上の動物だけ抽出
  3. 草食(vore == "herbi")かつ総睡眠時間(sleep_total)が 8 時間以上の動物を抽出

問:1 で取り出した雑食動物は20件でした。vore が欠損している7件は, この20件に入っていますか。入っていないとすれば,それはなぜですか。

演習2:select() の練習

msleep から動物名・食性・総睡眠時間・体重の4列だけを選んだデータフレームを作ってください。

演習3:mutate() の練習

msleep に「覚醒時間の割合」を計算した列(awake_ratio = awake / 24)を追加してください。 その後,値の大きい順に並べ替え,上位10行を表示してください。

msleep |>
  select(name, awake) |>
  mutate(awake_ratio = ___ / ___) |>
  arrange(___) |>
  head(___)

問:上位に並ぶのはどんな動物ですか。sleep_total(総睡眠時間)と見比べて, 気づいたことを書いてください。


本日のまとめ

  • filter() で行を絞り込む
  • select() で列を選ぶ
  • mutate() で新しい列を作る・変換する
  • arrange() で並び替える
  • パイプ |> で処理をつなげると読みやすい
  • 条件の判定が NA になる行は,filter() の結果から落ちる

宿題・予習

  • 本日の演習を完成させ,スクリプトを保存する
  • 次回は summarise() と group_by() によるデータ集計を学びます
  • 教科書のdplyrに関する章(集計まで)を読んでおく

← 授業トップへ戻る