9章 tidyrによるデータの整理

9.0 ライブラリーの読み込み

library("tidyverse")

9.1 はじめに

練習問題はありません

9.2 整理データ

練習問題1 例に上げた表について、変数と観測値がどのように組織されているか答えなさい。

各行は(国、年)の組み合わせを表します。列casespopulationは、それらの変数の値を含みます。いわゆるtidyな形式です。

table1
# A tibble: 6 x 4
  country      year  cases population
  <chr>       <int>  <int>      <int>
1 Afghanistan  1999    745   19987071
2 Afghanistan  2000   2666   20595360
3 Brazil       1999  37737  172006362
4 Brazil       2000  80488  174504898
5 China        1999 212258 1272915272
6 China        2000 213766 1280428583

各行は(国、年、タイプ)の組み合わせを表します。countには、各typeの値を含みます。

各行は(国、年)の組み合わせを表します。カラムは、casespopulationの値を文字列として持つrateがあります。

変数ごとに表が分かれています。この表table4aにはcasestable4bにはpopulationの値が含まれています。日本のお役所のデータによく見られる形式で、人間には見やすいが、機械には読みにくい形式です。

練習問題2 table2table4a+table4bについてrateを計算しなさい。下記、4つの操作を実行する必要がある。どの表現が最も簡単で、どれが一番難しいか?

  • 国ごとの年間の結核の症例数を抽出します。

  • 1年ごとに国ごとに一致する人口を抽出します。

  • ケースを母集団で割り、10000を掛けます。

  • 適切な場所に戻して保管してください。

本来はこのように加工したいですね。spread()を使い、素直にカラムを横に展開すれば3行で計算できます。以下は、あまり推奨されない加工です。

1人当たりの症例数を計算するには、国と年の単位で、症例数を人口で割る必要があるので、そこを目標にtable2を加工します。table2を分割してbind_cols()で結合し直してますが、このような簡単にデータを揃えられない場合もビジネスのデータでは多いので、その際は**_join()を使ったほうがいいと思います。**_join()はデータが多くなると、検索で処理が重くなるので、その点はトレードオフです。

tablea4atable4bを使う方はこのような感じでしょうか。わざと%>%{dplyr}を使っているのでくどいですね。このように計算するのであれば、{dplyr}は使わないほうが簡潔かもしれません。

練習問題3 table1の代わりにtable2を使用して、casesの時系列プロットを再作成しなさい。

9.3 広げたり集めたり

練習問題1 gather()spread()はなぜ対象ではないのか。

gather()を適用する際に、列のデータ型の情報が失われます。その点で対象ではありません。

convert = TRUEを設定すれば、ベクトルを適切な型に変換してれますが、この変換は単に変数の型を推測しているだけなので、常に元の変数型を返すわけではありません。

練習問題2 このコードが失敗するのはなぜですか?

データフレームから変数を選択するとき、gather()は1999や2000のような数を列番号として解釈します。この場合、gather()はデータフレームの1999番目と2000番目の列を選択しようとします。1999と2000のような非構文変数名を選択するには、名前をバッククォート(`)で囲むか、文字列として指定します。

練習問題3 なぜこのtibbleを広げると失敗するのでしょうか。

spread()でkeyを展開した際に、1行目と3行目のPhillip Woodsのageを一意に特定できないので、どちらの行にvalueが入れば適切なのか判別できません。

このような場合は、一意に特定するための複合主キーを作成します。

練習問題4 このtibbleを整理しなさい。

こんな感じにtidyにするのはどうでしょうか。

9.4 分割と接合

練習問題1 separate()extrafillは何をするのでしょうか。

separate()extra = "drop"はカラムが不足している場合、その値をドロップします。

separate()extra = "merge"はカラムが不足している場合、その値を残します。

この例では、2行目の要素が少ないため、NAが発生します。

separate()fill = "right"は要素が少ない場合、どちらから値を埋めるかを設定できます。

練習問題2 unite()separate()には、引数removeがあります。それは何をするためのものか?

デフォルトでは、remove = TRUEとなっており、結合または分割の対象カラムを残すかどうかを設定できます。

練習問題3 separate()extract()を比較しなさい。

extract()は正規表現を使用して文字ベクトル内のグループを指定し、その単一文字ベクトルを複数の列に分割します。separate()と比べると、共通の区切り記号や特定の列位置を必要としないので、柔軟です。

9.5 欠損値

練習問題1 fill引数をspread()complete()で比較しなさい。

spread()fillは、特定の値で欠損値を補完することが可能です。

complete()fillは、特定の値をリストで指定し、欠損値を補完することが可能です。

練習問題2 fill().dirctionは何をするのか。

fill().directionは、欠損値をレコードの上の値を使って補完するのか、下の値を使って補完するのかを設定します。

9.6 ケーススタディ

この章で使われているコードを先に実行しておきます。

練習問題1 このケーススタディでは欠損値をna.rm = TRUEで削除したが、これは妥当か。

妥当かどうかの判断はデータから判断できるのかもしれません。0自体はデータに含まれているので、欠損値は結核が0件ということを意味するのではなく、データが取得できない欠損といえます。なので、欠損値を除外しても良いのではないでしょうか。

また、欠損値として認識できる行もありますが、全ての国で、全ての年代があるわけでないようです。なので暗黙的な欠損がデータ自体に存在しています。

調べてみると、たくさんの国のデータが暗黙的に欠損しているというよりも、特定の国のデータがごそっと抜けていてるようですね。

練習問題2 mutate(key = str_replace(key, "newrel", "new_rel")を無視するとどうなるのか。

separate()は、分割後の要素が少ないというエラーが発生します。

練習問題3 iso2iso3countryと重複していたが、これを確認しなさい。

group_by()の単位にcountryをいれても入れなくてもカーディナリティは変わりません。なので、countryiso2 or iso3は同じような値を持っています。

練習問題4 各国、年、性別について結核の総症例数を計算し、可視化しなさい。

国の数を考えるとファセットや色分けは難しいので、一旦国ごとに男女でわけで時系列推移を確認します。特定の年代にスパイクが確認できます。

性別に関わらず、総結核数が多い上位10カ国を抜き出して見てみます。インドと中国の増加の仕方は異なります。インドは突発的に結核が増えた一方で、中国は増加したまま結核数が減少していないようです。

9.7 非整理データ

練習問題はありません

最終更新

役に立ちましたか?