パッケージ(package)とは、Rの機能を拡張するプログラムである。 (他のプログラミング言語ではライブラリと呼ぶものにあたる)
公開されているパッケージをダウンロードしてインストールするにはinstall.packages("パッケージ名")
と書き、インストールしたパッケージを読み込むにはlibrary(パッケージ名)
と書く。
なお、インストールは一度すれば次回からはinstall.packages()
を実行する必要はないが、library()
はRを起動するたびに必要になる。なお、install.packages()
やlibrary()
を使わないでパッケージを読み込む方法も、後日学びます。
さて、以下ではExcelファイルを読み込むためのパッケージ{readxl}
を使用していく。
まず、分析したいデータファイルを作業用フォルダに入れる。今回は、講義ページにある{test_scores.xlsx}のファイルを使う。
なお、R Studio Cloudのワークスペースにアップロードする場合は、右下の[Files]タブの[Upload]をクリックしてファイルをアップロードする。
test_scores.xlsx
をアップロードすれば、[Files]タブにも反映される。
オブジェクトdat
に代入されたデータフレームは[Environment]タブにも表示される。
「40 obs. of 5 variables」とは、「観測値(行)が40、変数(列)が5」のデータフレームであることを示している。
データフレームオブジェクトの行数と列数を関数で確認したいときはdim()
を使う
## [1] 40 5
(行数だけを取得するnrow()
や列数だけを取得するncol()
といった関数もある)
「40 obs. of 5
variables」の右にある表のようなアイコンをクリックする(あるいはView(dat)
を実行する)と、エクセルのようなセルにデータが入った形式でデータフレームを表示することができる。
head()
関数は、データフレームの先頭6行を表示する関数である。
どういった変数が入ったデータなのかを簡単に把握することができる。
## # A tibble: 6 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 C 安藤 67 78 45
## 2 A 藤村 55 73 72
## 3 B 大泉 47 55 73
## 4 B 木村 78 71 85
## 5 A 鈴井 51 74 61
## 6 C 望月 79 84 75
(なお、後尾6行を見たいときはtail()
関数を使う)
Rは基本的に関数を使ってコードを書くため、複数の処理をまとめて書くときは関数の中に関数を内包する形になる。
複雑な処理を行うときは、関数を内包するたびにコードがどんどん読みづらくなっていく。
## # A tibble: 6 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 C 安藤 67 78 45
## 2 A 藤村 55 73 72
## 3 B 大泉 47 55 73
## 4 B 木村 78 71 85
## 5 A 鈴井 51 74 61
## 6 C 望月 79 84 75
そこでパイプ演算子(%>%
)を利用する。
パイプ演算子は{dplyr}
パッケージをインストールすると利用できるようになる。
パイプ演算子は左にあるオブジェクトを右の関数に受け渡して処理をさせることができる。
## # A tibble: 6 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 C 安藤 67 78 45
## 2 A 藤村 55 73 72
## 3 B 大泉 47 55 73
## 4 B 木村 78 71 85
## 5 A 鈴井 51 74 61
## 6 C 望月 79 84 75
なおRStudioではShift + Ctrl + M
(MacはShift + Command + M
)でパイプ演算子を挿入することができる。
パイプの始点は関数でなくオブジェクトでもよい。
## # A tibble: 6 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 C 安藤 67 78 45
## 2 C 望月 79 84 75
## 3 C 嬉野 54 50 51
## 4 C 安田 46 93 67
## 5 C 伊藤 64 44 68
## 6 C 津久井 52 77 52
なお、パイプ処理で関数に渡されるオブジェクトは関数の第一引数に入れられる。
(本来subset(データフレーム, 条件)
となっていて、この「データフレーム」が第一引数)
ただし、subset(, 条件)
のようにカンマを残す必要はなく、subset(条件)
のように書けばよい。
データの本格的な分析に入る前にデータの整理や加工を行うことを前処理(preprocess)という。
Rでは前処理を効率よく行うために{dplyr}や{tidyr}や{stringr}などのパッケージが整備されている。
いくつものパッケージを個別にインストールと読み込みを行うのは面倒なので、{readxl}や{dplyr}や{stringr}などの便利なパッケージをまとめた{tidyverse}というパッケージをインストールする。
なお、今回のデータはわかりやすいように変数名が日本語になっており、そのまま使用する。しかし実際には、英語名(ローマ字)に変換してから前処理を進めることを奨励する。異なる環境での思わぬエラーなどを防ぐことができ、日本語や漢字が分からない人にもreadableだからである。
{tidyverse}パッケージで読み込まれるパッケージは、例えば次のようなものである
ここでいう条件とは、「変数Xが2である(\(X = 2\))」「変数Zが0以上である(\(Z \geq 0\))」などといったもののこと。
Rでは等号や不等号は次のように表す。
数学上の記号 | Rでの記法 | 意味 |
---|---|---|
=、≠ | == 、!= |
である、でない |
>、< | > 、< |
より大きい、より小さい |
≧、≦ | >= 、<= |
以上、以下 |
これらの条件を複数つなげるとき(例えば「\(X=2\)かつ\(Z=10\)」のようにするとき)の論理演算子は次のように書く。
数学上の記号 | Rでの記法 | 意味 |
---|---|---|
∧、∩ | & |
かつ(and) |
∨、∪ | | |
または(or) |
## [1] TRUE
## [1] FALSE
条件式の計算結果はTRUE(真)とFALSE(偽)の値(論理値)で返される。
条件を満たす行を抜き出したいとき、関数を使わずにシンプルに記述する場合は次の方法で行う。
## # A tibble: 15 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 C 安藤 67 78 45
## 2 C 望月 79 84 75
## 3 C 嬉野 54 50 51
## 4 C 安田 46 93 67
## 5 C 伊藤 64 44 68
## 6 C 津久井 52 77 52
## 7 C 松沢 69 60 99
## 8 C 平藤 65 62 81
## 9 C 荻下 51 98 48
## 10 C 岸 90 51 43
## 11 C 鈴木 66 46 62
## 12 C 山津 68 77 74
## 13 C 木村 43 97 71
## 14 C 望月 87 98 87
## 15 C 増田 70 97 66
これは、df
というデータフレームの"クラス"
という列(df["クラス"]
)が"C"
であるか否かをdf["クラス"] == "C"
として計算させて論理値(TRUEやFALSE)のベクトルを得て、それをdf[行番号,列番号]
の行番号の部分に入れることで条件に合致する行を取り出す方法。
{dplyr}パッケージのfilter()
関数を使っても同様に条件指定して行を取り出すことができる。
filter(データフレーム, 条件式)
の形で書く。
## # A tibble: 7 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 B 大泉 47 55 73
## 2 A 赤石 44 53 40
## 3 B 吉川 43 58 56
## 4 A 渡辺 42 59 89
## 5 C 岸 90 51 43
## 6 A 白川 45 58 68
## 7 A 桜井 94 55 89
(filter()
はパイプ処理の節で登場したsubset()
と機能も文法もほぼ一緒)
なお、dplyr::
は省略することもできる。ただし、読み込んでいる他のパッケージに同じ名前の関数があった場合、エラーが生じるので、できるだけ省略しないことをすすめる。ただ、本講義では簡便化のためにわりと省略している。
## # A tibble: 7 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 B 大泉 47 55 73
## 2 A 赤石 44 53 40
## 3 B 吉川 43 58 56
## 4 A 渡辺 42 59 89
## 5 C 岸 90 51 43
## 6 A 白川 45 58 68
## 7 A 桜井 94 55 89
if_any()
、if_all()
といった関数を組み合わせることでより複雑なフィルタリング条件を簡潔に指定することもできる。
# データフレームのいずれかの変数で100という値をとる行
# (参考)やや古い書き方になるが filter_all(df, any_vars(. == 100)) と書くこともできる
filter(df, if_any(everything(), ~ . == 100))
## # A tibble: 2 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 B 山口 100 99 100
## 2 B 平井 100 49 96
if_any(対象の列を指定する関数, 条件や処理を指定する関数)
というやや難しい記法になる。
(~ . == 100
は{purrr}パッケージで導入される無名関数の記法で、.
を引数に取る関数function(.){. == 100}
を定義していることと等しい)
# 「語」で終わる列名すべてで90以上の値をとる行を取り出す
# if_all()をif_any()に変えると「いずれかで90以上の値」という条件になる
df %>% filter(if_all(ends_with("語"), ~ . > 90))
## # A tibble: 1 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 B 山口 100 99 100
select()
関数はデータフレームから条件に合う列を取り出す関数である
基本的にはselect(データフレーム, 列名1, 列名2, ...)
のように書く。
## # A tibble: 40 × 2
## クラス 名前
## <chr> <chr>
## 1 C 安藤
## 2 A 藤村
## 3 B 大泉
## 4 B 木村
## 5 A 鈴井
## 6 C 望月
## 7 C 嬉野
## 8 B 山口
## 9 C 安田
## 10 A 新城
## # ℹ 30 more rows
パイプ演算子を使用してもよい。
## # A tibble: 40 × 2
## クラス 名前
## <chr> <chr>
## 1 C 安藤
## 2 A 藤村
## 3 B 大泉
## 4 B 木村
## 5 A 鈴井
## 6 C 望月
## 7 C 嬉野
## 8 B 山口
## 9 C 安田
## 10 A 新城
## # ℹ 30 more rows
列名を指定するときに、マイナス(-
)をつけると、「その列以外を取り出す」という指定になる
## # A tibble: 40 × 4
## クラス 数学 英語 国語
## <chr> <dbl> <dbl> <dbl>
## 1 C 67 78 45
## 2 A 55 73 72
## 3 B 47 55 73
## 4 B 78 71 85
## 5 A 51 74 61
## 6 C 79 84 75
## 7 C 54 50 51
## 8 B 100 99 100
## 9 C 46 93 67
## 10 A 88 81 83
## # ℹ 30 more rows
データフレームの列名を変更したいときは、主に次の2つの方法がある
colnames()
を使うcolnames()
関数を使うとデータフレームの列名を取得できる(なお、行名はrownames()
で取得できる)
## [1] "クラス" "名前"
逆に、colnames()
に(列数と同じ長さの)文字列ベクトルを指定することでデータフレームの列名を変更できる。
## # A tibble: 6 × 2
## class name
## <chr> <chr>
## 1 C 安藤
## 2 A 藤村
## 3 B 大泉
## 4 B 木村
## 5 A 鈴井
## 6 C 望月
「点数が低い順に並べ替える」といった操作を行いたい場合、arrange()
を使う
## # A tibble: 40 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 A 渡辺 42 59 89
## 2 B 吉川 43 58 56
## 3 C 木村 43 97 71
## 4 A 赤石 44 53 40
## 5 B 岩田 45 63 51
## 6 A 白川 45 58 68
## 7 C 安田 46 93 67
## 8 B 大泉 47 55 73
## 9 A 鈴井 51 74 61
## 10 C 荻下 51 98 48
## # ℹ 30 more rows
「高い順に並べ替える」という操作をしたい場合はarrange()
の中でdesc()
を使う
## # A tibble: 40 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 B 山口 100 99 100
## 2 C 荻下 51 98 48
## 3 C 望月 87 98 87
## 4 C 木村 43 97 71
## 5 C 増田 70 97 66
## 6 C 安田 46 93 67
## 7 B 前田 92 92 78
## 8 B 橋本 71 87 59
## 9 C 望月 79 84 75
## 10 B 磯部 95 83 47
## # ℹ 30 more rows
前処理においては、「変数を加工し、新たな列に追加する」という処理を行う機会が多い。
変数の加工の仕方は目的に応じて様々だが、ここでは例として学生ごとの3科目の合計得点を算出する、
各科目の列を取り出して足し合わせれば合計得点の算出はできるので、それをdf["新たな列の名前"]
のように記述したものに代入すれば列の追加は簡単に終わる
## # A tibble: 6 × 6
## クラス 名前 数学 英語 国語 合計点
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 C 安藤 67 78 45 190
## 2 A 藤村 55 73 72 200
## 3 B 大泉 47 55 73 175
## 4 B 木村 78 71 85 234
## 5 A 鈴井 51 74 61 186
## 6 C 望月 79 84 75 238
ただし、この方法では追加したい列の数だけこの記述を繰り返す必要がある。
mutate()
関数を使うと列の追加をもう少しスマートに記述できて、mutate(df, 新しい列の名前 = 代入したい内容)
のように書く。
例えば「数学+国語」、「数学+英語」の2つの変数を作り、それぞれ「数国計」「数英計」と名付けることにする。
その場合、次のようにカンマで区切りながら変数を追加していく。
## # A tibble: 40 × 8
## クラス 名前 数学 英語 国語 合計点 数国計 数英計
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 C 安藤 67 78 45 190 112 145
## 2 A 藤村 55 73 72 200 127 128
## 3 B 大泉 47 55 73 175 120 102
## 4 B 木村 78 71 85 234 163 149
## 5 A 鈴井 51 74 61 186 112 125
## 6 C 望月 79 84 75 238 154 163
## 7 C 嬉野 54 50 51 155 105 104
## 8 B 山口 100 99 100 299 200 199
## 9 C 安田 46 93 67 206 113 139
## 10 A 新城 88 81 83 252 171 169
## # ℹ 30 more rows
同じ行数の2つのデータフレームを連結したいときはbind_cols()
を使う
## # A tibble: 40 × 5
## クラス 名前 数学 英語 国語
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 C 安藤 67 78 45
## 2 A 藤村 55 73 72
## 3 B 大泉 47 55 73
## 4 B 木村 78 71 85
## 5 A 鈴井 51 74 61
## 6 C 望月 79 84 75
## 7 C 嬉野 54 50 51
## 8 B 山口 100 99 100
## 9 C 安田 46 93 67
## 10 A 新城 88 81 83
## # ℹ 30 more rows
(ちなみに、同様の機能をもつ関数でcbind()
というものもある。)
同じ列数の2つのデータフレームを連結したいときはbind_rows()
を使う
## # A tibble: 40 × 6
## クラス 名前 数学 英語 国語 合計点
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 C 安藤 67 78 45 190
## 2 A 藤村 55 73 72 200
## 3 B 大泉 47 55 73 175
## 4 B 木村 78 71 85 234
## 5 A 鈴井 51 74 61 186
## 6 C 望月 79 84 75 238
## 7 C 嬉野 54 50 51 155
## 8 B 山口 100 99 100 299
## 9 C 安田 46 93 67 206
## 10 A 新城 88 81 83 252
## # ℹ 30 more rows
(同様の機能をもつ関数でrbind()
というものもある。)
「異なる行数・列数のデータフレームが2つあり、“id”列だけが対応関係にある」というような状況は公的統計でも民間企業のデータでも非常に多くある。 (例えば公的統計なら「“地方自治体コード”列が対応関係にあるデータ群」であったり、民間企業なら「“顧客id”列が対応関係にあるデータ群」であったりする。)
そうした場合は”id”列を基準にデータフレームを結合するjoin関数を使う。
full_join()
関数を例に実行してみる。
まず、例示用に簡単なデータフレームを作る
## 顧客id 性別 年齢
## 1 1 男性 20
## 2 2 女性 24
## 3 3 女性 35
# 取引データ
sales <- data.frame(取引id = 1:3,
顧客id = c(1,2,2),
商品 = c("みかん", "みかん", "りんご"),
金額 = c(200, 200, 300))
sales
## 取引id 顧客id 商品 金額
## 1 1 1 みかん 200
## 2 2 2 みかん 200
## 3 3 2 りんご 300
これをfull_join()
で結合する。full_join(df1, df2, by = "id")
のように書く。
## 顧客id 性別 年齢 取引id 商品 金額
## 1 1 男性 20 1 みかん 200
## 2 2 女性 24 2 みかん 200
## 3 2 女性 24 3 りんご 300
## 4 3 女性 35 NA <NA> NA
このように顧客id
で紐づけしてひとつのデータフレームへと結合する。
ところで、結合する2つのデータフレーム間でidのデータが等しいとは限らない。
一方では他方に比べて収録されているidのデータが少ないかもしれない
(先の例で顧客id == 3
の取引履歴が存在しなかったように)。
結合の方法は一般的に4種類存在する。 Rでは結合方法に応じて別々の関数になっており、
inner_join()
:
両方のデータフレームに存在するidを使うfull_join()
:
いずれかのデータフレームに存在するidを使うleft_join()
:
左側に指定されたデータフレームに存在するidを使うright_join()
:
右側に指定されたデータフレームに存在するidを使うとなっている。
データの形式には「ロング形式(縦持ち)」と呼ばれるものと、「ワイド形式(横持ち)」と言われるものがある。
ロング形式は、例えば上記のsales
データのように”商品”列には商品の種類を書き、“金額”列にはその商品の売上金額を書くものである。
一般的なデータが基本的に採用している形式で、これまで例に使用してきたデータフレームもロング形式である。
## 取引id 顧客id 商品 金額
## 1 1 1 みかん 200
## 2 2 2 みかん 200
## 3 3 2 りんご 300
ワイド形式は、例えばsales
データで”商品”列の商品の種類ごとに列を分け、“顧客id”に対応する金額をセルに入れたもの(クロス集計表のような形式になっているもの)である。
{tidyr}パッケージのpivot_wider()
でワイド形式に変換することができる
## # A tibble: 3 × 4
## 取引id 顧客id みかん りんご
## <int> <dbl> <dbl> <dbl>
## 1 1 1 200 NA
## 2 2 2 200 NA
## 3 3 2 NA 300
{tidyr}パッケージのpivot_longer()
でロング形式に戻すことができる
# ロング形式に戻す
sales_long <- sales_wide %>%
tidyr::pivot_longer(cols = c(-顧客id, -取引id), names_to = "商品", values_to = "金額")
sales_long %>% dplyr::filter(!is.na(金額))
## # A tibble: 3 × 4
## 取引id 顧客id 商品 金額
## <int> <dbl> <chr> <dbl>
## 1 1 1 みかん 200
## 2 2 2 みかん 200
## 3 3 2 りんご 300
{stringr}パッケージによる文字列操作の基本を紹介する
文字列ベクトルの全要素を結合してひとつの文字列にまとめるにはstr_flatten()
を使う
## [1] "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
プログラミング言語などにおいて、基本的な知識をまとめた文書をチートシート(Cheat Sheet)という。
RStudioの公式サイトにもチートシートの一覧がまとめられているが、主要なものはRStudioの[Help]→[Cheatsheets]からも簡単にアクセスできる。
有志による日本語のチートシートは公式サイトの下の方の「Japanese Translations - 日本語翻訳」で見ることができる(翻訳版は更新頻度が低く内容がやや古い場合があるので注意)。
石田基広(2017)『Rによるテキストマイニング入門』 森北出版 第2版
Rによるテキストマイニングの教科書だが、「第3章 R/RStudio速習」には、本稿と重なる内容が説明されている。