3章 dplyrによるデータ変換

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

library("tidyverse")
library("nycflights13")
library("gridExtra")

3.1 はじめに

練習問題はありません

3.2 filter()で行にフィルタをかける

練習問題1.1 : 到着が2時間以上遅れた

arr_delayは分単位なので、120分以上をフィルタします。

flights %>% 
  filter(., arr_delay >= 120)

# A tibble: 10,200 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>  
 1  2013     1     1      811            630       101     1047            830       137 MQ     
 2  2013     1     1      848           1835       853     1001           1950       851 MQ     
 3  2013     1     1      957            733       144     1056            853       123 UA     
 4  2013     1     1     1114            900       134     1447           1222       145 UA     
 5  2013     1     1     1505           1310       115     1638           1431       127 EV     
 6  2013     1     1     1525           1340       105     1831           1626       125 B6     
 7  2013     1     1     1549           1445        64     1912           1656       136 EV     
 8  2013     1     1     1558           1359       119     1718           1515       123 EV     
 9  2013     1     1     1732           1630        62     2028           1825       123 EV     
10  2013     1     1     1803           1620       103     2008           1750       138 MQ     
# … with 10,190 more rows, and 9 more variables: flight <int>, tailnum <chr>, origin <chr>,
#   dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

練習問題1.2 : ヒューストンへのフライト

or条件でdest == "IAH" | dest == "HOU"と指定します。

この選び方だと条件が多くなると見づらくなるので、dest %in% c("IAH", "HOU")で指定します。

指定したもの以外を抜き出す%nin%は実装されていないので、自分で作る必要があります。

練習問題1.3 : United, American, deltaのフライト

%in%で複数指定しますが、これだと正しくデータを取得できません。

理由は簡単で、実際に使われているのはキャリアコードだからです。実務でもよく起こるエラーです。実際に調べると、Deltaのキャリアコードは"DL"、Americanの場合"AA"、Unitedの場合です"UA"

キャリコードを指定して、フィルタします。

練習問題1.4 : 夏期(7~9月)のフライト

and条件でmonth >= 7, month <= 9と指定します。

month %in% 7:9と指定しても同じデータをフィルタできます。こうすることで簡潔に記述できます。

練習問題1.5 : 到着が2時間遅れたが、出発が遅れなかったフライト

練習問題1.6 : 遅延は少なくとも1時間を超えたが、運行で30分以上取り返したフライト

1時間以上遅延したものはdep_delay >= 60でフィルタでき、30分以上取り戻したものは、dep_delay - arr_delay > 30 となる。dep_delay - arr_delay == 0の場合、遅れた分、遅れて到着しているため。

練習問題1.7 : 深夜0時〜午前6時までのフライト

深夜0時は、dep_time == 0000ではないので、dep_time == 2400で指定します。

モジュロ演算を使用すればもう少し簡潔に表現できます。

練習問題2 : between()を使って、先程の問題を簡略化しなさい。

練習問題3 : dep_timeが欠損値のフライトはいくつあるか。

is.na(dep_time)TRUEかどうかを判定し、TRUEをフィルタします。

これだと欠損値の数がカウントできないので、カウントしたい場合はmap()を使うと簡潔。

練習問題4 : NA^0はなぜ欠損値にならないのか。

Rでは、NA^0 == 1となっています。したがって、Rではx^0 = 1となります。他には、下記のような特徴があります。

3.3 arrange()で行を配置する

練習問題1 : 欠損値を頭から並べるためにはarrange()をどう使えばよいか。

arrange()を使うとNAは最後に並べられます。なので、tail()でお尻のデータを表示させることでも、目的は達成できます。

desc(dep_time)では、NAから並べることはできません。

他の方法として、 NAをソートしてから、dep_timeを昇順にソートすることも可能です。

練習問題2 : flightsを並べて、遅延が最も大きなフライト、最も早朝に飛んだフライトを探す。

desc(dep_delay)で、降順に並び替えれば、遅延が最も大きいフライトを検索できます。出発は1301分遅れなので、21時間41分遅れです。

練習問題3 : flightsを並べて、最速のフライトを探す

20分ほどしかフライトしていないデータがあるようです。アメリカの土地勘がわからないですが、どの航路なんでしょうか。データから探索することで、誤入力かどうかを調べるのも良いかもしれません。

練習問題4 : flightsを並べて、最長距離のフライトを探す

幅の制限上、distanceが見えなくなるので、select()で先頭に持ってきています。最長フライトはHA 51のJFKからHNLで、4,983マイルなので8,020kmくらいでしょうか。

3.4 select()で列を選ぶ

練習問題1 : flightsからdep_time, dep_delay, arr_time, arr_delayを選ぶ方法をたくさん探しなさい。

変数名を指定する方法、列番号を指定する方法、文字列ベクトルを使う方法、ヘルパー関数を使う方法、正規表現を使う方法などが考えられます。列番号を指定する方法は、列を並び替えると意図した変数を選択できないので、推奨しません。

もし、この変数のセットをよく使うのであれば、変数名自体を変更することも良いかもしれません。文字列ベクトルを使う方法と似ています。

練習問題2 : select()において、変数名を繰り返すとどうなるのか。

変数名を繰り返しても、繰り返した分、取得できるわけではありません。特に、エラーや警告を出したりしないので、注意が必要です。

練習問題3 : one_of()は何をするのか。次のベクトルと一緒に使うとなぜ便利なのか。

文字列のベクトルで変数名を指定することができるので便利かと思います。select_if()の場合、文字列と整数列の1列だけを取得したい場合に困難ですが、このように文字列で指定しておけば自由に変数を取得できます。

下記のように使用することは、コードが明確ではなくなるので、推奨しません。arr_timeという変数名はデータの中に存在する変数名なので、それを文字列ベクトルの名前属性に割り当てるのは、混乱のもとなので、避けるべきです。推奨はしませんが、!!!演算子を利用し、評価の方法なども合わせて変更して違いを明らかにするべきですが、やはり非推奨です。

練習問題4 : 次のコードの実行結果は驚くものだが、select()のヘルパー関数は、デフォルトで大文字、小文字をどう扱うのか。

例えば、contains()start_with()は、デフォルトの設定では、文字の大小は問いません。これは、カラム名よりもデータの値を確認することが目的でselect()が使われるため、検索の簡便性を高めるという、思想を反映しているためかもしれません。また、MySQLなどのデータベースでは大小を区別しないという理由もあるかもしれません。

文字の大小を正確に判定させるためには、ignore.case = FALSEを設定します。

3.5 mutate()で新しい変数を追加する

練習問題1 : dep_time, sched_dep_timeを、深夜0時以降の分数のより便利な表現に変換しなさい。

例えばdep_timeは、分単位で記録されています。下記の例の一番上のレコードだと5時17分です。これを317分に変換するためには、100で割り、60を乗算し、残りのdep_timeを100 で割った値を加算します。

これだと24:00のレコードが1440になってしまうので、1440で割って2400を0に変換します。sched_dep_timeも同様に処理します。

練習問題2 : air_timearr_time - dep_timeと比べなさい。

air_time - (arr_time - dep_time)の差が0であるならば、飛行時間と(到着時間-出発時間)の記録が正しく記録されていることが期待できます。しかし、実際には大きくずれています。これは、日をまたいでいたり、タイムゾーンによる差異が影響しているのかもしれません。探索してみてください。

練習問題3 : dep_time, sched_dep_time, dep_delayを比べなさい。

dep_time - sched_dep_time = dep_delayとなるはずです。出発時刻から予定出発時刻を引けば、実際に出発で遅れた時間に対応するはずです。

しかし、実際には一致しないものも多く、何が原因か探索してみてください。

練習問題4 : 遅延が大きいフライトのランク付けしなさい。

{dplyr}のウインドウ関数を使えば、ランクをつけることができます。min_rank()はgapあり、dense_rank()はgapなしです。Gapとは、タイの順位があった場合にその次の順位を飛ばすか、飛ばさないかの違いです。ソートしなおせば、row_numbers()でも順位をふることは可能なので、目的に応じて使い分けてください。この例だと違いを見つけられませんが…。

top_n()という関数もありますが、こちらはデータの中からトップNのレコードを取得するのみなので、並び替えは行なわれません。

練習問題5 : 1:3 + 1:10は何を返すか。

これはRのリサイクル規則によって、長さが大きいベクトルの長さにあうように、短い方のベクトルが繰り返されます。

リサイクル規則を書き下すとこうなります。

練習問題6 : Rには、どのような三角関数が用意されているのか。

  • sin() : サイン・正弦関数

  • cos() : コサイン ・ 余弦関数

  • tan() : タンジェント ・ 正接関数

  • asin(): sin の逆関数

  • acos(): cos の逆関数

  • atan() : tan の逆関数

  • sinh() : ハイパボリックサイン

  • cosh() : ハイパボリックコサイン

  • tanh() : ハイパボリックタンジェント

  • asinh() : sinh の逆関数

  • acosh() : cosh の逆関数

  • atanh() : tanh の逆関数

3.6 summarise()によるグループごとの要約

練習問題1 : フライトのグループの典型的な遅延特性を評価しなさい。どれが重要でしょうか。

  • 50%は15分はやく、50%は15分遅い

  • 常に10分遅れる

  • 50%は30分はやく、50%は30分遅い

  • 99%が定時で、1%が2時間遅れとなる

どのケースが重要なのかどうか、考えてください。

練習問題2 : count()を使わずにnot_cancelled %>% count(dest)not_cancelled %>% count(tailnum, wt = distance)の同じ出力が得られる別の方法を考えなさい。

count()は、引数をグループ単位にしてカウントを行う関数なので、group_by()でグループ化し、summarise(n())で行数をカウントすれば同じことができます。また、summarise(n())ではなくtally()でも同じです。

count()関数を使用しますが、wt引数で重みが追加されているので、重みを調整(足し合わせる)します。

練習問題3 : キャンセル便の定義として(is.na(dep_delay) | is.na(arr_delay))は、最適ではありません。どうしてでしょうか?

出発して、到着しない場合があるためです。その場合、dep_delayNAではありません。最も重要な変数は到着の遅延量を表すarr_delayではないでしょうか。

練習問題4 : 日毎のキャンセル便数をカウントしなさい。なにかパターンはあるのか。ここでのキャンセルの定義は(is.na(arr_delay) | is.na(dep_delay))です。また、キャンセルされたフライトの割合は平均遅延に関連していますか?

キャンセルされたフライト数が総フライト数とともに増加することがわかりますが、そこまで強い相関などはなさそうです。

出発遅延の平均と到着遅延平均は、キャンセルされたフライトの割合との間には、増加する関係があります。

練習問題5 : 遅延に関して、どの航空会社が最悪か。

平均的に遅延時間が大きい航空会社はF9:Frontier Airlinesです。

練習問題6 : 飛行機ごとに、最初の1時間以上遅延する前の飛行回数をカウントしなさい。

質問の意図がいまいちわからないので、ここでは、1時間以上遅延する割合を航空会社ごとに算出します。

練習問題7 : sort引数はカウントに何をするのか。

sortはカウントを並び替えます。

3.7 グループごとの変更

練習問題1 : mutate(or filter)のグループ処理時の違いを教えてください。

mutate()は、グループ化することによって、グループ単位で関数が適用されます。

練習問題2 : どの飛行機(tailnum)が定時着陸記録に関して最悪なのか。

特に最悪についての指標が定義されていないので、100回以上フライトしており、到着時間が平均的に悪いものを最悪と考えます。 

練習問題3 : 遅延を避けるためには、どの時間帯がよいか。

フライトのスケジュールが早ければ早いほど、予想される遅延は短くなります。遅延が後のフライトに影響するのは直感的に理解できます。

練習問題4 : 目的地ごとに総遅延時間を分単位で計算しなさい。

LGA-ATLの航路がもっとも遅延が多い航路のようです。

練習問題5 : 遅延が発生した際に、次の便へのどの程度、影響するのか、lag()を使って調べなさい。

練習問題6 : データが誤って入力されたサンプルを探しなさい。

航路ごとに標準化した値を使って、異常な値を検索する方法も1つのやり方かもしれません。

練習問題7 : 少なくとも2つの航空会社が、運行している目的地を探しなさい。そして、この情報をもとに航空会社をランクしなさい。

複数の航空会社が運航するすべての空港を探し、次に、サービスを提供する目的地の数で航空会社にランクをふります。

最終更新

役に立ちましたか?