はじめに
先日、以下の記事で、2001年以降の台風位置表 CSV を用いて、台風の位置と勢力の関係を概観してみました。
一方、2001年より前の台風データについては、気象庁から「ベストトラック(Best Track)」というデータで提供されています。今回は、こちらのデータを用いて、1951年~2023年現在までの台風の位置と勢力について、見てみたいと思います。
データの入手と加工
気象庁の以下のページでデータを入手可能です。
1951年~現在(2023年)までの台風データがひとつのテキストファイルにまとまっています。一方、2001年以降の台風位置表 CSV とは異なり、整然データとはなっておりません。
データフォーマットについては、以下のページに掲載されています。
簡単に言うと、各台風の情報(台風番号や名称など)を記載した行の後ろに、その台風の各位置における情報(経度、緯度、中心気圧など)が、1つの位置につき1行掲載されています。位置の情報だけ見れば整然データとなっています。以下はイメージです。
台風の情報
位置の情報
位置の情報
・・・
位置の情報
台風の情報
位置の情報
位置の情報
・・・
位置の情報
・・・
ただし、各行について、タブやコンマといった区切り文字があるわけではなく、厳密に各情報が記載される文字の位置が決まっています。たとえば、以下の各台風の情報となりますが、台風の名称は HHHHHHHHHHHHHHHHHHHH
で記載された31文字目~50文字目に記載されています。各情報は空白を含む場合の他、空白だけの場合もありえるので、スペースなど(正規表現では \s
)で区切る手法は使うことができないです。
なお、各台風の情報の、先頭の AAAAA
は固定で 66666
となっていますので、この部分を使って、台風毎の情報か、各位置の情報かを識別することになりそうです。
5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80
::::+::::|::::+::::|::::+::::|::::+::::|::::+::::|::::+::::|::::+::::|::::+::::|
AAAAA BBBB CCC DDDD EEEE F G HHHHHHHHHHHHHHHHHHHH IIIIIIII
5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80
::::+::::|::::+::::|::::+::::|::::+::::|::::+::::|::::+::::|::::+::::|::::+::::|
AAAAAAAA BBB C DDD EEEE FFFF GGG HIIII JJJJ KLLLL MMMM P
今回、今後の解析をしやすくするために、各台風の情報(台風番号や名称)を取り出して、各位置の情報に付与して、整然データとなっている CSV を作成しました。各情報について、JavaScript を用いた正規表現で取り出すことします。正規表現は以下の通りです。
// 変数 line は各行の文字列とする。
// 台風毎の情報
const m = line.match(/^66666 (.{4}) (.{3}) (.{4}) (.{4}) (.) (.) (.{20}) (.{8})/);
// 各位置の情報
const c = line.match(/^(.{8}) (.{3}) (.) (.{3}) (.{4}) (.{4}) (.{3}) (.)(.{4}) (.{4}) (.)(.{4}) (.{4}) (.)/);
ベストトラックデータから情報を取り出し、整然データ CSV として保存するコード全体は以下のようになります。
const fs = require('fs');
// ベストトラック("bst_all.txt")のデータを読み込み
const text = fs.readFileSync("bst_all.txt", "utf-8");
let csv = "台風識別,日時,緯度,経度,中心気圧,最大風速,50kt長径方向,50kt長径,50kt短径,30kt長径方向,30kt長径,30kt短径,上陸"
+ "\n";
let tInfo = "";
text.split(/\n/).forEach( line => {
if(!line) return;
if(!line.match(/\d/)) return;
if(line.match(/^66666/)){
const m = line.match(/^66666 (.{4}) (.{3}) (.{4}) (.{4}) (.) (.) (.{20}) (.{8})/);
const yy = m[1].slice(0,2);
const tt = m[1].slice(2,4);
let year = (yy>50) ? "19" + yy : "20" + yy;
// "{年(yyyy)}T{台風番号}_{国際名}" 形式で識別子とする
tInfo = year + "T" + tt + "_" + m[7].replace(/\s+/, "");
return;
}
const c = line.match(/^(.{8}) (.{3}) (.) (.{3}) (.{4}) (.{4}) (.{3}) (.)(.{4}) (.{4}) (.)(.{4}) (.{4}) (.)/);
if(c){
csv += `${tInfo},${c[1]},${c[4]/10},${c[5]/10},${c[6]},${c[7]},${c[8]},${c[9]},${c[10]},${c[11]},${c[12]},${c[13]},${c[14]}` + "\n";
}
});
fs.writeFile(`./tyhoon-bst.csv`, csv, (e) => {
if(e) console.error(e);
});
なお、JavaScriptでこれらのデータを処理する場合、slice()
の方が高速かつデータ提供者の意図に合っているかもしれませんが、正規表現の処理でもそんなに時間はかからなかったので、このまま進めました。
データの観察
提供されているデータフォーマットを整然データとするまでの処理が異なりましたが、これ以降の作業は、前回の記事とは大きく変わりませんので、前回行った内容から、位置(経緯度)と勢力(中心気圧)にポイントを絞って見ていきたいと思います。
各位置の情報として、1951年であっても、経度・緯度、中心気圧は提供されていますが、最大風速や上陸の有無のフラグといった情報は、どうやら途中から追加されているようです。たとえば、上陸フラグは1991年以降のデータにしか見られません。これらの情報がいつから追加されているのかは、気象庁の Web ページでは見つけることができていません。
まずは、経緯度と中心気圧をプロットしてみます。ツールは、R を用いています。
# 整然データへ変換した CSV ("tyhoon-bst.csv")の読み込み
tdf <- read.csv("tyhoon-bst.csv", header=TRUE)
pairs(tdf[,c(3,4,5)], panel = panel.smooth)
次に、緯度と中心気圧について、詳しく見てみます。
plot(tdf$緯度, tdf$中心気圧, col=1, type = "p", main="緯度と中心気圧の関係")
abline(v=35.5, col="red") #東京湾
abline(v=33.5, col="red", lty=2) #紀伊半島
abline(v=31, col="red", lty=2) #大隅半島
abline(v=30, col="red") #30度
abline(v=26.2, col="red", lty=2) #那覇市
abline(h=911.8, col="red") #室戸台風
abline(h=929.6, col="red") #伊勢湾台風
abline(h=940, col="red", lty=2) #中心気圧 940 hPa
abline(h=965, col="red", lty=2) #中心気圧 965 hPa
2001年以降の台風でも注目していた「プロットがされていない領域」ですが、今回も東京湾相当の緯度より北においては、約940 hPa 以下の台風がプロットがされていません。そのため、1951年以降、東京湾に相当する緯度帯に伊勢湾台風級(約930 hPa)の経験はないということが分かります。(なお、前記事からの繰り返しになりますが、今後も来ないとは言っていないです。)
紀伊半島周辺の緯度帯ですと、930 hPa 以下のプロットも見られます。
なお、中心気圧 940 hPa くらいになると、高緯度でもプロットが見られます。以下は、北緯30度より北において、930 hPa 以下、940 hPa 以下となった位置をプロットしたものです。
台風経路を地図上でプロット
前回の記事と同様に今回も、データを GeoJSON へ変換し、ウェブ地図上で見ることができるようにしています。
(追記)
経路だけでなく、各位置の情報もポイントデータとして表示できるようにしました。点の色を中心気圧によって変えています。また、中心気圧で絞り込みをできるようにしています。以下は、東京周辺で 965 hPa 以下となった地点を絞り込んだ例です。
各位置の情報は、経路のラインデータと比べてデータ量が非常に大きくなります。そのため、そのまま GeoJSON データとして配信するのは避け、ベクトルタイルとしています。ホストする際は、PMTiles として、1つのファイルをサーバ(GitHub レポジトリ)へアップロードすれば良いようにしています。便利です。
ランキング
各台風の中心気圧の最小値を並べてみました。
トップにランクインした昭和54年台風第20号は、観測史上世界で最も低い気圧となっているようです。気象庁によれば、全国各地で暴風が吹き、北海道の東部では漁船の遭難が相次ぎ、67名の死者・行方不明者が出たとのことです。
4位は昭和33年の狩野川台風です。気象庁によれば、北緯30度線を越えたあたりから急速に衰えたため、風による被害は少なかったとのことですが、伊豆半島中部では、特に集中して雨が降り、大量の水が流れ込んだ狩野川が氾濫、伊豆地方だけで1,000名を超える死者が出ました。
行ラベル | 最小 / 中心気圧 |
---|---|
1979T20_TIP | 870 |
1973T15_NORA | 875 |
1975T20_JUNE | 875 |
1958T22_IDA | 877 |
1966T04_KIT | 880 |
1978T26_RITA | 880 |
1984T22_VANESSA | 880 |
先ほどの緯度と中心気圧の関係を示した図に、トップ4までの台風及び伊勢湾台風、第二室戸台風の変遷を追記してみました。(トップ4:青、伊勢湾台風:赤、第二室戸台風:黄色。)
tdf2 <- subset(df, df[,1]=="1979T20_TIP")
lines(tdf2$緯度, tdf2$中心気圧, col=4, lwd=4)
tdf2 <- subset(df, df[,1]=="1973T15_NORA")
lines(tdf2$緯度, tdf2$中心気圧, col=4, lwd=4)
tdf2 <- subset(df, df[,1]=="1975T20_JUNE")
lines(tdf2$緯度, tdf2$中心気圧, col=4, lwd=4)
tdf2 <- subset(df, df[,1]=="1958T22_IDA")
lines(tdf2$緯度, tdf2$中心気圧, col=4, lwd=4)
tdf2 <- subset(df, df[,1]=="1959T15_VERA")
lines(tdf2$緯度, tdf2$中心気圧, col=2, lwd=4)
tdf2 <- subset(df, df[,1]=="1961T18_NANCY")
lines(tdf2$緯度, tdf2$中心気圧, col=7, lwd=4)
大隅半島以北~東京湾周辺の緯度帯を見ると、これらの観測史上上位の最低気圧を記録した台風に比べて、伊勢湾台風、第二室戸台風の方が、中心気圧が低いことが分かります。当たり前かもしれませんが、注目する地域において、台風勢力がどの程度か、という視点を持つことは重要かと思います。
また、中心気圧だけで被害が決まるわけでもないかと考えられます。たとえば、上記で引用した通り、狩野川台風は、日本上陸前に勢力が衰えたようですが、前線が活発化しながら北上したため、東海地方と関東地方では大雨となったようです。
レポジトリ
ウェブ地図用のソース、GeoJSON への変換コード、R スクリプトを置いています。
感想
台風位置表とは異なり、独自フォーマットの気象庁ベストトラックでしたが、それでもデータ構造自体は機械判読できるものであり、時間をかけずに処理を行うことができました。このような情報が提供されていることは、ありがたい限りです。
一方、日本語での説明が少ないことや、上陸フラグ等、年次ごとに取得された情報についての説明が少ない点(どこかにあるのかもしれませんが、ダウンロードページ周辺では見つけられず……)が気になりました。いったん記事にはしてみましたが、自分ももう少しリテラシーを高めるべく、色々と周辺情報を調査してみたいと思います。
また、台風の統計がとられているのが、まだ100年経っていないことに少し意外な気持ちになっています。現在、気象庁提供データの台風の識別情報は、西暦の下2桁+台風番号となっておりますが、100年経つとこれが衝突するので、その際にどうするのか、これも気になるところです。