初心者セッション

データハンドリング

y__mattu

2021-05-29 TokyoR #92

はじめに

誰?

  • 松村優哉
  • Twitter: y__mattu
  • 人材・HR Tech系で働くデータ分析屋さん
  • 学生時代: 計量経済学、ベイズ統計、因果推論、マーケティング
  • R歴: 7年目
  • https://ymattu.github.io/
  • Tokyo.R 運営(初心者セッションとか)
  • 近況: ロードバイクにはまってます

icon icon

この資料の目的

  • R 初心者(触ったことはあるけど、なんかよくわからない)が、データ操作の雰囲気を掴む

前提知識

  • Rはパッケージを使って様々な機能拡張ができる

Contents

  • tidyverse について
  • データの読み込み
  • データハンドリング

注意

  • 扱う範囲が広く資料の分量が多いので、特に重要なところをピックアップしながら進めます。
  • 参考リンクも多いので資料は後でじっくり御覧ください。
  • パッケージ名だけでも覚えていただけると嬉しいです。

データ分析の(おおまかな)流れ

tidyverse

tidyverse について

tidyverse(概念)

ざっくり:

  • R でやるいろんな操作(データハンドリング、可視化、スクレイピング、分析、etc)を直感的で統一的なインターフェースでできるようになったら嬉しくない?

tidyverse パッケージ

  • 上記の概念を実現するためのコアパッケージ群
  • install.packages("tidyverse")でインストール

tidyverse を読み込み

library(tidyverse)
── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
✓ ggplot2 3.3.3     ✓ purrr   0.3.4
✓ tibble  3.1.0     ✓ dplyr   1.0.3
✓ tidyr   1.1.2     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.0
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()

読み込まれるパッケージ

  • ggplot2: 可視化
  • dplyr: データの操作
  • tidyr: データを tidy に
  • readr: データの読み書き
  • purrr: 関数型プログラミング
  • stringr: 文字列の操作
  • forcats: 因子型データの操作
  • tibble: tibble というモダンなデータフレーム

データの読み込み

R でのデータ読み込みのベストプラクティス

  1. RStudio でプロジェクトを作成
    • ファイルの位置が分かりやすくなります
  2. 様々な読み込み関数を使って読み込み
    • ローカルにあるファイル
    • データベース
    • Web スクレイピング(またの機会に…)

RStudio でプロジェクトを作成

Project → New Project

project1

New Directory → New Project

newdir

newproj

ディレクトリ名を入力

dirname

Done!

  • 読み込みの関数は、プロジェクトの中のファイルを探しにいきます。
  • 書籍によっては setwd() を書いているものもありますが、RStudioプロジェクトでは必要ありません。
    • むしろ、RStudio プロジェクトでは非推奨

データハンドリング

データハンドリングでやること、例えば

  • 縦横変換
  • 絞り込み(列・行)
  • 新しい変数の作成
  • 集計
  • テーブルのマージ
  • etc… →分析できる形に整形

データハンドリング編のコンテンツ

  1. tidy data
  2. dplyr
  3. FAQ

本日の主役は

tidyr

特徴

パッケージを使わないやり方より

  • (大きいデータだと特に)
    速い
  • 簡単
    ≒ わかりやすい
  • 他の tidyverse のパッケージと相性がいい

データハンドリング編のゴール

  • tidy data についてざっくり理解する
  • R の dplyr パッケージで簡単な集計ができるようになること
  • dplyr やtidyrで何ができるのかをなんとなく把握して、「ググり力」を身につける

tidy data

データの形式

2つのデータ形式(例: カテゴリごとの購買金額(千円))

Wide 型

Long 型

tidy data

  • 2016 年に Hadley Wickham 氏が提唱
  • 定義
    • 1つの列が1つの変数を表す
    • 1つの行が1つの観測を表す
    • 1つのテーブルが1つのデータセットを含む
  • Rでのtidy data は、Long 型。

tidyr

gather_spread

tidyrでの縦横変換の例

  • 以下のデータを例に説明
  • これは、いわゆる「横持ちのデータ」
df <- tibble::tibble("country" = c("a", "b", "c"),
                     "1999" = c(0.7, 0.3, 1.0),
                     "2000" = c(1.0, 2.0, 4.8),
                     "2001" = c(2.0, 5.0, 7.0))
df
# A tibble: 3 x 4
  country `1999` `2000` `2001`
  <chr>    <dbl>  <dbl>  <dbl>
1 a          0.7    1        2
2 b          0.3    2        5
3 c          1      4.8      7

pivot_longer

  • 横→縦(tidyな形)の変換
df_long <- df %>%
  pivot_longer(col = -country, names_to = "year", values_to = "amount")
df_long
# A tibble: 9 x 3
  country year  amount
  <chr>   <chr>  <dbl>
1 a       1999     0.7
2 a       2000     1  
3 a       2001     2  
4 b       1999     0.3
5 b       2000     2  
6 b       2001     5  
7 c       1999     1  
8 c       2000     4.8
9 c       2001     7  

pivot_longer

  • 縦(tidyな形)→横の変換
    • 統計解析のパッケージによっては、この形でないとうまく行かないものもある
df_wide <- df_long %>%
  pivot_wider(names_from = "year", values_from = "amount")
df_wide
# A tibble: 3 x 4
  country `1999` `2000` `2001`
  <chr>    <dbl>  <dbl>  <dbl>
1 a          0.7    1        2
2 b          0.3    2        5
3 c          1      4.8      7

詳しくは

参考: tidyr (〜2019/09/11)

gather_spread

%>%

パイプ演算子

  • “これまでの処理を次の関数の第 1 引数として渡す」という働き”
1:3 %>%
  sum()
[1] 6
# これと全く同じ
sum(1:3)

例えば、以下の動作を考えてみる

どう書くのか問題

思考の流れと書く流れ

パイプ演算子を使うときのポイント

  • 結果 <- スタート地点 を書いて、やりたい処理をパイプでつないでいく
  • RStudioでのキーボードショートカット
    • Windows: Ctrl + Shift + M
    • Mac: Cmd + Shift + M

扱うデータ

EC サイトのログデータ

データの読み込み方

  1. RStudio のプロジェクトを作成
  2. Terminal ペインで以下を実行
git clone https://github.com/ymattu/sampledata_small
  1. readr パッケージの関数で読み込み
sales <- read_csv("sampledata_small/csv/Sales.csv")
product <- read_csv("sampledata_small/csv/Products.csv")
user_master <- read_csv("sampledata_small/csv/UserMaster.csv")

dplyr のデータハンドリング基礎

列選択

sales %>%
  select(UserID) %>%
  head()

列選択のやりかたいろいろ 2

select(product, 1:3) # 列番号が連続している場合
select(product, ProductID:Price) # 列名でも連続していれば同様
select(product, -CreatedDate) # 特定の列を除く
select(product, -4) # 特定の列番号を除く
select(product, starts_with("p")) # "p"で始まる列のみを選択
select(product, starts_with("p"), ignore.case = TRUE) # 大文字小文字を無視
select(product, matches("^(Product|Price)")) # "Product"または"Price"で始まる列を選択

列追加

  • 税込み価格を計算
product %>%
  mutate(zeikomi = Price * 1.1) %>%
  head(4)

行の絞り込み

user_master %>%
  filter(Age >= 20, Sex == "F") # 年齢 20 歳以上の女性

集計

  • グルーピング + 集計
sales %>%
  group_by(UserID) %>%
  summarise(buy_count = n())

ここまでやったところで

パッケージを使わないでできないの?

  • できるものもあります。
  • select, filter あたりはできます。
  • でもめんどくさい
  • しかもデータが大きいと遅い
  • このあたり、私の過去資料もみてね
  • でも$はお手軽だしよく使います。

$で 1 列だけ取り出す

product$Category %>%
  unique()
[1] "雑貨・日用品"           "花・グリーン"           "食品"                  
[4] "衣料品"                 "ヘルス&ビューティー"   "家具・インテリア・家電"

日付の操作

lubridate パッケージ

lubridate

  • 日付の操作をよしなにやってくれるパッケージ
library(lubridate)
ymd("20110604")
[1] "2011-06-04"
ymd(20120101) + years(1)
[1] "2013-01-01"

詳しくはこちらこちらを参照

データハンドリングでの使い所

たくさんあるけど例えば

sales %>%
  mutate(buy_year = year(Timestamp)) %>%
  head()

ここから集計につなげる

ユーザー、年ごとに集計

sales %>%
  mutate(buy_year = year(Timestamp)) %>%
  group_by(UserID, buy_year) %>%
  summarise(buy_count = n()) %>%
  arrange(UserID) %>% 
  head()

その他、代表的な
(面倒くさい)型たち

文字列型

因子型(factor 型)

テーブルのマージ

複数のテーブルを考える

a

b

  • 基本は SQL と同じ

inner_join()

a

b

inner_join(a, b, by = "x1")

left_join()

a

b

left_join(a, b, by = "x1")

full_join()

a

b

full_join(a, b, by = "x1")

anti_join()

a

b

anti_join(a, b, by = "x1")

FAQ

dplyr とかだと何で
R の標準関数より速いの?

Answer : C++を使っているから

  • dplyrreadrでは、メインの処理を C++でやり、結果を R で受け取る、という構造になっています。
  • Rcpp パッケージが活躍!

たくさんのテーブルを join したい!

例えばこんな感じ(a, b, c 3 つのデータ)

  x1 x2
1  A  1
2  B  2
3  C  3
  x1    x3
1  A  TRUE
2  B FALSE
3  D  TRUE
  x1 x4
1  B 10
2  C 11
3  D 12

こうする…?

a %>%
  full_join(b, by = "x1") %>%
  full_join(c, by = "x1")

数が増えると大変!

たくさんのテーブルを join したい!

Answer : 少し応用的ですが、purrrパッケージを使うと簡単です。

datlist <- list(a, b, c)
datlist %>%
  purrr::reduce(~full_join(.x, .y, by = "x1"))

purrr パッケージの参考資料→そろそろ手を出す purrr

まとめ

Contents

  • R と RStudio について
  • データハンドリング編
    • tidyverse について
    • dplyr, tidyrパッケージを用いたデータハンドリング

ありがとうございました