20 データ読み込み(Import)
20.1 はじめに
データの読み込みは、データサイエンスの最初のステップです。しかし、データを読み込む時に、その後の、データの整形・変形、さらには、視覚化について、ある程度の理解をしているかどうかで、変わってきますので、順番を、Tidyverse での、dplyr をつかった変形と、ggplot2 を使った視覚化のあとにしました。
個々のデータの読み込みは、それぞれのサイトに特徴的なこともありますし、R のパッケージ(API: Application Programing Interface を用いたプログラム群)を用いて読み込む場合などによって、異なりますので、それは、第三部で扱いたいと思います。
20.2 概略
まずは、基本を確認しましょう。
すでに、WDI パッケージを用いて、データを読み込みましが。同様に、他にも、それぞれのサイトが、コンピュータで直接データを取得できるようにするために、提供している、API(Application Programing Interface)を用いたパッケージが存在します。十分な質のものが提供されている場合は、それを使うのが適切だと思います。
そのような パッケージが提供されていない場合には、データファイルを取得して読み込むことになります。この場合にも、データファイルの URL(universal resource locator)から直接取り込むことができる場合と、一旦、自分のコンピュータにダウンロードして、それから、読み込む場合とがあります。
再現性(reproducibility)を考えると、URL から、直接読み込む方がよいと思いますが、そうはいかない場合、また、自分で作成した、データファイルもあるでしょうから、その場合は、コンピュータから読み込むことになります。
データの形式はさまざまでが、オープンデータでは、CSV(comma separated values) 形式のテキストデータ24か、MicroSoft の Excel 形式のデジタルデータのどちらかを提供している場合がほとんどです。ですから、どちらの形式のファイルなのかを確認することが必要です。
library(tidyverse)
#> ── Attaching core tidyverse packages ──── tidyverse 2.0.0 ──
#> ✔ dplyr 1.1.3 ✔ readr 2.1.4
#> ✔ forcats 1.0.0 ✔ stringr 1.5.0
#> ✔ ggplot2 3.4.4 ✔ tibble 3.2.1
#> ✔ lubridate 1.9.3 ✔ tidyr 1.3.0
#> ✔ purrr 1.0.2
#> ── Conflicts ────────────────────── tidyverse_conflicts() ──
#> ✖ dplyr::filter() masks stats::filter()
#> ✖ dplyr::lag() masks stats::lag()
#> ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(readxl)
library(WDI)
library(owidR)
library(wid)
上で説明した三つの方法を簡単にまとめておきます。
20.2.1 テキストファイル(CSV など)の読み込み
-
readr
パッケージで読み込みます。tidyverse
パッケージ群に含まれる基本パッケージなので、library(tidyverse)
としてあれば使えます。データ間の分離記号の種類によって使う関数が異なります。read_csv()
: comma-separated values (CSV) - カンマの場合read_tsv()
: tab-separated values (TSV) - タブの場合read_csv2()
: semicolon-separated values with,
as the decimal mark - セミコロン; の場合で、少数点に カンマが使われている場合(ヨーロッパでよく使われています)read_delim()
: delimited files (CSV and TSV are important special cases) - 分離記号を指定する場合read_fwf()
: fixed-width files - 固定幅でデータが並んでいる場合read_table()
: whitespace-separated files - 空白が分離記号に使われている場合read_log()
: web log files - ログファイルを読み込む場合例:
df_name <- read_csv("./data/datafile.csv")
詳細は、readr サイト を参照してください。サイトには、Data Importing CheatSheet もあります。
20.2.2 Excel ファイルの読み込み
-
readxl パッケージで読み込みます。
tidyverse
パッケージ群に含まれていますから、新たに、インストールする必要はありませんが、基本パッケージではないので、library(readxl)
としてから使います。例:
df_name <- read_excel("./data/datafile.xlsx")
Excel ファイルには、xls 形式と、xlsx 形式があります。どちらも、read_excel で読み込むことが可能ですが、それぞれの形式に特化した
read_xls
とread_xlsx
も用意されています。Excel ファイルには、複数のシートが含まれる場合があります。そのときには、シートを、何番目のシートか(例:
sheet = 2
)、または、シート名を指定(例:sheet = “name”)して読み込みます。シートの一部を読み込むような場合もあり、その場合は、指定が必要です。Help や、リンク、または、後から示す例を参照してください。
詳細は、readxl サイト を参照してください。サイトには、Data Importing CheatSheet もあります。
20.2.3 データのダウンロード
データの URL がわかっている場合は、直接、データを取り込んだり、data ディレクトリ(フォルダー)にダウンロードすることができます。ダウンロードしたら、テキストファイルか、Excel ファイルかによって、上で説明した方法を使って読み込んでください。
圧縮ファイルになっている場合もあります。圧縮ファイルも R 起動時に読み込まれる util パッケージで解凍できますが、基本的に、コンピュータのプログラムを使いますから、ファイルをダブルクリックするなどして、解凍する場合と同じです。
-
CSV のようなテキストふぁいると、Excel ファイルのようなデジタルファイルで少しだけ異なります。下に例を書きます。いずれも、data ディレクトリ(フォルダー)に保存しています。詳しくは、
download.file
の Help を参照してください。テキストファイル(CSV):
download.file(url = "URL", destfile = "./data/file_name.csv")
-
デジタルファイル(Excel):
download.file(url = "URL", destfile = "./data/file_name.xlsx", mode = "wb")
-
mode = "wb"
デジタルファイルの指定です。Mac の場合には、リソースファイルと呼ばれる不可視ファイルを使っているので、この設定がなくても、読み込めるようです。
-
-
URL がわかっている、CSV ファイルの場合には、直接、readr でも読み込むことができます。
- 例:
df_name <- read_csv(URL)
- 例:
-
URL がわかっていて、read_csv などで読み込んだ場合も、保存しておくことをお勧めします。
保存:
write_csv(df_name, "./data/df_name.csv")
読み込み:
df_name <- read_csv("./data/df_name.csv")
20.3 データの整形 tidyr
R にとって大切な整形されたデータ(tidy data)について学び、Tidyverse パッケージ群の主要なパッケージの一つ
tidyr
について学びます。特に、pivot_longer
とその逆変換である、pivot_wider
の使い方について学びます。
20.3.1 変数、値、観測
データには、変数があり、それぞれの観測における、その変数に関する観測値がありあす。それを、表に記したものが、データ表(Data Table)です。
- 変数(variable)は、量的または質的な値を、測定することが可能なもの
- 値(観測値 value)は、観測し計測した時の測定値
- 観測または場合(observation, case) ある一定のとき、ある一定の条件のもとで、それぞれの変数について行う測定
- データ表(Tabular data)は、観測に基づく、それぞれの変数の値を表にしたもの
20.3.2 整形済みデータ(tidy data)
整形済みの(データ)表とは、それぞれの値が表の一つの枠(ある行ある列)に割り当てられ、変数が列に、それぞれの観測が行に割り当てられたもの
今までは、整形済みのデータを多くみてきましたが、データ表は、必ずしも、整形済みではなく、整形済みのデータが良いデータ表というわけではありません。しかし、R で分析をするときには、整形済みのデータ表の概念を理解し、整形済みのデータに dplyr などを使って 変形にしておくことが重要なステップになります。
まとめると、整形済みデータ(表)とは:
- 各変数が一つの列に対応(Each variable is in its own column)
- 各観測・場合が一つの行に対応(Each observation is in its own row)
- ある変数のある観測における値が枠(セル)に書き込まれてる(1,2 から自動的に従うことです) (Each value is in its own cell (this follows from #1 and #2))
Tidyverse の中心的な開発者である H. ウィッカム(Hadley Wickham)は次のように言っています。
“Tidy data sets are all alike; but every messy data set is messy in its own way.” — Hadley Wickham
訳:整形済みのデータは似たり寄ったりだが、整形されていないデータの乱雑さはそれぞれである。(H. ウィッカム)
“all happy families are all alike; each unhappy family is unhappy in its own way” - Tolstoy’s Anna Karenina
幸せな家族はみな似たり寄ったりだが、不幸な家族は、それぞれに不幸だ。(トルストイ「アンナ・カレーニナ」より)
トルストイの小説「アンナ・カレーニナ」の冒頭の言葉から変形したものですが、実際の世の中を表現するものとして、さまざまな分野で引用されます。データサイエンスでは、アンナ・カレーニナの法則(Anna Karenina Principle (AKP) )とも呼ばれています。
ある指標に関して、平均値や中央値付近のケースは、似たり寄ったりの状況が多いが、外れ値を取るようなケースは、一つの理由ではなく、さまざまな原因で外れ値となっており、それぞれの原因を考察することは、背景を理解する上で重要だという意味にとれると、わたしは理解しています。
20.3.3 整形済みデータと整形済みでないデータ
tidyr
パッケージには、例がデータとして含まれていますので、table1, table2, table3, table4a, table4b, table5 をまずはみてみましょう。
table1
table2
table3
table4a
table4b
table5
どうでしょうか。どれが、整形済みか、どれが整形済みでないかわかりましたか。何を持って、整形済みではないとしているのでしょうか。
ここでは、table1 は整形済み、それ以外は、整形済みでないとして、table1 のように変形するにはどうしたら良いかを考えていきます。
簡単に理由を書いておきます。
table2: count とありますが、人口(population)と場合(case)を一つの物差しでは計れません。
table3: 割合(率)が書かれていますが、同時に、この表記で、人口と、場合を同時に表そうとしています。それぞれの観測において、一つの物差しでの計測値ではありません。
table4a, table4b: どちらも、年毎に別の列になっています。観測値として、同時に計測できるわけではありません。また、これらを、統合する必要もあるでしょう。
table5: 年が二つに分かれています。このように分けることが便利なこともあるでしょうが、まとまっていた方が自然です。
20.3.4 tidyr
による整形の基礎 Pivoting
長型データ(long data)と、幅広型データ(wide data)の変換です。pivoting はある箇所を支点として、回転または折り返すという意味です。Excel にも同様の機能があります。以前は、pivot_longer() は、gather()、pivot_wider() は、spread() という関数が使われていましたから、少し前の文献には、そちらが使われているかもしれません。Posit Primers でもまだ、古いものが使われているようです。
設定値(arguments)やその初期値(default)については、Help をみてください。下には、もっとも簡単なもののみを書きます。
pivot_longer(data = <data>, cols = <column>,
names_to = <new column>, values_to = <value column>)
pivot_longer(data = table4a, cols = c(1999,2000),
names_to = "year", values_to = "population" )
pivot_wider(data = <data>, names_from = <specified column>,
values_from = <value column>)
pivot_wider(data = table2, names_from = type,
values_from = count)
20.3.4.1 例 1: pivot_longer
年(cols = c(“1999”,“2000”))を year (names_to = “year”)という列にまとめ、それぞれの値を、values_to = “cases” にします。同時に、年が、連続変数の dbl ですから、それを離散変数(飛び飛びの値をとる)int(整数に変形します)
table4a
pivot_longer(data = table4a, cols = c("1999","2000"),
names_to = "year", values_to = "cases",
names_transform = list("year" = as.integer))
pivot_longer(data = table4a, cols = c("1999","2000"),
names_to = "year", values_to = "cases",
names_transform = list("year" = as.integer))
20.3.4.2 例 2: pivot_wider
type (names_from = type)を二種類の変数に分け、値を cases (values_from = count) からとります。
table2
pivot_wider(data = table2, names_from = type,
values_from = count)
pivot_wider(data = table2, names_from = type,
values_from = count)
20.3.4.3 例 3: separate
分け方はいろいろとありますが、ここでは、“/” で分けることにします。正規表現を使うことでかなり複雑な分離方法も可能です。参照
table3
separate(table3, rate, c("cases", "population"),
sep = "/", convert = TRUE)
20.3.4.4 例 4: unite
結合します。参照
table5
table5 %>% unite(col = "year", century, year, sep = "") %>%
separate(rate, c("cases", "population"), sep = "/",
convert = TRUE) %>%
mutate(year = as.integer(year), rate = cases / population)
table5 %>% unite(col = "year", century, year, sep = "") %>%
separate(rate, c("cases", "population"), sep = "/",
convert = TRUE) %>%
mutate(year = as.integer(year), rate = cases / population)
20.3.4.5 例 5: bind_rows
二つの表を結合します。行や列の結合:参照
table4a; table4b
tables <- list(cases = table4a, population = table4b)
tables %>% bind_rows(.id = "type") %>%
pivot_longer(cols = c("1999", "2000"), names_to = "year") %>%
pivot_wider(names_from = "type", values_from = "value") %>%
mutate(year = as.integer(year)) %>% arrange(country)
20.4 参照: tidyr
- Textbook: R for Data Science,Tidy Data
- Reference: https://tidyr.tidyverse.org
20.4.1 RStudio Primers: See References in Moodle at the bottom
- Tidy Your Data – r4ds: Wrangle, II
The first component, ‘Reshape Data’ deals with pivot_longer
and pivot_wider
. However, it uses an older version of these functions calls gather
and spread
.
20.5 二つの表の結合
最初に紹介した、世界開発指標(WDI)は、同じ規格でデータを提供してくれていますし、WDI パッケージを使えば、いくつもの指標について同時に入手することもできます。そのようなデータベースに、広範囲の 1400以上の分野からの指標が提供され、毎年定められたときに、更新してくれています。その意味でも、初心者にはとても親切なデータベースです。
しかし、一般的に、データサイエンスにおいては、2つの異なる出処(ソース)のデータを一つにまとめて行うことで、世界が広がり、独自の、データサイエンスが始められるとも言えます。
ここでは、そのための基本的な手法を学びます。変形のところで少し書きましたが、Tidyverse パッケージ群の、dplyr パッケージでは、一つのデータ表の変形だけではなく、2つ以上のデータ表も扱えます。基本的には、2つのデータ表を一つにすることができれば、それに3つ目のデータ表を加えていけば良いので、2つの場合を説明ます。
整理されたデータ表(tidy data)について上に書きましたが、それぞれのデータ表は、整理されているものとして話を進めます。すでに、上で、unite の説明をしてありますから、参考にしてください。
この部分は、Two Table Verbs として、dplyr の機能にある部分ですが、ここで紹介します。
- R for Datascience (2ed) Joins: https://r4ds.hadley.nz/joins#introduction
- Two Table Verbs: https://dplyr.tidyverse.org/articles/two-table.html
- Vignette: https://cran.r-project.org/web/packages/dplyr/vignettes/two-table.html
- 早見表(p.2)Cheat sheet: https://github.com/rstudio/cheatsheets/blob/main/data-transformation.pdf
20.5.1 三種類の結合
融合結合:適合するものを他から読み込む:Mutating joins, which add new variables to one table from matching rows in another.
抽出結合:同一のもの相異なるものを抽出:Filtering joins, which filter observations from one table based on whether or not they match an observation in the other table.
集合算結合:データ集合として結合:Set operations, which combine the observations in the data sets as if they were set elements.
20.5.2 融合結合(mutating joins)
いずれの場合にも両方の表に共通の key を定め、key を媒介として結合する。たとえば、a 列が共通なら、by = “a”, a, b 列が共通に存在する場合は、by = c(“a”, “b”) とし、x の a と、y の c, x の b と y の d が対応する場合は、by = c(“a” = “c”, “b” = “d’) などとする。共通するものが明らかな場合は、省略することも可能。
-
left_join(x,y): x をもとに、y を加える
例:left_join(x,y, by = “a”)
b, c 列も共通の場合は、b.1, b,2, c.1, c.2 などとなる。必要なものだけにして結合したほうが安全である。
right_join(x,y): y をもとに、x を加える
full_join(x,y): x も y も含める
20.5.3 抽出結合(Filtering joins)
- anti_join()
- anti_join(x,y, …): x の行で、y に含まれないもの(return all rows from x without a match in y.)
- semi_join()
- semi_join(x,y, …): x の行で、y に含まれるもの(return all rows from x with a match in y.)
20.5.4 集合算結合(Set joins)
-
intersect(x, y)
: return only observations in bothx
andy
-
union(x, y)
: return unique observations inx
andy
-
setdiff(x, y)
: return observations inx
, but not iny
.
20.5.5 例
以下では、三種類の結合の例を見てみます。Data Transformation with dplyr の早見表の 2ページ目の例も参照してください。
df_1, df_2 では、A 列は共通ですから、何も指定しないと、by = ‘A’ を仮定して結合します。
left_join(df_1, df_2)
#> Joining with `by = join_by(A)`
left_join(df_1, df_2, by = "A")
by = c(“A”, “B”=“F”) としましたが、B と F では一致していない箇所があります。そこで、一致していない場所は、左側の表 df_1 はそのまま C 列を読み込みますが、右側の表 df_2 は、その部分を NA にして読み込んでいません。つまり、一致した行のみ読み込んでいます。
A 列も一致していますが、それは指定していないので、それは別と考えて、A.x, A.y と列名を別にして、かつ左側の表をもとにして読み込んでいます。
roght_join ですから、今度は、右側の表 df_2 をもとにして読み込みます。B 列には、F 列が入っています。
right_join(df_1, df_2, by = c("A", "B"="F"))
左側の表 df_1 と 右側の表 df_2 が一致していない行は、B と F の値によって分けて、読み込んでいます。
左側の表と一致しないものに入れ替えています。たとえば、a, b, c は、右側の行でも、t, u, v であるべきときに、違っている部分をチェックするようなときにも使えます。
anti_join とは逆に、一致しているもののみ取り出します。
集合算では、同じ列について、intersect は共通な部分を取り出します。
intersect(df_1, df_3)
union は、和集合ですから、すべてを含むものを作成します。
union(df_1, df_3)
setdiff は差集合ですから、df_1 に入っていて、df_3 には入っていないものを取り出します。
setdiff(df_1, df_3)
20.6 練習
20.6.1 Posit Primers https://posit.cloud/learn/primers
Tidy Your Data – r4ds: Wrangle, II
データ表の行と列の交換:Reshape Data - a bit old
行または列の結合と分離:Separate and Unite
二つのデータ表の結合:Join Data Sets