9月といえば台風の季節ですね。皆様、台風接近時には気象情報等をチェックして、くれぐれもご注意ください。
さて、NOAA (National Oceanic and Atmospheric Administration)のウェブサイトでは、世界中で起こった2015年までの主なストーム(嵐)についてのデータを公開しています。もちろん、日本の台風も含まれています。データのダウンロードは、こちらから行うことができます。今回は、このデータを使って、Exploratory Desktopを使って分析を行ってみたいと思います。
まず、地図上に表示してみる
まずは、実際にこのデータにはどのような情報が入っていて、どのようなことができるのかを調べてみます。データには、それぞれのストームの6時間ごとの位置の緯度経度情報と、その時点での風速、気圧などの情報が入ってます。そこで、まず単純に、ある年の緯度経度をもとに、Exploratory Desktopを使ってプロットしてみます。
ここでは、2012年のストームをすべてプロットしてみました。それぞれのストームごとのデータの点を線でつなぎ、経路がわかりやすいようにしてあります (注: この機能は現在開発中の次バージョンに実装予定です。皆様のお手元になるべく急いでお届けすべくチーム一同がんばっていますので、いましばらくお待ち下さい) 。また、わかりやすいように地域ごとに色分けしてあります。これだけでも、ストームというのは世界のどの地域でどのくらい発生しているのか、というのがひと目でわかり、とても興味深いのではないかと思います。この年アメリカでは、Sandyというハリケーンが大きな被害を及ぼし、アメリカでは大きなニュースになりました。
過去10年の大きな台風を調べる
次に、東アジア、東南アジア地域で主に発生するストーム、いわゆる台風について調べてみたいと思います。台風の勢力の目安となる指標は気圧と風速がありますが、ここでは、より被害に直結する風速に注目したいと思います。
ここで一つ問題になるのは、このNOAAの提供するデータには、いわゆる「台風◯号」というデータが無い、ということです。幸い、全てのストームには国際的に用いられる英語の名前がつけられていて、この名前と、いわゆる「台風◯号」との対応表が気象庁のページに公開されているので、これを、Webページから直接データを取ってくる「Webスクレイピング」という機能を使って、これをデータとしてインポートします。これの操作は、すべてUIから行うことができます。必要なのは、このページのURLだけです。
インポートが完了したら、このデータを先ほどのストームのデータと結合することで、見慣れた台風の名前を地図上に表示することができます。
データが揃ったところで、まず、2005年から2015年までの10年のあいだで、最大風速がもっとも大きかった台風のトップ10を調べてみたいと思います。トップ10を調べるには、台風ごとにデータをグループ化してそれぞれの最大風速を集計し、そのトップ10データをもって元データをフィルタする、というラングリング(処理)を行います。詳細は文末のスクリプトをご参照ください。過去10年の台風トップ10は、以下のようになりました。
10位タイのデータが10件あったので、実際には19個の台風が表示されています。それぞれの台風の名前の横の数字は、それぞれの台風の風速の最大値(m/秒)です。
日本に上陸した台風を調べる
この地図を見ただけでも日本に上陸したかどうか、というのは割と自明ですが、ここで厳密に、上陸したかどうかというのをデータを用いて確認したいと思います。国立情報学研究所の北本さんによるデジタル台風、というサイトに、過去に上陸した台風のデータがHTMLのテーブル形式で公開されていますので、こちらを先ほどと同様にUIでWebスクレイピングしてでデータをインポートします。インポートができたら、「上陸」というデータだけをフィルタし、その結果を先ほどのトップ10データに適用することで、この中で日本に上陸した台風、をデータから導くことができます。
具体的にどのようなデータを用いて、どのようなステップでこのデータを作っているか、というのは こちらからみることができます。Exploratoryを既にお持ちであれば、EDFというファイルをダウンロードしてインポートすることで、ここで用いられているデータやチャートが全てExploratory上に再現できますので、よかったら試してみてください。
過去10年の勢力の強い台風19個のうち、上陸したのは4個、というのがわかりました。割合としては20%強となります。上陸したのはいずれも、カテゴリー5に属する、いわゆるスーパータイフーンと呼ばれるものですが、その中でも2014年の台風19号は、ひときわ最大風速が大きいのがわかります。実際、この台風は日本列島を縦断し、死者は3名、負傷者は重軽傷含め94名を出した猛烈なものでしたので(Wikipediaより抜粋)、ご記憶の方も多いのではないかと思います。
まとめ
NOAAの提供するストームのデータを元に、Webスクレイピングによって必要なデータを付加してゆくことで、台風に関する様々なことがわかりました。また、そのデータを地図上に可視化することで、より直感的に、より身近にデータを理解できたのではないかと思います。また、私だったらこうしてみる、私だったらここを調べたい、というアイデアが湧いた方も多いのではないかと思います。もしそう思った方は、ぜひ、Exploratoryをダウンロードして試してみてください。サインアップ、および最初の30日間の使用は無料です。サインアップはこちらからできます。
データ分析をさらに学んでみたいという方へ
今年10月に、Exploratory社がシリコンバレーで行っている研修プログラムを日本向けにした、データサイエンス・ブートキャンプの第3回目が東京で行われます。上記のようなデータサイエンスの手法を、プログラミングなしで学んでみたい方、そういった手法を日々のビジネスに活かしてみたい方はぜひこの機会に、参加を検討してみてはいかがでしょうか。こちらに詳しい情報がありますのでぜひご覧ください。
スクリプト
手順を再現するためのRスクリプトです。Exploratoryを既にお持ちの方は、こちらからEDFファイルをダウンロードしてインポートすることで、自動的に全て復元することができます。
# Set libPaths.
.libPaths("/Users/kei/.exploratory/R/3.4")
# Load required packages.
library(janitor)
library(lubridate)
library(hms)
library(tidyr)
library(stringr)
library(readr)
library(forcats)
library(RcppRoll)
library(dplyr)
library(tibble)
library(exploratory)
# Custom R function as Data.
typhoon_names.func <- function(){
df2005 <- exploratory::scrape_html_table("http://www.jma.go.jp/jma/kishou/know/typhoon/1-6.html", 12, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
rename(number = `2005`, name = `20051`) %>%
mutate(year=2005)
df2006 <- exploratory::scrape_html_table("http://www.jma.go.jp/jma/kishou/know/typhoon/1-6.html", 11, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
rename(number = `2006`, name = `20061`) %>%
mutate(year=2006)
df2007 <- exploratory::scrape_html_table("http://www.jma.go.jp/jma/kishou/know/typhoon/1-6.html", 10, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
rename(number = `2007`, name = `20071`) %>%
mutate(year=2007)
df2008 <- exploratory::scrape_html_table("http://www.jma.go.jp/jma/kishou/know/typhoon/1-6.html", 9, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
rename(number = `2008`, name = `20081`) %>%
mutate(year=2008)
df2009 <- exploratory::scrape_html_table("http://www.jma.go.jp/jma/kishou/know/typhoon/1-6.html", 8, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
rename(number = `2009`, name = `20091`) %>%
mutate(year=2009)
df2010 <- exploratory::scrape_html_table("http://www.jma.go.jp/jma/kishou/know/typhoon/1-6.html", 7, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
rename(number = `2010`, name = `20101`) %>%
mutate(year=2010)
df2011 <- exploratory::scrape_html_table("http://www.jma.go.jp/jma/kishou/know/typhoon/1-6.html", 6, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
rename(number = `2011`, name = `20111`) %>%
mutate(year=2011)
df2012 <- exploratory::scrape_html_table("http://www.jma.go.jp/jma/kishou/know/typhoon/1-6.html", 5, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
rename(number = `2012`, name = `20121`) %>%
mutate(year=2012)
df2013 <- exploratory::scrape_html_table("http://www.jma.go.jp/jma/kishou/know/typhoon/1-6.html", 4, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
rename(number = `2013`, name = `20131`) %>%
mutate(year=2013)
df2014 <- exploratory::scrape_html_table("http://www.jma.go.jp/jma/kishou/know/typhoon/1-6.html", 3, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
rename(number = `2014`, name = `20141`) %>%
mutate(year=2014)
df2015 <- exploratory::scrape_html_table("http://www.jma.go.jp/jma/kishou/know/typhoon/1-6.html", 2, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
rename(number = `2015`, name = `20151`) %>%
mutate(year=2015)
bind_rows(df2005,df2006,df2007,df2008,df2009,df2010,df2011,df2012,df2013,df2014,df2015) %>%
mutate(id = str_c("20", number), jname = str_sub(number, 3,4), jname = extract_numeric(jname), jname = str_c("台風", parse_character(jname), "号"), name = str_to_upper(name))
}
# Steps to produce typhoon_landed
`typhoon_landed` <- exploratory::scrape_html_table("http://agora.ex.nii.ac.jp/digital-typhoon/disaster/landfall-full/index.html.ja", 5, "TRUE" ,encoding="Unicode (UTF-8)") %>% exploratory::clean_data_frame() %>%
filter(種別 == "上陸") %>%
rename(id = 台風番号) %>%
mutate(id = parse_character(id))
# Steps to produce typhoon_names
`typhoon_names` <- typhoon_names.func() %>% exploratory::clean_data_frame() %>%
mutate(id = parse_character(id))
# Steps to produce branching_point_1
`branching_point_1` <- exploratory::read_delim_file("/Users/kannishida/Downloads/Allstorms.ibtracs_all.v03r09.csv" , ",", quote = "\"", skip = 1 , col_names = TRUE , na = c("","NA") , locale=readr::locale(encoding = "UTF-8", decimal_mark = "."), trim_ws = FALSE , progress = FALSE) %>% exploratory::clean_data_frame() %>%
slice(-1) %>%
select(Serial_Num, Season, Num, Name, ISO_time, Latitude, Longitude, `Wind(WMO)`, Basin) %>%
mutate(Season = extract_numeric(Season)) %>%
mutate(Latitude = extract_numeric(Latitude), Longitude = extract_numeric(Longitude)) %>%
filter(Latitude != -999) %>%
mutate(ISO_time = ymd_hms(ISO_time), Name = ifelse( Latitude<0 & Name=="KATE", "KATE(1)", Name )) %>%
inner_join(typhoon_names, by = c("Season" = "year", "Name" = "name")) %>%
group_by(id) %>%
mutate(`Wind(WMO)` = parse_number(`Wind(WMO)`), wind = as.integer(`Wind(WMO)`/ 1.943844), max_wind = max(wind))
# Steps to produce top10wind
`top10wind` <- branching_point_1 %>%
summarize(maxwind = max(`Wind(WMO)`, na.rm = TRUE)) %>%
top_n(10, maxwind)
# Steps to produce the output
branching_point_1 %>%
ungroup() %>%
mutate(jname_full = str_c(Season, ' ', jname, ' ', as.character(max_wind), 'm/s'), jname_year = str_c(Season, ' ', jname)) %>%
semi_join(top10wind, by = c("id" = "id")) %>%
semi_join(typhoon_landed, by = c("id" = "id"))