[1] 21
第9回講義資料
データハンドリング (1)
スライド
Tidyverseとパイプ演算子
Tidyverseとは
Tidyverse(たいでぃばーす)とはデータサイエンスのために考案された、強い信念と思想に基づいたRパッケージの集合である。具体的には{dplyr}、{tidyr}、{readr}、{ggplot2}など数十パッケージで構成されており、Tidyverseに属するパッケージは思想、文法およびデータ構造(tidy data; 整然データ)を共有しる。また、ベクトルやデータフレーム、関数などのオブジェクトをパイプ演算子 (|>
)で繋ぐという点が特徴である。これらのパッケージ群は{tidyverse}をインストールすることで導入可能であり、JDCat分析ツールでは既に導入済みである。
2010年代中盤以降、Rの書き方はtidyverseな書き方が定着しているため、Rのコードを作成する際はlibrary(tidyverse)
から始めよう。
パイプ演算子
Tidyverseにおいてオブジェクトはパイプ演算子(|>
)で繋がっている。なぜパイプ演算子を使うのだろうか。一般的なプログラミング言語に共通する書き方は書き方と読み方が逆という特徴を持つ。たとえば、「ベクトルXの和を出力する」コードはprint(sum(X))
であり、print
、sum
、X
の順で書く。このコードの読み方には二通りがある。
- 読み方1:
X
をsum()
し、print()
する。 - 読み方2:
print()
する内容はsum()
で、sum()
はX
に対して行う。
1は人間にとって自然な読み方であるが、書き方と逆である。一方、2は書き方と順番は一致するものの、直感的ではない。しかし、Tidyverseな書き方、つまりパイプ演算子を用いた書き方は書き方と読み方が一致するメリットがある。たとえば、先ほどのコードはパイプ演算子を使うとX |> sum() |> print()
と書く。
このパイプ演算子、実はごく簡単な仕組みである。|>
の左側のオブジェクトを右側オブジェクトの最初の引数として渡すだけであり、X |> 関数(Y)
は関数(X, Y)
と同じだ。つまり、X |> sum(na.rm = TRUE)
はsum(X, na.rm = TRUE)
と同じコードである。
|>
演算子はパイプ左側オブジェクトを右側オブジェクトの最初の引数として渡すと説明したたが、第2、3、…引数として渡すことも可能である。ただし、この場合はパイプ左側のオブジェクトが入る箇所に_
と記入する必要がある。詳細は割愛するが、線形回帰分析の関数lm()
は最初の引数が数式(formula型)であるため、データフレームをlm()
に渡すためには、lm()
内にdata = _
と書く必要がある。これは_
の箇所にパイプ左側のオブジェクトが入ることを意味する。
このパイプ演算子(|>
)、実は2021年5月リリースされたR 4.1から使用可能な比較的新しいものである。しかし、パイプ演算子そのものの歴史は短くはない。R 4.1がリリースされるまではRにパイプ演算子は存在しなかったものの、{magrittr}というパッケージが独自のパイプ演算子(%>%
)を提供してきた。%>%
パイプ演算子の使い方は|>
と同じであるため、現段階では何を使っても問題ない。しかし、R界隈の神様であるHadley Wickham先生も現在は%>%
から|>
へ乗り換え済みであることから、これからの主流は|>
になっていくと予想される。現時点に存在する教科書、インターネット記事では%>%
が主流になっているが、それらのコードのパイプ演算子は基本的に|>
に置換しても問題ない。ただし、第一引数以外に使う位置指定子(place holder)が異なる点に注意しておこう。%>%
の位置指定子は.
であり、|>
の位置指定子は_
である。本講義ではパイプ演算子として|>
を使用するが、|>
を使っても同じ結果が得られる。少なくとも本講義に限定した場合、%>%
と|>
は同じものであると考えても良い。
|>
が打ちにくい…!!
旧パイプ演算子%>%
に比べ、|>
は打ちにくいかも知れない。しかし、RStudioを使うのであればショートカットを活用しよう。macOSなら「⌘ + Shift + m」、Windows/Linuxなら「Control (Ctrl) + Shift + m」を同時に押すと、自動的に|>
が入力される(RStudioの設定によっては|>
でなく、%>%
が入力される)。
{dplyr}とは
{dplyr}はTidyverseパッケージ群のコア・パッケージの一つである、表形式データ (データフレームやtibble)を操作するパッケージである。{dplyr}を使えば、第8回の講義で解説した行・列の抽出も簡単に可能となる。{dplyr}を使うためには別途library(dplyr)
を実行する必要はなく、{tidyverse}を読み込む際に自動的に読み込まれる。
まずは本講義に使用するデータを読み込んでみよう。サポートページからcountries.csv
をダウンロードし、プロジェクト・フォルダーにアップロードする。宋はプロジェクト・フォルダー内にData
という名のフォルダーを作成し、そこにデータをアップロードした。
読み込んだデータを出力してみよう。
# A tibble: 186 × 18
Country Population Area GDP PPP GDP_per_capita PPP_per_capita G7
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Afghani… 38928346 6.53e5 1.91e4 8.27e4 491. 2125. 0
2 Albania 2877797 2.74e4 1.53e4 3.97e4 5309. 13781. 0
3 Algeria 43851044 2.38e6 1.70e5 4.97e5 3876. 11324. 0
4 Andorra 77265 4.7 e2 3.15e3 NA 40821. NA 0
5 Angola 32866272 1.25e6 9.46e4 2.19e5 2879. 6649. 0
6 Antigua… 97929 4.4 e2 1.73e3 2.08e3 17643. 21267. 0
7 Argenti… 45195774 2.74e6 4.50e5 1.04e6 9949. 22938. 0
8 Armenia 2963243 2.85e4 1.37e4 3.84e4 4614. 12974. 0
9 Austral… 25499884 7.68e6 1.39e6 1.28e6 54615. 50001. 0
10 Austria 9006398 8.24e4 4.46e5 5.03e5 49555. 55824. 0
# ℹ 176 more rows
# ℹ 10 more variables: G20 <dbl>, OECD <dbl>, HDI_2018 <dbl>,
# Polity_Score <dbl>, Polity_Type <chr>, FH_PR <dbl>, FH_CL <dbl>,
# FH_Total <dbl>, FH_Status <chr>, Continent <chr>
dim()
関数を使うとdf
は186行、18列のデータであることが分かる。
また、18個の変数名のみを出力するためにはnames()
関数を使う。
[1] "Country" "Population" "Area" "GDP"
[5] "PPP" "GDP_per_capita" "PPP_per_capita" "G7"
[9] "G20" "OECD" "HDI_2018" "Polity_Score"
[13] "Polity_Type" "FH_PR" "FH_CL" "FH_Total"
[17] "FH_Status" "Continent"
この実習用データは186カ国の社会経済・政治体制のデータであり、18個の変数で構成されている。詳細は以下の通りである。
変数名 | 説明 | 変数名 | 説明 | |
---|---|---|---|---|
Country |
国名 | OECD |
OECD加盟有無 | |
Population |
人口 | HDI_2018 |
人間開発指数 (2018年) | |
Area |
面積( \(\text{km}^2\) ) | Polity_Score |
政治体制のスコア | |
GDP |
国内総生産(ドル) | Polity_Type |
政治体制 | |
PPP |
購買力平価国内総生産 | FH_PR |
政治的自由 | |
GDP_per_capita |
一人当たりGDP | FH_CL |
市民的自由 | |
PPP_per_capita |
一人当たりPPP | FH_Total |
FH_PR + FH_CL |
|
G7 |
G7加盟有無 | FH_Status |
自由の状態 | |
G20 |
G20加盟有無 | Continent |
大陸 |
列の抽出
データフレームから特定の列(column)を抽出する際はselect()
関数を使用する。select()
関数の第一引数はデータフレームのオブジェクト名であり、第二引数以降では抽出する列名を記入する。第一引数がデータフレームであるため、パイプ演算子を使うことが可能である。
select()
関数は複数ある!
select()
関数は{dplyr}だけでなく、{MASS}からも提供されるが、別の関数である。
- {MASS}もデータ分析において頻繁に使われるパッケージであるため、
select()
だけだと、どのパッケージのselect()
か分からなくなる場合がある。 - エラーが生じる場合は、
dplyr::select()
など、パッケージ名を指定すること
それではいくつかの例を紹介しよう。まずはdf
からCountry
、Population
、HDI_2018
列を抽出してみよう。
# A tibble: 186 × 3
Country Population HDI_2018
<chr> <dbl> <dbl>
1 Afghanistan 38928346 0.496
2 Albania 2877797 0.791
3 Algeria 43851044 0.759
4 Andorra 77265 0.857
5 Angola 32866272 0.574
6 Antigua and Barbuda 97929 0.776
7 Argentina 45195774 0.83
8 Armenia 2963243 0.76
9 Australia 25499884 0.938
10 Austria 9006398 0.914
# ℹ 176 more rows
この操作を第8回で紹介した方法で行う場合、以下のようなコードとなる。どちらの方が可読性が良いかは一目瞭然だろう。
既存の書き方
# A tibble: 186 × 3
Country Population HDI_2018
<chr> <dbl> <dbl>
1 Afghanistan 38928346 0.496
2 Albania 2877797 0.791
3 Algeria 43851044 0.759
4 Andorra 77265 0.857
5 Angola 32866272 0.574
6 Antigua and Barbuda 97929 0.776
7 Argentina 45195774 0.83
8 Armenia 2963243 0.76
9 Australia 25499884 0.938
10 Austria 9006398 0.914
# ℹ 176 more rows
Tidyverseな書き方
# A tibble: 186 × 3
Country Population HDI_2018
<chr> <dbl> <dbl>
1 Afghanistan 38928346 0.496
2 Albania 2877797 0.791
3 Algeria 43851044 0.759
4 Andorra 77265 0.857
5 Angola 32866272 0.574
6 Antigua and Barbuda 97929 0.776
7 Argentina 45195774 0.83
8 Armenia 2963243 0.76
9 Australia 25499884 0.938
10 Austria 9006398 0.914
# ℹ 176 more rows
注意すべき点として、この時点では抽出・出力されただけだということだ。抽出したデータを引き続き使うためには、代入演算子(<-
)を使って、抽出した結果を別途のオブジェクトとして格納する必要がある1。たとえば、df
から3つの変数を抽出したものをdf2
という名で作業環境内に格納するためには以下のように入力する。
ls()
で現在の作業環境内のオブジェクトの一覧を出力するとdf2
がある。
df2
を出力してみるとdf
から3つの列のみ抽出されたものがdf2
という新しい名のオブジェクトとして格納されていることが分かる。
# A tibble: 186 × 3
Country Population HDI_2018
<chr> <dbl> <dbl>
1 Afghanistan 38928346 0.496
2 Albania 2877797 0.791
3 Algeria 43851044 0.759
4 Andorra 77265 0.857
5 Angola 32866272 0.574
6 Antigua and Barbuda 97929 0.776
7 Argentina 45195774 0.83
8 Armenia 2963243 0.76
9 Australia 25499884 0.938
10 Austria 9006398 0.914
# ℹ 176 more rows
課題の問題には「出力せよ」だけでなく、「格納した上で出力せよ」といった形式もある。加工したデータを引き続き使うためには格納が必須であるため、問題文を注意深く読むこと。
select()
関数のもう一つの特徴は、変数名の変更と抽出を同時に行えることだ。抽出する際、新しい変数名 = 既存の変数名
と記入すれば、抽出と同時に変数名も変更できる。たとえば、df
からCountry
、Population
、HDI_2018
を抽出し、HDI_2018
の変数名をHDI
に変更したい場合は以下のように書く。
# A tibble: 186 × 3
Country Population HDI
<chr> <dbl> <dbl>
1 Afghanistan 38928346 0.496
2 Albania 2877797 0.791
3 Algeria 43851044 0.759
4 Andorra 77265 0.857
5 Angola 32866272 0.574
6 Antigua and Barbuda 97929 0.776
7 Argentina 45195774 0.83
8 Armenia 2963243 0.76
9 Australia 25499884 0.938
10 Austria 9006398 0.914
# ℹ 176 more rows
抽出は行わず、変数名のみを変更したい場合はrename()
関数を使用する。使い方はselect()
関数と同じである。たとえば、df
のPopulation
をJinko
に、Area
をMenseki
に変更し、18列は温存する場合は以下のように書く。
# A tibble: 186 × 18
Country Jinko Menseki GDP PPP GDP_per_capita PPP_per_capita G7
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Afghanistan 3.89e7 652860 1.91e4 8.27e4 491. 2125. 0
2 Albania 2.88e6 27400 1.53e4 3.97e4 5309. 13781. 0
3 Algeria 4.39e7 2381740 1.70e5 4.97e5 3876. 11324. 0
4 Andorra 7.73e4 470 3.15e3 NA 40821. NA 0
5 Angola 3.29e7 1246700 9.46e4 2.19e5 2879. 6649. 0
6 Antigua an… 9.79e4 440 1.73e3 2.08e3 17643. 21267. 0
7 Argentina 4.52e7 2736690 4.50e5 1.04e6 9949. 22938. 0
8 Armenia 2.96e6 28470 1.37e4 3.84e4 4614. 12974. 0
9 Australia 2.55e7 7682300 1.39e6 1.28e6 54615. 50001. 0
10 Austria 9.01e6 82409 4.46e5 5.03e5 49555. 55824. 0
# ℹ 176 more rows
# ℹ 10 more variables: G20 <dbl>, OECD <dbl>, HDI_2018 <dbl>,
# Polity_Score <dbl>, Polity_Type <chr>, FH_PR <dbl>, FH_CL <dbl>,
# FH_Total <dbl>, FH_Status <chr>, Continent <chr>
18の変数の中から17個を抽出したい場合はselect()
内に17つの変数名を入れれば良いが、これは非効率的である。select()
関数は変数名の前に!
(推奨)、または-
を付けることで、特定の列を除外することができる。また、2つ以上の変数を除外する場合、変数名をc()
や、後述する:
でまとめることもできる。。
たとえば、df
からPopulation
とArea
、GDP
、PPP
列を除外するコードは以下の通りである。
# A tibble: 186 × 14
Country GDP_per_capita PPP_per_capita G7 G20 OECD HDI_2018 Polity_Score
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Afghan… 491. 2125. 0 0 0 0.496 -1
2 Albania 5309. 13781. 0 0 0 0.791 9
3 Algeria 3876. 11324. 0 0 0 0.759 2
4 Andorra 40821. NA 0 0 0 0.857 NA
5 Angola 2879. 6649. 0 0 0 0.574 -2
6 Antigu… 17643. 21267. 0 0 0 0.776 NA
7 Argent… 9949. 22938. 0 1 0 0.83 9
8 Armenia 4614. 12974. 0 0 0 0.76 7
9 Austra… 54615. 50001. 0 1 1 0.938 10
10 Austria 49555. 55824. 0 0 1 0.914 10
# ℹ 176 more rows
# ℹ 6 more variables: Polity_Type <chr>, FH_PR <dbl>, FH_CL <dbl>,
# FH_Total <dbl>, FH_Status <chr>, Continent <chr>
以上の例だと、Population
からPPP
は連続して位置する変数であるが、{dplyr}では:
演算子を使うと、XXからYYまでといった選択ができる。たとえば、「Population
からPPP
まで」は「Population:PPP
」と表記する。つまり、上記のコードは以下のように書くこともできる。
# A tibble: 186 × 14
Country GDP_per_capita PPP_per_capita G7 G20 OECD HDI_2018 Polity_Score
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Afghan… 491. 2125. 0 0 0 0.496 -1
2 Albania 5309. 13781. 0 0 0 0.791 9
3 Algeria 3876. 11324. 0 0 0 0.759 2
4 Andorra 40821. NA 0 0 0 0.857 NA
5 Angola 2879. 6649. 0 0 0 0.574 -2
6 Antigu… 17643. 21267. 0 0 0 0.776 NA
7 Argent… 9949. 22938. 0 1 0 0.83 9
8 Armenia 4614. 12974. 0 0 0 0.76 7
9 Austra… 54615. 50001. 0 1 1 0.938 10
10 Austria 49555. 55824. 0 0 1 0.914 10
# ℹ 176 more rows
# ℹ 6 more variables: Polity_Type <chr>, FH_PR <dbl>, FH_CL <dbl>,
# FH_Total <dbl>, FH_Status <chr>, Continent <chr>
むろん、:
は否定演算子じゃなくても使える。df
のCountry
〜PPP
, HDI_2018
列を抽出するコードは以下の通りである。
# A tibble: 186 × 6
Country Population Area GDP PPP HDI_2018
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Afghanistan 38928346 652860 19101. 82737. 0.496
2 Albania 2877797 27400 15278. 39658. 0.791
3 Algeria 43851044 2381740 169988. 496572. 0.759
4 Andorra 77265 470 3154. NA 0.857
5 Angola 32866272 1246700 94635. 218533. 0.574
6 Antigua and Barbuda 97929 440 1728. 2083. 0.776
7 Argentina 45195774 2736690 449663. 1036721. 0.83
8 Armenia 2963243 28470 13673. 38446. 0.76
9 Australia 25499884 7682300 1392681. 1275027. 0.938
10 Austria 9006398 82409 446315. 502771. 0.914
# ℹ 176 more rows
以下では変数を選択するより洗練された方法について解説する。変数名が特定の文字列で始まる列を選択する関数としてstarts_with()
がある。たとえば、df
からCountry
, "FH"
で始まる列を抽出する場合は以下のように書く。
# A tibble: 186 × 5
Country FH_PR FH_CL FH_Total FH_Status
<chr> <dbl> <dbl> <dbl> <chr>
1 Afghanistan 13 14 27 NF
2 Albania 27 40 67 PF
3 Algeria 10 24 34 NF
4 Andorra 39 55 94 F
5 Angola 11 21 32 NF
6 Antigua and Barbuda 33 52 85 F
7 Argentina 35 50 85 F
8 Armenia 21 32 53 PF
9 Australia 40 57 97 F
10 Austria 37 56 93 F
# ℹ 176 more rows
starts_with()
の前に!
を付けると該当する列が除外される。たとえば、"GDP"
と"PPP"
で始まる列を除外する場合はstarts_with()
内にcharacter型ベクトルを入れる。
# A tibble: 186 × 14
Country Population Area G7 G20 OECD HDI_2018 Polity_Score Polity_Type
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
1 Afghan… 38928346 6.53e5 0 0 0 0.496 -1 Closed Ano…
2 Albania 2877797 2.74e4 0 0 0 0.791 9 Democracy
3 Algeria 43851044 2.38e6 0 0 0 0.759 2 Open Anocr…
4 Andorra 77265 4.7 e2 0 0 0 0.857 NA <NA>
5 Angola 32866272 1.25e6 0 0 0 0.574 -2 Closed Ano…
6 Antigu… 97929 4.4 e2 0 0 0 0.776 NA <NA>
7 Argent… 45195774 2.74e6 0 1 0 0.83 9 Democracy
8 Armenia 2963243 2.85e4 0 0 0 0.76 7 Democracy
9 Austra… 25499884 7.68e6 0 1 1 0.938 10 Full Democ…
10 Austria 9006398 8.24e4 0 0 1 0.914 10 Full Democ…
# ℹ 176 more rows
# ℹ 5 more variables: FH_PR <dbl>, FH_CL <dbl>, FH_Total <dbl>,
# FH_Status <chr>, Continent <chr>
starts_with()
に似たような機能をする関数として特定の文字列で終わる列を選択するends_with()
と特定の文字列を含む列を選択するcontains()
がある。これらの使い方はstarts_with()
と同じだ。
続いて、列の順番を変更する方法を紹介する。実はselect()
関数は書かれた順番で列を抽出する。たとえば、G7
からOECD
列をCountry
とPopulation
の間へ移動する場合は以下のように書く。
# A tibble: 186 × 18
Country G7 G20 OECD Population Area GDP PPP GDP_per_capita
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Afghanistan 0 0 0 38928346 6.53e5 1.91e4 8.27e4 491.
2 Albania 0 0 0 2877797 2.74e4 1.53e4 3.97e4 5309.
3 Algeria 0 0 0 43851044 2.38e6 1.70e5 4.97e5 3876.
4 Andorra 0 0 0 77265 4.7 e2 3.15e3 NA 40821.
5 Angola 0 0 0 32866272 1.25e6 9.46e4 2.19e5 2879.
6 Antigua an… 0 0 0 97929 4.4 e2 1.73e3 2.08e3 17643.
7 Argentina 0 1 0 45195774 2.74e6 4.50e5 1.04e6 9949.
8 Armenia 0 0 0 2963243 2.85e4 1.37e4 3.84e4 4614.
9 Australia 0 1 1 25499884 7.68e6 1.39e6 1.28e6 54615.
10 Austria 0 0 1 9006398 8.24e4 4.46e5 5.03e5 49555.
# ℹ 176 more rows
# ℹ 9 more variables: PPP_per_capita <dbl>, HDI_2018 <dbl>, Polity_Score <dbl>,
# Polity_Type <chr>, FH_PR <dbl>, FH_CL <dbl>, FH_Total <dbl>,
# FH_Status <chr>, Continent <chr>
しかし、いくら:
演算子があるとはいえ、全ての変数名を書く必要がある。抽出と同時に順番を変更するならselect()
が便利だが、順番のみを変更するならrelocate()
関数がおすすめである。relocate()
関数は移動する変数を指定し、.after
または.before
で移動先を指定する必要がある。
たとえば、G7
からOECD
列をCountry
の後ろへ移動させる場合は以下のように書く。
# A tibble: 186 × 18
Country G7 G20 OECD Population Area GDP PPP GDP_per_capita
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Afghanistan 0 0 0 38928346 6.53e5 1.91e4 8.27e4 491.
2 Albania 0 0 0 2877797 2.74e4 1.53e4 3.97e4 5309.
3 Algeria 0 0 0 43851044 2.38e6 1.70e5 4.97e5 3876.
4 Andorra 0 0 0 77265 4.7 e2 3.15e3 NA 40821.
5 Angola 0 0 0 32866272 1.25e6 9.46e4 2.19e5 2879.
6 Antigua an… 0 0 0 97929 4.4 e2 1.73e3 2.08e3 17643.
7 Argentina 0 1 0 45195774 2.74e6 4.50e5 1.04e6 9949.
8 Armenia 0 0 0 2963243 2.85e4 1.37e4 3.84e4 4614.
9 Australia 0 1 1 25499884 7.68e6 1.39e6 1.28e6 54615.
10 Austria 0 0 1 9006398 8.24e4 4.46e5 5.03e5 49555.
# ℹ 176 more rows
# ℹ 9 more variables: PPP_per_capita <dbl>, HDI_2018 <dbl>, Polity_Score <dbl>,
# Polity_Type <chr>, FH_PR <dbl>, FH_CL <dbl>, FH_Total <dbl>,
# FH_Status <chr>, Continent <chr>
行の抽出
列の抽出はselect()
関数を使うが、行の抽出にはfilter()
関数を使う。行の抽出は基本的に、指定された条件に合致する行を抽出することを意味する。したがって、filter()
関数を使うためには論理演算子(==
、>
、&
など)の理解が必須だ。
filter()
関数の使い方は以下の通りである。パイプを使わずデータオブジェクト名をfilter()
の第一引数として使っても良い。
たとえば、df
からContinent
の値が"Europe"
である行を抽出し、Country
〜PPP
, HDI_2018
列を抽出し、HDI_2018
はHDI
に変更するコードは以下の通りである。行の抽出と列の抽出を同時に行っているため、filter()
関数とselect()
関数を組み合わせる必要がある。
# A tibble: 4 × 6
Country Population Area GDP PPP HDI
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Australia 25499884 7682300 1392681. 1275027. 0.938
2 Fiji 896445 18270 5536. 12496. 0.724
3 New Zealand 4842780 263820 206929. 204260. 0.921
4 Papua New Guinea 8947024 452860 24970. 37319. 0.543
ただし、filter()
とselect()
の順番に注意しよう。filter()
が3行目、select()
が2行目に位置する場合、以下のコードは走らない。なぜなら、select()
関数を通すことでContinent
列が除外されるからだ。
filter()
内の条件式は二つ以上でも使える。たとえば、二つの条件を同時に満たす行を抽出するとしよう。この場合はAND演算子(&
)を使う。たとえば、df
からContinent
が"Asia"
(条件1)、HDI_2018
が0.8以上 (条件2)の行を抽出し、Country
とHDI_2018
列を抽出する場合、以下のように書く。
# A tibble: 13 × 2
Country HDI_2018
<chr> <dbl>
1 Bahrain 0.838
2 Brunei 0.845
3 Israel 0.906
4 Japan 0.915
5 Kazakhstan 0.817
6 South Korea 0.906
7 Kuwait 0.808
8 Malaysia 0.804
9 Oman 0.834
10 Qatar 0.848
11 Saudi Arabia 0.857
12 Singapore 0.935
13 United Arab Emirates 0.866
二つの条件式を&
で繋いだことに注意されたい。filter()
関数で複数の条件式を使う場合は,
、&
、|
のいずれかを使うが、,
と&
は同じ(=AND演算子)である。混乱を避けるために&
の使用を推奨するが、,
を使っても良い。
もう一つの演算子はOR演算子(|
)である。これは2つ以上の条件のうち、一つ以上の条件を満たす行を抽出することを意味する。たとえば、df
からContinent
が"Asia"
(条件1)か"Oceania"
(条件2)の行を抽出し、Country
とHDI_2018
、Continent
列を抽出する場合、以下のように書く。
Code 26
# A tibble: 46 × 3
Country HDI_2018 Continent
<chr> <dbl> <chr>
1 Afghanistan 0.496 Asia
2 Australia 0.938 Oceania
3 Bahrain 0.838 Asia
4 Bangladesh 0.614 Asia
5 Bhutan 0.617 Asia
6 Brunei 0.845 Asia
7 Burma 0.584 Asia
8 Cambodia 0.581 Asia
9 China 0.758 Asia
10 Fiji 0.724 Oceania
# ℹ 36 more rows
AND演算子とOR演算子は同時に使うこともできる。たとえば、df
からContinent
が"Asia"
(条件1)か"Oceania"
(条件2)でありながら、HDI_2018
が0.9以上 (条件3)の行を抽出し、Country
とHDI_2018
、Continent
列を抽出する場合は以下のようになる。ただし、AND演算子とOR演算子を同時に使用する場合は適切な箇所にカッコ(()
)を付ける必要がある。
Code 27
# A tibble: 6 × 3
Country HDI_2018 Continent
<chr> <dbl> <chr>
1 Australia 0.938 Oceania
2 Israel 0.906 Asia
3 Japan 0.915 Asia
4 South Korea 0.906 Asia
5 New Zealand 0.921 Oceania
6 Singapore 0.935 Asia
実は上記のコード、もう少し効率化することもできる。そのためには%in%
演算子を使う必要があるが、==
を用いる複数の条件式がOR演算子で繋がっている場合、大変便利な演算子である。たとえば、Continent
の値がc("Asia", "Oceainia")
のいずれかに該当するかどうかを判定する場合は、これまで(Continent == "Asia" | Continent == "Oceania")
と書いたが、これはContinent %in% c("Asia", "Oceania")
と同じコードである。したがって、上記のコードは以下のように簡素化することもできる。
Code 28
# A tibble: 6 × 3
Country HDI_2018 Continent
<chr> <dbl> <chr>
1 Australia 0.938 Oceania
2 Israel 0.906 Asia
3 Japan 0.915 Asia
4 South Korea 0.906 Asia
5 New Zealand 0.921 Oceania
6 Singapore 0.935 Asia
欠損値の扱い
データには欠損値が含まれていることが多く、Rでは欠損値をNA
と表記する。欠損値が含まれている場合、多重代入法(multiple imputation)などの処理を施すことも可能だが、これはかなり高度の知識を要する。多重代入法を使わない場合は、欠損値を含むケースを除外することが有効である。なぜなら欠損値を含まれている場合、関数が使えないケースも多いからだ2。たとえば、一人あたり購買力平価GDP(PPP_per_capita
)には欠損値が含まれている。この場合、平均値を計算するmean()
関数はそのまま使えない。
この場合、mean()
関数内にna.rm = TRUE
を付けて欠損していない値の平均値を求めるように指定するか、予め欠損値が含まれているケースを除外する必要がある。ここでは後者について説明する。
まず、df
のPPP
が欠損している行を抽出し、Country
からPPP
列まで出力してみよう。PPP
が欠損している場合はNA
の値を取るため、filter()
内にPPP == NA
と条件式を書けば動くかも知れない。
# A tibble: 0 × 5
# ℹ 5 variables: Country <chr>, Population <dbl>, Area <dbl>, GDP <dbl>,
# PPP <dbl>
いや、そうでもなかった。実はある値がNA
か否かを判定するために==
演算子は使えない。代わりにis.na()
関数を使用する。
# A tibble: 8 × 5
Country Population Area GDP PPP
<chr> <dbl> <dbl> <dbl> <dbl>
1 Andorra 77265 470 3154. NA
2 Cuba 11326616 106440 100023 NA
3 Holy See 801 0 NA NA
4 Liechtenstein 38128 160 6553. NA
5 Monaco 39242 1 7188. NA
6 Somalia 15893222 627340 917. NA
7 Syria 17500658 183630 40405. NA
8 Western Sahara 597339 266000 909. NA
しかし、我々が本当にやりたいことはPPP
が欠損している行のみ抽出するのではなく、 PPP
が欠損している行を除外することだ。ここでも否定を意味する!
が使える。
# A tibble: 178 × 5
Country Population Area GDP PPP
<chr> <dbl> <dbl> <dbl> <dbl>
1 Afghanistan 38928346 652860 19101. 82737.
2 Albania 2877797 27400 15278. 39658.
3 Algeria 43851044 2381740 169988. 496572.
4 Angola 32866272 1246700 94635. 218533.
5 Antigua and Barbuda 97929 440 1728. 2083.
6 Argentina 45195774 2736690 449663. 1036721.
7 Armenia 2963243 28470 13673. 38446.
8 Australia 25499884 7682300 1392681. 1275027.
9 Austria 9006398 82409 446315. 502771.
10 Azerbaijan 10139177 82658 48048. 144556.
# ℹ 168 more rows
このようにPPP
が欠損していない行だけが抽出された。また、より簡単な方法としてdrop_na()
関数を使うこともできる。これは()
内で指定した変数が欠損している行をすべて除外する関数であり、複数の変数を同時に指定できるので便利である。たとえば、df
からPPP
とPolity_Score
が欠損していない行だけを抽出し、Country
からPPP
、そしてPolity_Score
列を残してみよう。
# A tibble: 155 × 6
Country Population Area GDP PPP Polity_Score
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Afghanistan 38928346 652860 19101. 82737. -1
2 Albania 2877797 27400 15278. 39658. 9
3 Algeria 43851044 2381740 169988. 496572. 2
4 Angola 32866272 1246700 94635. 218533. -2
5 Argentina 45195774 2736690 449663. 1036721. 9
6 Armenia 2963243 28470 13673. 38446. 7
7 Australia 25499884 7682300 1392681. 1275027. 10
8 Austria 9006398 82409 446315. 502771. 10
9 Azerbaijan 10139177 82658 48048. 144556. -7
10 Bahrain 1701575 760 38574. 74230. -10
# ℹ 145 more rows
行のソート
最後に行のソート(並び替え)について解説する。行のソートにはarrange()
関数を使用する。第一引数はデータフレームのオブジェクトであり、第二引数以降は並び替えの基準となる変数名である。ソートは基本的には昇順、つまり値が小さい行が上に表示される。
たとえば、df
からContinent
の値が"Africa"
の行のみを抽出し、Polity_Score
が小さい国3を上位にする。そして、Country
とPPP_per_capita
、Polity_Score
列のみ残すコードは以下の通りである。
Code 34
# A tibble: 54 × 3
Country PPP_per_capita Polity_Score
<chr> <dbl> <dbl>
1 Eswatini 8634. -9
2 Eritrea 1860. -7
3 Equatorial Guinea 19458. -6
4 Cameroon 3506. -4
5 Congo (Brazzaville) 3191. -4
6 Egypt 11198. -4
7 Morocco 7554. -4
8 Sudan 4063. -4
9 Comoros 3007. -3
10 Congo (Kinshasa) 1043. -3
# ℹ 44 more rows
もし、Polity_Score
が高い国を上位にしたい場合は、変数名をdesc()
関数で囲む。
Code 35
# A tibble: 54 × 3
Country PPP_per_capita Polity_Score
<chr> <dbl> <dbl>
1 Mauritius 22637. 10
2 Kenya 4105. 9
3 South Africa 12605. 9
4 Botswana 17311. 8
5 Ghana 5097. 8
6 Lesotho 3019. 8
7 Benin 3067. 7
8 Liberia 1461. 7
9 Nigeria 5018. 7
10 Senegal 3248. 7
# ℹ 44 more rows
しかし、Polity_Score
が同点の場合はどうなるだろうか。この場合、第2の基準となる変数を指定すると、第1基準が同点の場合、第2基準変数の値に応じてソートされる。以下は、Polity_Score
が高い国を上位にし、同点の場合はPPP_per_capita
が高い国を上位にするコード(さらに、変数名も変更)である。
Code 36
# A tibble: 54 × 3
Country PPP Polity
<chr> <dbl> <dbl>
1 Mauritius 22637. 10
2 South Africa 12605. 9
3 Kenya 4105. 9
4 Botswana 17311. 8
5 Ghana 5097. 8
6 Lesotho 3019. 8
7 Tunisia 10773. 7
8 Nigeria 5018. 7
9 Senegal 3248. 7
10 Benin 3067. 7
# ℹ 44 more rows
教科書
- 『私たちのR: ベストプラクティスの探求』