初心者セッション

R入門〜データハンドリング

y__mattu

2022-01-29 TokyoR #96

はじめに

誰?

  • 松村優哉
  • Twitter: y__mattu
  • ex.バックオフィスクラウド、next広告系のDS
  • 学生時代: 計量経済学、ベイズ統計、因果推論、マーケティング
  • R歴: 8年目突入
  • https://ymattu.github.io/
  • http://y-mattu.hatenablog.com/
  • Tokyo.R 運営(初心者セッションとか)

icon

宣伝

改訂2版 R ユーザのための RStudio[実践]入門
− tidyverse によるモダンな分析フローの世界−

rstudiobook

この資料の目的

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

Contents

  • R と RStudio について
  • tidyverse について
  • テーブルデータの読み込み
  • データハンドリング
  • 統計学・モデリング・可視化については触れません。

注意

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

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

RとRStudioについて

Rとは

  • 統計解析およびその周辺環境に強いプログラミング言語
    • データの読み込み(ローカル, Webページ, DB)
    • データハンドリング
    • モデリング
    • 可視化
  • 最近はWebアプリやAPI作成など、「プロダクションレベル」を支えられるような環境も整いつつある
  • また、機械学習やディープラーニングなど、これまでPythonに優位性があった手法も多くカバーされるようになってきた
    • tidymodels, keras, torchなど
  • プログラミング未経験でも始めやすい(個人的な感想)

R の環境構築

R のパッケージ

  • R のパッケージを使うことで、世界中で開発されている便利な手法を使える
  • パッケージに含まれている関数を呼び出すことで、様々な拡張機能を使う
  • パッケージは、関数の集まり
  • CRANに登録されているものは、install.packages("パッケージ名") でインストール
    • 例: install.packages("ggplot2")

パッケージ内の関数の表記

  • readr パッケージの read_csv 関数を使いたいとき
# 方法 1
library(readr)
dat <- read_csv("hoge.csv")
# 方法 2
dat <- readr::read_csv("hoge.csv")
  • 特に、「方法2」は関数が所属するパッケージを明示することで、あとから見たときにコードの確認がしやすかったり、他の人と共有する際に分かりやすいなど、利点が多く個人的にはおすすめ
  • ただし、本資料では直感的なわかりやすさを優先し「方法1」を多く使います

データハンドリング編

tidyverse

tidyverse について

tidyverse(概念)

ざっくり:

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

tidyverse パッケージ

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

tidyverse を読み込み

library(tidyverse)
── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.5     ✓ purrr   0.3.4
✓ tibble  3.1.6     ✓ dplyr   1.0.7
✓ tidyr   1.1.4     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.1
── 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 プロジェクトでは非推奨

いよいよデータの読み込み

ローカルにあるファイル

csv

read.csv()

  • パッケージを使わない方法
dat <- read.csv("sample.csv")
  • R < 4.0.0 では stringsAsFactors = TRUE がデフォルトになっているので、stringsAsFactors = FALSE をつけることを推奨します。
dat <- read.csv("sample.csv", stringsAsFactors = FALSE)

readr::read_csv()

  • 高速で、列の型をいい感じにやってくれる(オススメ)
dat <- readr::read_csv("sample.csv")

data.table::fread()

  • readr::read_csv() よりも高速
  • デフォルトでは、data.table というデータフレームとは別の形で読み込まれるのでデータフレームがいいときは data.table = FALSE
library(data.table)
dat <- fread("sample.csv", data.table = FALSE)

どれがいいのか

  • 個人的には readrパッケージの read_***()関数が一番オススメ
  • 速い、エンコーディングの調整が難しくない
  • 参考速度比較表
read.*** read_*** fread
速さ(45MB) 3秒 0.8 秒 0.6秒
区切り値の判定ミス × ×
エンコーディング

xlsx, xls

エクセルファイル

エクセルファイルを読み込めるパッケージ

  • xlsx
  • gdata
  • XLConnect
  • openxlsx
  • readxl → オススメ(速い、列の型をいい感じに読める)

読み込み方

dat <- readxl::read_excel("sample.xlsx", sheet = "シート名")
# シート名はシート番号でも OK

文字コードの指定

エンコーディング問題

  • Windows の文字コードは Shift-JIS(CP932)
  • Mac の文字コードは UTF8
  • Windows で作られた(日本語を含む)ファイルを Mac で読むときは Encoding=cp932
  • Mac で作られた(日本語を含む)ファイルを Windows で読むときは Encoding=UTF8

csv を CP932 で読む

R の標準関数

dat <- read.csv("sample.csv", stringAsFactors = FALSE, fileEncoding = "cp932")

readr

dat <- readr::read_csv("sample.csv", locale = locale(encoding = "cp932"))

data.table

dat <- data.table::fread("sample.csv", data.table = FALSE) %>%
  dplyr::mutate(VAR1 = iconv(VAR1, from = "UTF8", to = "CP932"))

関数とかオプション(引数)を
覚えられない

RStudio の GUI 読み込み

dataimport

RStudio の GUI 読み込み

dataimport2

データハンドリング

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

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

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

  1. パイプ演算子
  2. tidy data
  3. dplyr
  4. FAQ

主役は

tidyr

特徴

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

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

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

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

%>%

パイプ演算子

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

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

どう書くのか問題

思考の流れと書く流れ

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

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

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 × 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 × 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 × 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

このような場合でも

dat_m <- tibble::tibble(user = c('A', 'B', 'C'),
                        category_1 = c(10, 15, 8),
                        category_2 = c(2, 4, 5),
                        subject_1 = c(4, 5, 6),
                        subject_2 = c(5, 6, 7))
dat_m
# A tibble: 3 × 5
  user  category_1 category_2 subject_1 subject_2
  <chr>      <dbl>      <dbl>     <dbl>     <dbl>
1 A             10          2         4         5
2 B             15          4         5         6
3 C              8          5         6         7

long型に変形可能

dat_long <- dat_m %>%
  pivot_longer(cols = -user,
               names_to = c("group", "num"),
               names_sep = "_")
dat_long
# A tibble: 12 × 4
   user  group    num   value
   <chr> <chr>    <chr> <dbl>
 1 A     category 1        10
 2 A     category 2         2
 3 A     subject  1         4
 4 A     subject  2         5
 5 B     category 1        15
 6 B     category 2         4
 7 B     subject  1         5
 8 B     subject  2         6
 9 C     category 1         8
10 C     category 2         5
11 C     subject  1         6
12 C     subject  2         7

詳しくは

Tokyo.R #79 の応用セッション を参照。

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

gather_spread

dplyr

扱うデータ

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()

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

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, starts_with("p") & ends_with("e")) # "p"で始まり"e"で終わる列を選択
select(product, matches("^(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 型)

FAQ

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

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

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

まとめ

Contents

  • R と RStudio について
  • データの読み込み
  • データハンドリング編
    • tidyverse について
    • readrパッケージを用いたテーブルデータの読み込み
    • dplyr, tidyrパッケージを用いたデータハンドリング

ありがとうございました

enjoy!