Rによるデータの読み込みと書き出し

特殊講義「インターネットを活用した経済データの分析」講義資料

2/16/2017

1 はじめに

Rでのファイルの読み込みや書き出しの作法はエクセルのようなソフトウェアとは異なり,「ファイルのダブルクリック」等ではなく,Rのコンソールへのコマンド入力によって行なう.一見敷居が高いように思えるが,一旦慣れてしまえば,毎回キーボードから手を離し「ポチポチ」しなくてはならないエクセルのようなソフトウェアよりも作業が大幅に楽になる.以下では,

  1. サンプルデータの呼び出し
  2. ファイルの保存 (書き出し)
  3. ローカルデータの読み込み
  4. ウェブ上のデータの読み込み

の方法を,具体例と便利なパッケージを用いて説明する.また,データを読み込むだけではつまらないので,適宜作図を交える. 以下で説明する基本をマスターして,お金も手間もかかれば使いやすくもなく,何もいいところのないエクセルには満面の笑みで「さようなら」と言おう (ついでにwordにもPowerPointにもry).

2 サンプルデータの呼び出し

Rをインストールすると,同時に多数のサンプルデータがついてくる.これらのデータセットは解析や作図の練習に使えるだけでなく,パッケージの使い方を解説する説明文書でも多用される. サンプルデータは,Rのコンソールに data(サンプルデータ名) と入力することで読み込める.たとえば,irisというサンプルデータを読み込むには,次のように入力する.

data(iris)

エラーは出ていないが,本当に読み込まれているだろうか.確認してみる.

exists("iris")
## [1] TRUE

exists()関数は,引数 (引用符でくくって文字列として与えることに注意) に与えられたオブジェクトが,現在の作業領域上に存在するか否かを返す.たとえばここでは,exists("iris")の返り値がTRUEならirisが存在する (きちんと読み込まれている) ことを,FALSEなら存在しない (読み込まれていない) ことを示す.

2.1 サンプルデータの解説記事

こうしたサンプルデータの解説は,日本語でも多数見つかる.たとえば,以下のウェブサイトがある.

2.2 tibbleクラスへの変換

これらのデータはいずれもdata.frameオブジェクトとして呼び出されるが,ここではより便利なtibbleクラスに変換しておく. tibbleオブジェクトでは,データの大きさ (行数と列数)や各列のデータタイプが一目瞭然となるため,特にこだわりがなければtibbleクラスの積極的な利用を強く勧める. data.frameオブジェクトをtibbleオブジェクトに変換するには,dplyr::tbl_df()関数もしくはtibble::as_data_frame()関数を用いる.

# install.packages("tidyverse", dependencies = TRUE) # tidyverseパッケージをインストールしていなければ,行頭の#を削除してこの行を実行
library(tidyverse) ## tidyverseを呼び出すことで,dplyr を含むいくつかの便利なパッケージをまとめて呼び出す
iris_tibble = tbl_df(iris)
iris_tibble
## # A tibble: 150 × 5
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
##           <dbl>       <dbl>        <dbl>       <dbl>  <fctr>
## 1           5.1         3.5          1.4         0.2  setosa
## 2           4.9         3.0          1.4         0.2  setosa
## 3           4.7         3.2          1.3         0.2  setosa
## 4           4.6         3.1          1.5         0.2  setosa
## 5           5.0         3.6          1.4         0.2  setosa
## 6           5.4         3.9          1.7         0.4  setosa
## 7           4.6         3.4          1.4         0.3  setosa
## 8           5.0         3.4          1.5         0.2  setosa
## 9           4.4         2.9          1.4         0.2  setosa
## 10          4.9         3.1          1.5         0.1  setosa
## # ... with 140 more rows

なお,1行目で呼び出しているtidyverseパッケージは,この講義でも多用するdplyrreadrといったパッケージの「セット」を提供する.具体的に読み込まれるパッケージはこのウェブサイトで確認できる.それぞれのパッケージを個別に呼び出してもよいが,tidyverseを用いた方が単純に楽なのでこれを用いる.

さて,2行目で作成したtibbleクラスのオブジェクトiris_tibbleを3行目によって呼び出すと,各変数 (列) のデータタイプや行列の大きさが表示され,データの構造が簡単に確認できる.Rでは,dblは実数,fctrは (グループ化された) 文字列 というデータタイプであることを示す.Rに限らず,プログラミング言語では一般に多様なデータの「型」「タイプ」が区別される.Rにおけるデータ型の日本語による簡略な解説としては,このウェブサイトがある.

tibbleクラスのiris_tibbleの出力に対して,data.frameクラスのirisオブジェクトでは,下記のような情報しか見られない.

head(iris, n=10) ## irisの先頭10行を表示
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1           5.1         3.5          1.4         0.2  setosa
## 2           4.9         3.0          1.4         0.2  setosa
## 3           4.7         3.2          1.3         0.2  setosa
## 4           4.6         3.1          1.5         0.2  setosa
## 5           5.0         3.6          1.4         0.2  setosa
## 6           5.4         3.9          1.7         0.4  setosa
## 7           4.6         3.4          1.4         0.3  setosa
## 8           5.0         3.4          1.5         0.2  setosa
## 9           4.4         2.9          1.4         0.2  setosa
## 10          4.9         3.1          1.5         0.1  setosa

しかも,オブジェクトの先頭部分を表示するhead()関数 (デフォルトでは6行) を使わずにirisとだけコンソールに入力すると全部のデータが表示されてしまい,コンソールがいっぱいになってしまう. tibbleクラスを使っておけば,こうした点に悩まされることはない.

tibble::as_data_frame()関数を用いてもtbl_df()関数と同様の結果が得られることを確認しておこう.

as_data_frame(iris)
## # A tibble: 150 × 5
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
##           <dbl>       <dbl>        <dbl>       <dbl>  <fctr>
## 1           5.1         3.5          1.4         0.2  setosa
## 2           4.9         3.0          1.4         0.2  setosa
## 3           4.7         3.2          1.3         0.2  setosa
## 4           4.6         3.1          1.5         0.2  setosa
## 5           5.0         3.6          1.4         0.2  setosa
## 6           5.4         3.9          1.7         0.4  setosa
## 7           4.6         3.4          1.4         0.3  setosa
## 8           5.0         3.4          1.5         0.2  setosa
## 9           4.4         2.9          1.4         0.2  setosa
## 10          4.9         3.1          1.5         0.1  setosa
## # ... with 140 more rows

このように,dplyr::tbl_df()関数とtibble::as_data_frame()関数がしてくれることに差異はないので,どちらを用いてもよい (好みで使い分ければよい).ただし,単純に打つ文字数が少ないtbl_df()関数を用いることが多い.実際関数の中身を確かめても,次のようにtbl_df()as_data_frameを内部的に呼び出している (つまり結果だけでなく,関数の中身もまったく同じ).

tbl_df
## function (data) 
## {
##     as_data_frame(data)
## }
## <environment: namespace:dplyr>
as_data_frame
## function (x, ...) 
## {
##     UseMethod("as_data_frame")
## }
## <environment: namespace:tibble>

2.3 簡単な作図

せっかくサンプルデータを呼び出したので,ヒストグラムをいくつか描いてみる.

## default function
hist(iris_tibble$Sepal.Length, border="gray15", col="gray60", main="", xlab="Sepal.Length", breaks=30)

## using ggplot2 package
nbins = 25
ggfig = ggplot(iris_tibble, aes(Sepal.Length)) 
ggfig + geom_histogram(bins=nbins)

上の図にはRデフォルトの関数を使った場合,下の図にはggplot2パッケージを使った場合のプロットが出力されている.ggplot2パッケージには簡単に「それなりにかっこいい」図が作れるという利点があるが,ユーザが細かな調整をしにくいという欠点もある.デフォルトの関数とggplot2パッケージの関数の使い分けは好みだが,初学者はひとまずggplot2を使っておくとよい.なお,tidyverseパッケージを呼び出すとggplot2パッケージも自動的に呼び出されるので,tidyverseを呼び出した後にggplot2を個別に呼び出す必要はない.

ggplot2は様々な機能をもち,たとえばirisに記録されている植物の種類 (Species変数) 別にヒストグラムを並べて (ついでに色分けして) 描く,という作業も下記のコードで簡単にできる.

ggfig_facet = ggfig + geom_histogram(bins=nbins, aes(fill=Species), alpha=0.8) + facet_wrap( ~ Species)
ggfig_facet

背景のグレーが鬱陶しい場合は,theme_bw()を足してやればよい.

ggfig_facet + theme_bw()

ggplot2がデフォルトで提供するtheme_bw以外のテーマについては,英語だがこの記事を参照のこと.また,ggplot2theme_**を拡張する便利なパッケージに,ggthemesがある.このパッケージを仕様すると,theme_bw()以外の様々なテーマが利用できる.同じく英語だが,解説はこの記事を参照のこと.たとえば,次のようなテーマが利用できる.

library(ggthemes)
## 定番の統計ソフトウェアStataっぽいテーマ
ggfig_facet + theme_stata() 

## エクセルっぽいテーマ.ただの嫌味.いつ使うのか謎
ggfig_facet + theme_excel() 

## さっぱりしたテーマを2つ
ggfig_facet + theme_tufte()

ggfig_facet + theme_minimal()

これと同じことをデフォルトの関数でしようと思うと,それなりに手間がかかる (その代わり,自分の好きなように調整できる). 以下の記事のような,日本語でのggplot2パッケージのhow toはウェブ上にいくつも転がっているので,適宜参照することを勧める.

ggplot2の「勝手に色々設定される」機能が気持ち悪いなら,デフォルトの描画関数を使いこなそう.R界隈にも,頑なにggplot2を使わない人も存在するし,彼らのグラフが汚いということは決してない.

3 ファイルの保存 (書き出し)

さて,これらのデータは.csvや.txt等の形式で保存できる.ここでは,最も頻繁に用いられる.csv形式でサンプルデータを保存する方法を示す.データの保存はデフォルトのwrite.csv()関数でも行なえるが,色々と細かなオプションを指定してやる必要があり,正直面倒に感じる.readrパッケージのwrite_csv()関数を用いると細かなオプションや形式の指定を省略できる.ここではこの関数を用いて,irisデータを.csv形式で保存する.なお,ggplot2パッケージと同じく,tidyverseパッケージを呼び出すとreadrパッケージも自動的に呼び出される.

library(pathological)
# library(readr) ## tidyverseパッケージを読み込んでいれば「ついでに」読み込まれるので省略.実行してもいいが,tidyverseを既に読み込んでいれば意味はない
trgt_dir = "/Users/Gaku/Dropbox/040-ToyamaNIHU/090-ToyamaTeaching/sample_data" ## 保存先のディレクトリ:自分の環境に合わせて修正すること
create_dirs(trgt_dir)
## /Users/Gaku/Dropbox/040-ToyamaNIHU/090-ToyamaTeaching/sample_data 
##                                                             FALSE
path2csv = file.path(trgt_dir, "iris.csv") ## ファイル名を設定
write_csv(iris_tibble, path = path2csv)

create_dirs(trgt_dir)でファイル保存先のディレクトリを作成し,write_csv(iris_tibble, path = path2csv)iris_tibblepath2csvのパスに保存している. pathological::create_dirs関数は,存在しないディレクトリが指定された場合はディレクトリを作成し,既に存在するディレクトリへのパスが引数に指定された場合はFALSEを返す (ここでは既に当該ディレクトリが存在するので,FALSEが返ってきている).?pathologicalとRのコンソールに打てば,このパッケージが提供する他の便利な関数の解説が表示されるので,一読することを勧める. このコードで,“/Users/Gaku/Dropbox/040-ToyamaNIHU/090-ToyamaTeaching/sample_data”というディレクトリに,iris_tibbleが“iris.csv”という名前で保存された.

なお,R独自のデータ形式に,.rdsがある.この形式のデータは他のアプリケーションでは開けないという欠点があるが,Rのオブジェクトであれば「何でも」保存できるという利点がある.たとえば,空間データで用いられる.shp (shapeファイル) という形式のオブジェクトでも,.csvから読み込んだオブジェクトでも,すべて.rds形式で書き出し・読み込みができるので,Rを用いる上で重宝する.

iris_tibble.rds形式で保存するには,readr::write_rds()関数を用いればよい.

path2rds = file.path(trgt_dir, "iris.rds") ## ファイル名を設定
write_rds(iris_tibble, path = path2rds)

意図した場所に“iris.csv”と“iris.rds”というファイルが保存されているか,各自確認しておこう.

4 ローカルデータの読み込み

さて,上で.csvと.rds形式で保存したiris_tibbleを読み込むにはどうしたらよいだろうか.Rデフォルトのファイル読み込み関数にread.csv()関数やread.txt()関数があるが,readrパッケージの関数を用いた方が楽に作業できる.readrパッケージには,ファイルの書き出しに使ったreadr::write_csv()関数とreadr::write_rds()関数と対応する形で,readr::read_csv()関数とreadr::read_rds()関数というファイル読み込み関数がある.これらの関数を用いて保存したデータを読み込むには,次のコードを実行すればよい.

iris_csv = read_csv(path2csv)
iris_rds = read_rds(path2rds)

readr::read_csv()関数とreadr::read_rds()関数では,「どのファイルを読み込むか」を引数として与えてやればよい.上のコードでは,引数として与えたパスにあるファイルのデータが,左辺のオブジェクト iris_csv to iris_rds に格納される.正しく書き出し・読み込みが行われていれば,iris_tibble (元のオブジェクト), iris_csv (csvから読み込んだオブジェクト), およびiris_rds (rdsから読み込んだオブジェクト) の内容は一致するはずなので,確かめてみよう.

iris_tibble
## # A tibble: 150 × 5
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
##           <dbl>       <dbl>        <dbl>       <dbl>  <fctr>
## 1           5.1         3.5          1.4         0.2  setosa
## 2           4.9         3.0          1.4         0.2  setosa
## 3           4.7         3.2          1.3         0.2  setosa
## 4           4.6         3.1          1.5         0.2  setosa
## 5           5.0         3.6          1.4         0.2  setosa
## 6           5.4         3.9          1.7         0.4  setosa
## 7           4.6         3.4          1.4         0.3  setosa
## 8           5.0         3.4          1.5         0.2  setosa
## 9           4.4         2.9          1.4         0.2  setosa
## 10          4.9         3.1          1.5         0.1  setosa
## # ... with 140 more rows
iris_csv
## # A tibble: 150 × 5
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
##           <dbl>       <dbl>        <dbl>       <dbl>   <chr>
## 1           5.1         3.5          1.4         0.2  setosa
## 2           4.9         3.0          1.4         0.2  setosa
## 3           4.7         3.2          1.3         0.2  setosa
## 4           4.6         3.1          1.5         0.2  setosa
## 5           5.0         3.6          1.4         0.2  setosa
## 6           5.4         3.9          1.7         0.4  setosa
## 7           4.6         3.4          1.4         0.3  setosa
## 8           5.0         3.4          1.5         0.2  setosa
## 9           4.4         2.9          1.4         0.2  setosa
## 10          4.9         3.1          1.5         0.1  setosa
## # ... with 140 more rows
iris_rds
## # A tibble: 150 × 5
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
##           <dbl>       <dbl>        <dbl>       <dbl>  <fctr>
## 1           5.1         3.5          1.4         0.2  setosa
## 2           4.9         3.0          1.4         0.2  setosa
## 3           4.7         3.2          1.3         0.2  setosa
## 4           4.6         3.1          1.5         0.2  setosa
## 5           5.0         3.6          1.4         0.2  setosa
## 6           5.4         3.9          1.7         0.4  setosa
## 7           4.6         3.4          1.4         0.3  setosa
## 8           5.0         3.4          1.5         0.2  setosa
## 9           4.4         2.9          1.4         0.2  setosa
## 10          4.9         3.1          1.5         0.1  setosa
## # ... with 140 more rows

ざっと見た限り,3つのオブジェクトの内容は同じに見える(iris_csvのみ,Species変数がfctrではなくchrクラスだが,これはread_csv()関数デフォルトの仕様のため.簡単に変更可能).

しかし,目で見ただけでは見落としがあるかも知れないので,きちんと確かめてみよう.Rデフォルトのall.equal()関数やidentical()関数を用いてもよいが,単純に2つのオブジェクトが保持するデータの中身が一致するかを詳しくみる.

summary(iris_tibble==iris_csv)
##  Sepal.Length   Sepal.Width    Petal.Length   Petal.Width   
##  Mode:logical   Mode:logical   Mode:logical   Mode:logical  
##  TRUE:150       TRUE:150       TRUE:150       TRUE:150      
##  NA's:0         NA's:0         NA's:0         NA's:0        
##  Species       
##  Mode:logical  
##  TRUE:150      
##  NA's:0

==演算子は,左辺と右辺の内容が一致すればTRUEを,しなければFALSEを返す (つまり自然言語でいう“=”の意味).両辺が複数のデータコラムからなるオブジェクトだった場合,

head(iris_tibble==iris_csv, n=3)
##      Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## [1,]         TRUE        TRUE         TRUE        TRUE    TRUE
## [2,]         TRUE        TRUE         TRUE        TRUE    TRUE
## [3,]         TRUE        TRUE         TRUE        TRUE    TRUE

のように行列の各要素が保持する値が一致するかどうかを2値で示した行列を返してくれる (4行目以降の出力は省略).2つのデータが等しければ,すべての要素についてTRUEとなる.

この新たな行列についてsummary関数を適用すれば,各列がTRUE (一致する要素) とFALSE (一致しない要素) をどれだけ含むかという情報を取得できる. 上に示したsummary(iris_tibble==iris_csv)の出力をみると,結果はすべてTRUEなので,iris_tibbleiris_csvが保持するデータは完全に一致することが分かる (「iris_csviris_rds」のような,他のオブジェクトの組み合わせについては各自やってみる).

5 ウェブ上のデータの読み込み

さて,ここまでは,サンプルデータやローカル環境に保存したデータの読み込みを想定していた.しかし,ウェブ上には .csv や .txt ファイルが転がっている.これらのファイルをダウンロードすることなく,ウェブから直接Rに読み込みたい場合もある. こうしたウェブからの直接読み込みも,readr::read_csv()関数やその兄弟関数で簡単に行なえる.

ここでは,武力紛争の代表的なデータプロジェクトであるCorrelates of War (COW) projectが提供するデータセットを例に,この手順を説明する. COWでは武力紛争の生起や同盟など,多様なデータセットが提供されている.この中で,武力紛争 (COWではMiliterized Interstate Disputes, MIDs と呼ばれ,戦争だけでなく武力の威嚇・行使をはじめ国家間の緊張が高まった状態を指す) が生じた「場所」を記録した Militarized Interstate Dispute Locations (MIDLOC) がある.このデータセットはcsv形式でダウンロードできるようになっているが,これを直接Rに読み込むにはどうしたらよいだろうか.

まずは,RにMIDLOCのcsvファイルへのハイパーリンク (のURL) を教える.

csv_url = "http://www.correlatesofwar.org/data-sets/MIDLOC/midloc-1.1/at_download/file"

ローカル環境にあるcsvファイルを読み込むときには,当該ファイルへのパスをread_csv()関数の引数に与えていた.要は,「読み込みたいファイルの場所」を引数で与えていた. ウェブ上にあるファイルを読み込む際も同様に「読み込みたいファイルの場所」を引数にしてやればよいので,urlをread_csv()関数の引数にする.

midloc = read_csv(csv_url)

エラーは出ていないようだが,きちんと読み込めているだろうか.念のため確かめてみる.

midloc
## # A tibble: 4,152 × 11
##    dispnum incidnum  year month   day                mid21location
##      <int>    <int> <int> <int> <int>                        <chr>
## 1        2     2001  1902     7    -9       Alaska-Canadian border
## 2        3     3001  1913     5     2 Austria's border with Serbia
## 3        4     4001  1946     5    15                Corfu Channel
## 4        7     7001  1951    10    13              Suez canal zone
## 5        8     8001  1856     7    -9                         Iran
## 6        9     9001  1889    12    29        Waters off Mozambique
## 7       11    11001  1938     3    11              Austrian Border
## 8       12    12001  1938     3    11                            .
## 9       13    13001  1863     4     6                            .
## 10      14    14001  1895    10    15               Constantinople
## # ... with 4,142 more rows, and 5 more variables:
## #   midlocmeasuringpoint <chr>, latitude <dbl>, longitude <dbl>,
## #   precision <int>, onset <int>

無事,ウェブ上のデータをRに直接読み込めた.たとえばエクセルで同じ作業をしようと思うと,(1) ウェブサイトにアクセスして,(2) ファイルをダウンロードして,(3) ファイルをダブルクリックして,といった煩雑な手順を踏まなければならない.Rなら,上記のようにmidloc = read_csv(csv_url)とコンソールに入力するだけで済んでしまう.どちらの方法が早くて楽,かつミスもでないかは言うまでもない.

さて,MIDLOCは武力紛争が生じた場所の情報も記録している.せっかくなので,地図も書いておこう.

library(cshapes) ## 国境線データのパッケージ
library(sp) ## 空間データを扱うためのパッケージ
cshp_2015 <- cshp(date=as.Date("2015-1-1"), useGW=TRUE) ## 1.1.2015時点の国境線データ
midloc = as.data.frame(midloc) %>% ## 空間データに変換するためにdata.frameクラスに一度変換する
    ## 緯度経度が欠測値 (missing value) になっているデータを除く
    filter(
        !is.na(latitude), !is.na(longitude),
        longitude>-9999, latitude>-9999
        )
coordinates(midloc) = ~longitude + latitude ## 空間データ (ポイント・データ) に変換 (後ほど解説)
## 簡略な作図.綺麗にするにはもっと工夫が必要 (省略)
plot(cshp_2015, col="gray30", border=NA) ## 世界地図
points(midloc, cex=.2, pch=19, col="magenta") ## 武力紛争の場所