LoginSignup
1
1

GoogleとAppleのモビリティデータを用いたCOVID-19分析

Last updated at Posted at 2023-07-11

はじめに

職場でデータ分析の練習をする機会があり、モビリティデータの解析をテーマに分析を行いました。
Pythonでの分析を実施し、その流れをまとめています。

目次

1. 対象データ
2. Community mobility reports(Google) -国内版
3. Community mobility reports(Google) -国外版
4. Mobility trends reports(Apple)

1. 対象データ

・Community mobility reports(Google)
小売店、食料品、公園、公共交通機関、職場、居住空間の人出に関する時系列データです。
https://www.google.com/covid19/mobility/?hl=ja

以下はデータに関する概要と注意点の抜粋です。(上記URLより抜粋)

レポートは、ロケーション履歴の設定(デフォルトではオフ)をオンにしているユーザーから集計された匿名のデータセットを使用して作成されています。

基準値からの変化を信頼性と匿名性を確保した方法で推測するのに十分なデータがない場合は、空白が生じます。

地域間で場所を比較しないようにしてください。地域によってデータに違いが生じることがあるため、誤った解釈を招く可能性があります。

データは、各カテゴリに分類された場所への訪問者(またはその場所に滞在した時間)が曜日別基準値と比べてどう変化したかを示すものです。曜日別基準値は、該当する曜日の標準値を表します。具体的には 2020 年 1 月 3 日〜2 月 6 日の 5 週間の曜日別中央値です。

各地域の各カテゴリごとに、基準値は 1 つではなく、7 つあります。曜日が異なれば、訪問者数が同じであっても増減率は異なります。そのため、以下の点にご留意ください。

・値が大きい方が訪問者数が多いわけではなく、小さい方が訪問者が少ないわけでもない。
・日単位で変化を比較しない。特に週末と平日を比較しない。

※地域間の比較は推奨されていませんが、今回は練習として実施します。
また、公園には国有林や城、キャンプ場などが、公共交通機関にはタクシー乗り場やSA、海港なども含まれます。

・mobility trends reports(Apple)
人々の移動方法(車、公共交通機関、徒歩)の推移を表す時系列データです。
※2022年4月14日の時点で、AppleはCOVID-19モビリティトレンドレポートを提供しなくなりました。
https://covid19.apple.com/mobility

以下はデータに関する概要です。(https://response.jp/article/2020/04/16/333686.html より抜粋)

Appleマップで経路が検索された回数と収集されたデータとを比較することで、徒歩、自動車、公共交通機関での人の移動量の変化として世界各地のデータに反映される。

いずれも移動量の絶対値ではなく、基準(コロナ前の水準)と比較した、相対的なデータになるのが特徴です。

国、州、都道府県ごとにデータがありますが、
国同士の比較と、日本国内においては都道府県での比較を行います。

中でもAppleの公共交通機関に関するデータが少なかったため、
今回はAppleの公共交通機関のデータがある国(=全てのデータがある国)に限って分析を行いました。

いずれもデータの期間は2020/2/15-2022/3/31です。

2. Communitiy mobility reports(Google) -国内版

まず、国内(都道府県ごと)のデータを分析します。

データの整形

とりあえず使いそうなライブラリをインポートします。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa import stattools as tsat
import statsmodels.graphics.api as smg
import statsmodels.graphics.tsaplots as tsap

import statsmodels.api as sm
import seaborn as sns

csv形式からdataframe形式に変換します。
日本国内のデータには「jp」と頭に付けていますが、世界各国のデータを扱う際には「world」を頭に付けました。

jp_park = pd.DataFrame(jp_park_csv)
jp_station = pd.DataFrame(jp_station_csv)
jp_retail = pd.DataFrame(jp_retail_csv)
jp_grocery = pd.DataFrame(jp_grocery_csv)
jp_workplace = pd.DataFrame(jp_workplace_csv)
jp_residential = pd.DataFrame(jp_residential_csv)

データには個人が特定されないようにするために、一部データに欠損があります。
そのため、データの欠損部分を前後の値から補完します。
今回はデフォルトの線形補完を行いました。

jp_park = jp_park.interpolate()
jp_station = jp_station.interpolate()
jp_retail = jp_retail.interpolate()
jp_grocery = jp_grocery.interpolate()
jp_workplace = jp_workplace.interpolate()
jp_residential = jp_residential.interpolate()

国内のデータには日本全体のものと、各都道府県のデータがあります。
今回は都道府県ごとに比較を行うため、日本全体のデータは削除します。

del jp_park["japan"]
del jp_station["japan"]
del jp_retail["japan"]
del jp_grocery["japan"]
del jp_workplace["japan"]
del jp_residential["japan"]

データの可視化

retail

fig_jp_retail = plt.figure(figsize = (12,8))
ax = fig_jp_retail.add_subplot(111)

columns = list(jp_retail.columns)
del columns[0]
x = jp_retail["date"]

for i in range(0,47):
    y = jp_retail[columns[i]]
    plt.plot(x,y, lw = 0.5)

#100日ごとに日付を表示
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)

#ベースラインを表示
plt.axhline(y=0, color = "red")

plt.title("jp_retail")

#画像を保存
fig_jp_retail.savefig("fig_jp_retail.png")

fig_jp_retail.png

時系列一つ一つは、各都道府県を表します。特段変な動きをする都道府県があるわけではなさそうです。

局所的に見られる大きな縦線は、祝日により基準とかけ離れている日になります。(ほかのデータでもよく見られます)
日本で緊急事態宣言が発令された2020年4月~5月にかけて、小売の人流が著しく下がっていることが確認できます。

grocery

fig_jp_grocery = plt.figure(figsize = (12,8))
ax = fig_jp_grocery.add_subplot(111)

columns = list(jp_grocery.columns)
del columns[0]
x = jp_grocery["date"]

for i in range(0,47):
    y = jp_grocery[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("jp_grocery")

#画像を保存
fig_jp_grocery.savefig("fig_jp_grocery.png")

fig_jp_grocery.png

食料品は生活に欠かせないため、自粛だからと言って人出が減っているわけではなく、ベースライン上(コロナ前と同じ水準)を推移しています。

park

fig_jp_park = plt.figure(figsize = (12,8))
ax = fig_jp_park.add_subplot(111)

columns = list(jp_park.columns)
del columns[0]
x = jp_park["date"]

for i in range(0,47):
    y = jp_park[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("jp_park")

#画像を保存
fig_jp_park.savefig("fig_jp_park.png")

fig_jp_park.png

公園もほぼベースライン上を推移しています。密になりにくいためでしょうか。
ただし、他の時系列データに比べると基準線の上下ともにボラティリティが高いように思われます。

station

fig_jp_station = plt.figure(figsize = (12,8))
ax = fig_jp_station.add_subplot(111)

columns = list(jp_station.columns)
del columns[0]
x = jp_station["date"]

for i in range(0,47):
    y = jp_station[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("jp_station")

#画像を保存
fig_jp_station.savefig("fig_jp_station.png")

fig_jp_station.png

駅は緊急事態宣言が発令された2020年4月~5月にかけて大きく人出が下がり、その後もベースラインを下回る水準で推移しています。テレワークの普及や自粛の効果と思われます。

workplace

fig_jp_workplace = plt.figure(figsize = (12,8))
ax = fig_jp_workplace.add_subplot(111)

columns = list(jp_workplace.columns)
del columns[0]
x = jp_workplace["date"]

for i in range(0,47):
    y = jp_workplace[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("jp_workplace")

#画像を保存
fig_jp_workplace.savefig("fig_jp_workplace.png")

fig_jp_workplace.png

職場の人流はコロナ以降ベースラインを下回った状態で推移しています。テレワークの普及によるものと思われます。(大きく下がっている日は年末年始や祝日です)

residential

fig_jp_residential = plt.figure(figsize = (12,8))
ax = fig_jp_residential.add_subplot(111)

columns = list(jp_residential.columns)
del columns[0]
x = jp_residential["date"]

for i in range(0,47):
    y = jp_residential[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("jp_residential")

#画像を保存
fig_jp_residential.savefig("fig_jp_residential.png")

fig_jp_residential.png

居住空間は職場とは反対に常にベースラインを上回っています。コロナ以降働く場が会社から自宅に移ったことが読み取れます。ただし、他の時系列データに比べて高々30%前後しか変動していないことが特徴です。

可視化からわかること

・小売、駅が緊急事態宣言により同程度の人流の影響を受けている。
・食料品については緊急事態宣言後、ひいてはコロナ以降において10%前後しか変動していない。
・職場、居住空間の人流は高々30%程度の変動

時系列クラスタリング

地域ごとに移動量の特徴に違いはないのか調べるため、時系列クラスタリングによる分析を行います。
今回はtimeserieskmeansを利用しました。

from tslearn.utils import to_time_series_dataset
from tslearn.clustering import TimeSeriesKMeans

必要なライブラリをインポートします。

#クラスタリングに日付が邪魔なので削除する
jp_retail_ = jp_retail.drop(columns = "date")
jp_grocery_ = jp_grocery.drop(columns = "date")
jp_park_ = jp_park.drop(columns = "date")
jp_station_ = jp_station.drop(columns = "date")
jp_workplace_ = jp_workplace.drop(columns = "date")
jp_residential_ = jp_residential.drop(columns = "date")

日付部分が邪魔になるため、削除します。

ts_retail = to_time_series_dataset(jp_retail_.T)
ts_grocery = to_time_series_dataset(jp_grocery_.T)
ts_park = to_time_series_dataset(jp_park_.T)
ts_station = to_time_series_dataset(jp_station_.T)
ts_workplace = to_time_series_dataset(jp_workplace_.T)
ts_residential = to_time_series_dataset(jp_residential_.T)
km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_retail = km.fit_predict(ts_retail)

km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_grocery = km.fit_predict(ts_grocery)

km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_park = km.fit_predict(ts_park)

km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_station = km.fit_predict(ts_station)

km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_workplace = km.fit_predict(ts_workplace)

km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_residential = km.fit_predict(ts_residential)

今回は3つのグループにクラスタリングします。
基準線より上回っているもの、下回っているもの、変化がないもの、あたりでグループ分けできればと思い、3つにクラスタリングしました。
(※エルボー法などで最適クラスタ数を計算しようとしましたが、最適クラスタ数が1になる、関節が2個あるなど、うまくいかなかったです。)

retail

fig_jp_retail_clu = plt.figure(figsize = (12,8))
ax = fig_jp_retail_clu.add_subplot(111)

columns = list(jp_retail.columns)
del columns[0]
x = jp_retail["date"]

for i in range(len(columns)):
    y = jp_retail[columns[i]]
    if labels_retail[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_retail[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_retail[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_retail[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("jp_retail_clu")

fig_jp_retail_clu.savefig("fig_jp_retail_clu.png")

可視化させます。
3つにグループ分けしていますが、一応5つまで色分けできるようにコードを書いています。

fig_jp_retail_clu.png

見たところグループ分けはある程度うまくいっているようです。
ここで、それぞれどの色がどの都道府県なのかを見てみます。

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_retail[i] == 0:
        Cyan.append(columns[i])
    elif labels_retail[i] == 1:
        Blue.append(columns[i])
    elif labels_retail[i] == 2:
        Purple.append(columns[i])
    elif labels_retail[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['aomori', 'akita', 'yamagata', 'niigata', 'toyama', 'ishikawa', 'fukui', 'tottori', 'shimane']
['hokkaido', 'tokyo', 'kanagawa', 'aichi', 'mie', 'kyoto', 'osaka', 'hyogo', 'hiroshima', 'yamaguchi', 'kagawa', 'ehime', 'kochi', 'fukuoka', 'kumamoto', 'miyazaki', 'okinawa']
['iwate', 'miyagi', 'fukushima', 'ibaraki', 'tochigi', 'gunma', 'saitama', 'chiba', 'yamanashi', 'nagano', 'gifu', 'shizuoka', 'shiga', 'nara', 'wakayama', 'okayama', 'tokushima', 'saga', 'nagasaki', 'oita', 'kagoshima']
[]
[]

出力結果を見ると、小売に関してコロナ前とあまり人流が変わらない都道府県は雪国が多い特徴がありました。
このデータの基準は2020年1月の人流を基に作成されているため、コロナの影響を受ける前から雪国は人出が少なかった可能性があります。
逆に大きく人出が減少した都道府県は、比較的都会の印象があります。

grocery

fig_jp_grocery_clu = plt.figure(figsize = (12,8))
ax = fig_jp_grocery_clu.add_subplot(111)

columns = list(jp_grocery.columns)
del columns[0]
x = jp_grocery["date"]

for i in range(len(columns)):
    y = jp_grocery[columns[i]]
    if labels_grocery[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_grocery[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_grocery[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_grocery[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("jp_grocery_clu")

fig_jp_grocery_clu.savefig("fig_jp_grocery_clu.png")
#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_grocery[i] == 0:
        Cyan.append(columns[i])
    elif labels_grocery[i] == 1:
        Blue.append(columns[i])
    elif labels_grocery[i] == 2:
        Purple.append(columns[i])
    elif labels_grocery[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])

fig_jp_grocery_clu.png

print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['aomori', 'iwate', 'miyagi', 'akita', 'yamagata', 'fukushima', 'niigata', 'toyama', 'ishikawa', 'fukui', 'nagano', 'gifu', 'wakayama', 'tottori']
['saitama', 'chiba', 'kanagawa', 'shiga', 'kyoto', 'osaka', 'hyogo', 'nara']
['hokkaido', 'ibaraki', 'tochigi', 'gunma', 'tokyo', 'yamanashi', 'shizuoka', 'aichi', 'mie', 'shimane', 'okayama', 'hiroshima', 'yamaguchi', 'tokushima', 'kagawa', 'ehime', 'kochi', 'fukuoka', 'saga', 'nagasaki', 'kumamoto', 'oita', 'miyazaki', 'kagoshima', 'okinawa']
[]
[]

食料品に関しては、元々ほとんど基準線と変わらないデータであるため、あまりクラスタリングの意味はなさそうです。

park

fig_jp_park_clu = plt.figure(figsize = (12,8))
ax = fig_jp_park_clu.add_subplot(111)

columns = list(jp_park.columns)
del columns[0]
x = jp_park["date"]

for i in range(len(columns)):
    y = jp_park[columns[i]]
    if labels_park[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_park[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_park[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_park[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("jp_park_clu")

fig_jp_park_clu.savefig("fig_jp_park_clu")

fig_jp_park_clu.png

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_park[i] == 0:
        Cyan.append(columns[i])
    elif labels_park[i] == 1:
        Blue.append(columns[i])
    elif labels_park[i] == 2:
        Purple.append(columns[i])
    elif labels_park[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['hokkaido', 'aomori', 'iwate', 'akita', 'yamagata', 'fukushima', 'niigata', 'toyama', 'ishikawa', 'fukui', 'yamanashi', 'shiga', 'wakayama', 'tottori', 'shimane']
['miyagi', 'ibaraki', 'tochigi', 'gunma', 'saitama', 'chiba', 'kanagawa', 'nagano', 'okayama', 'kochi']
['tokyo', 'gifu', 'shizuoka', 'aichi', 'mie', 'kyoto', 'osaka', 'hyogo', 'nara', 'hiroshima', 'yamaguchi', 'tokushima', 'kagawa', 'ehime', 'fukuoka', 'saga', 'nagasaki', 'kumamoto', 'oita', 'miyazaki', 'kagoshima', 'okinawa']
[]
[]

日本海側の人出が増加していて、太平洋側の人出は減少しています。
やはりコロナの影響というよりかは、地域性に違いがあったのではないかと考えられます。

station

fig_jp_station_clu = plt.figure(figsize = (12,8))
ax = fig_jp_station_clu.add_subplot(111)

columns = list(jp_station.columns)
del columns[0]
x = jp_station["date"]

for i in range(len(columns)):
    y = jp_station[columns[i]]
    if labels_station[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_station[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_station[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_station[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("jp_station_clu")

fig_jp_station_clu.savefig("fig_jp_station_clu.png")

fig_jp_station_clu.png

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_station[i] == 0:
        Cyan.append(columns[i])
    elif labels_station[i] == 1:
        Blue.append(columns[i])
    elif labels_station[i] == 2:
        Purple.append(columns[i])
    elif labels_station[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['hokkaido', 'aomori', 'iwate', 'akita', 'fukushima', 'tochigi', 'gunma', 'niigata', 'toyama', 'nagano', 'gifu', 'nara', 'wakayama', 'tottori', 'okayama', 'yamaguchi', 'kagawa', 'ehime', 'saga', 'nagasaki', 'kumamoto', 'oita', 'kagoshima']
['miyagi', 'ibaraki', 'saitama', 'chiba', 'tokyo', 'kanagawa', 'ishikawa', 'shizuoka', 'aichi', 'mie', 'shiga', 'kyoto', 'osaka', 'hyogo', 'hiroshima', 'fukuoka', 'okinawa']
['yamagata', 'fukui', 'yamanashi', 'shimane', 'tokushima', 'kochi', 'miyazaki']
[]
[]

北海道以外の7大都市圏(仙台、東京、大阪、愛知、広島、福岡)が一番基準線との乖離が大きいため、やはり栄えている都道府県の方がテレワークの変更が可能なのか、駅の利用者が少なくなっています。

workplace

fig_jp_workplace_clu = plt.figure(figsize = (12,8))
ax = fig_jp_workplace_clu.add_subplot(111)

columns = list(jp_workplace.columns)
del columns[0]
x = jp_workplace["date"]

for i in range(len(columns)):
    y = jp_workplace[columns[i]]
    if labels_workplace[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_workplace[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_workplace[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_workplace[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("jp_workplace_clu")

fig_jp_workplace_clu.savefig("fig_jp_workplace_clu.png")

fig_jp_workplace_clu.png

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_workplace[i] == 0:
        Cyan.append(columns[i])
    elif labels_workplace[i] == 1:
        Blue.append(columns[i])
    elif labels_workplace[i] == 2:
        Purple.append(columns[i])
    elif labels_workplace[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['hokkaido', 'miyagi', 'saitama', 'chiba', 'tokyo', 'kanagawa', 'aichi', 'shiga', 'kyoto', 'osaka', 'hyogo', 'hiroshima', 'fukuoka', 'kumamoto', 'okinawa']
['yamagata', 'wakayama', 'tottori', 'nagasaki', 'kagoshima']
['aomori', 'iwate', 'akita', 'fukushima', 'ibaraki', 'tochigi', 'gunma', 'niigata', 'toyama', 'ishikawa', 'fukui', 'yamanashi', 'nagano', 'gifu', 'shizuoka', 'mie', 'nara', 'shimane', 'okayama', 'yamaguchi', 'tokushima', 'kagawa', 'ehime', 'kochi', 'saga', 'oita', 'miyazaki']
[]
[]

都会の方がコロナ以降出社率が下がっている傾向にあります。都会の方がテレワークができる職業や、テレワークを推進できる会社が多いということでしょうか。

residential

fig_jp_residential_clu = plt.figure(figsize = (12,8))
ax = fig_jp_residential_clu.add_subplot(111)

columns = list(jp_residential.columns)
del columns[0]
x = jp_residential["date"]

for i in range(len(columns)):
    y = jp_residential[columns[i]]
    if labels_residential[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_residential[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_residential[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_residential[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("jp_residential_clu")

fig_jp_residential_clu.savefig("fig_jp_residential_clu.png")

fig_jp_residential_clu.png

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_residential[i] == 0:
        Cyan.append(columns[i])
    elif labels_residential[i] == 1:
        Blue.append(columns[i])
    elif labels_residential[i] == 2:
        Purple.append(columns[i])
    elif labels_residential[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['miyagi', 'ibaraki', 'tochigi', 'gunma', 'yamanashi', 'gifu', 'shizuoka', 'aichi', 'mie', 'shiga', 'kyoto', 'osaka', 'hyogo', 'nara', 'wakayama', 'okayama', 'hiroshima', 'yamaguchi', 'tokushima', 'kagawa', 'ehime', 'kochi', 'fukuoka', 'saga', 'nagasaki', 'kumamoto', 'oita', 'miyazaki', 'kagoshima', 'okinawa']
['hokkaido', 'aomori', 'iwate', 'akita', 'yamagata', 'fukushima', 'niigata', 'toyama', 'ishikawa', 'fukui', 'nagano', 'tottori', 'shimane']
['saitama', 'chiba', 'tokyo', 'kanagawa']
[]
[]

居住空間により多くいるようになった都道府県は関東に固まっており、埼玉、千葉、東京、神奈川でした。
元々労働人口の割合が高い都道府県が入っているということかもしれません。
また、やはり日本海側の居住空間の人流は変化しておらず、地域性が出ている蓋然性が高いです。

クラスタリング結果まとめ

・retail:5大都市いずれも人流が大きく下がるクラスタに存在する。一方で日本海側はコロナ前と人流の差が小さい。
・grocery:特記事項なし。
・park:人流は日本海側は増加、太平洋側は減少。九州に至ってはすべて減少。地域性が強く出てしまっている。(分析としては面白いが、コロナに関してではないためあまり使えないデータである。)
・駅:北海道以外の7大都市圏(仙台、東京、大阪、愛知、広島、福岡)がコロナ前より大きく人流が下がるクラスタに存在する。コロナ前と人流が近いクラスタにいるのは山形、福井、山梨、島根、徳島、高知、宮崎と、比較的地方の割合が多い。
・workplace:7大都市圏いずれもが基準線と乖離が大きいクラスタに存在する。
・residential:埼玉、千葉、東京、神奈川が最も基準線と乖離が大きいクラスタに存在する。

3. Community mobility reports(Google) -国外版

続いて、国別のデータを用いて分析を行います。

データの整形

やることは基本的に国内データで実施した内容と同じになります。

world_park_csv = pd.read_csv("world_park_google.csv")
world_station_csv = pd.read_csv("world_station_google.csv")
world_retail_csv = pd.read_csv("world_retail_google.csv")
world_grocery_csv = pd.read_csv("world_grocery_google.csv")
world_workplace_csv = pd.read_csv("world_workplace_google.csv")
world_residential_csv = pd.read_csv("world_residential_google.csv")

必要なファイルを読み込みます。

#csv形式→dataframe形式に変換
world_park = pd.DataFrame(world_park_csv)
world_station = pd.DataFrame(world_station_csv)
world_retail = pd.DataFrame(world_retail_csv)
world_grocery = pd.DataFrame(world_grocery_csv)
world_workplace = pd.DataFrame(world_workplace_csv)
world_residential = pd.DataFrame(world_residential_csv)

csv形式からデータフレーム形式に変換します。

#欠損値を前後の値から補完する
world_park = world_park.interpolate()
world_station = world_station.interpolate()
world_retail = world_retail.interpolate()
world_grocery = world_grocery.interpolate()
world_workplace = world_workplace.interpolate()
world_residential = world_residential.interpolate()

欠損値を前後の値から補完します。

データの可視化

retail

fig_world_retail = plt.figure(figsize = (12,8))
ax = fig_world_retail.add_subplot(111)

columns = list(world_retail.columns)
del columns[0]
x = world_retail["date"]

for i in range(len(columns)):
    y = world_retail[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_retail")

fig_world_retail.savefig("fig_world_retail.png")

fig_world_retail.png

やはりコロナが始まった段階で小売への大きく人流は減少し、徐々に回復に向かうという流れは日本国内と同様ですね。

grocery

fig_world_grocery = plt.figure(figsize = (12,8))
ax = fig_world_grocery.add_subplot(111)

columns = list(world_grocery.columns)
del columns[0]
x = world_grocery["date"]

for i in range(len(columns)):
    y = world_grocery[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_grocery")

fig_world_grocery.savefig("fig_world_grocery.png")

fig_world_grocery.png

食料品に関しても、生活必需品であるためベースラインとさほど変わらず推移しています。

park

fig_world_park = plt.figure(figsize = (12,8))
ax = fig_world_park.add_subplot(111)

columns = list(world_park.columns)
del columns[0]
x = world_park["date"]

for i in range(len(columns)):
    y = world_park[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_park")

fig_world_park.savefig("fig_world_park.png")

fig_world_park.png

公園への人流は二分しており、ベースライン付近を推移するものと、夏場に大きく人出が増えている国とに分かれています。夏場の増加は夏休みなどで公園やキャンプを利用する人が増えているのでしょうか。ベースラインが1月の人出を基に作成されていることを考えると、ベースライン付近を推移している国は、従来よりかは夏場の人出が減っているのではないかと思います。

station

fig_world_station = plt.figure(figsize = (12,8))
ax = fig_world_station.add_subplot(111)

columns = list(world_station.columns)
del columns[0]
x = world_station["date"]

for i in range(len(columns)):
    y = world_station[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_station")

fig_world_station.savefig("fig_world_station.png")

fig_world_station.png

駅への人流は各国ベースラインを下回ったまま推移しています。

workplace

fig_world_workplace = plt.figure(figsize = (12,8))
ax = fig_world_workplace.add_subplot(111)

columns = list(world_workplace.columns)
del columns[0]
x = world_workplace["date"]

for i in range(len(columns)):
    y = world_workplace[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_workplace")

fig_world_workplace.savefig("fig_world_workplace.png")

fig_world_workplace.png

職場への人流は各国ベースラインを下回ったまま推移しています。

residential

fig_world_residential = plt.figure(figsize = (12,8))
ax = fig_world_residential.add_subplot(111)

columns = list(world_residential.columns)
del columns[0]
x = world_residential["date"]

for i in range(len(columns)):
    y = world_residential[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_residential")

fig_world_residential.savefig("fig_world_residential.png")

fig_world_residential.png

住居の人流はやはりベースラインを上回ったまま推移しています。
強いロックダウンを実施している国などは、その傾向が強いのかもしれません。
クラスタリングを用いて分析してみましょう。

可視化結果まとめ

・小売:日本国内と同様に、4月~5月付近で大きく減少。夏場は基準に近い値になる傾向がある。
・食料品:日本と同様基準線付近を推移している国が大半。
・公園:大きく推移の仕方が2分しており、ベースライン付近の国と、夏場に大きく上昇する国とがある。
・駅:小売と似た推移をしている。
・職場:基本的に基準線下部を推移している。大体基準の3割程度減少。
・住居:基本的に基準線上部を推移している。大体基準の1割程度上昇。

時系列クラスタリング

クラスタリング用のライブラリをインポートします。

from tslearn.utils import to_time_series_dataset
from tslearn.clustering import TimeSeriesKMeans
import pandas as pd
#クラスタリングに日付が邪魔なので、いったん削除する
world_retail_ = world_retail.drop(columns = "date")
world_grocery_ = world_grocery.drop(columns = "date")
world_park_ = world_park.drop(columns = "date")
world_station_ = world_station.drop(columns = "date")
world_workplace_ = world_workplace.drop(columns = "date")
world_residential_ = world_residential.drop(columns = "date")
ts_retail = to_time_series_dataset(world_retail_.T)
ts_grocery = to_time_series_dataset(world_grocery_.T)
ts_park = to_time_series_dataset(world_park_.T)
ts_station = to_time_series_dataset(world_station_.T)
ts_workplace = to_time_series_dataset(world_workplace_.T)
ts_residential = to_time_series_dataset(world_residential_.T)

国内版の時と同様に、不要なデータを削除し、整形します。

km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_retail = km.fit_predict(ts_retail)

km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_grocery = km.fit_predict(ts_grocery)

km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_park = km.fit_predict(ts_park)

km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_station = km.fit_predict(ts_station)

km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_workplace = km.fit_predict(ts_workplace)

km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_residential = km.fit_predict(ts_residential)

今回も3つのクラスタに分類しました。

retail

fig_world_retail_clu = plt.figure(figsize = (12,8))
ax = fig_world_retail_clu.add_subplot(111)

columns = list(world_retail.columns)
del columns[0]
x = world_retail["date"]

for i in range(len(columns)):
    y = world_retail[columns[i]]
    if labels_retail[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_retail[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_retail[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_retail[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_retail_clu")

fig_world_retail_clu.savefig("fig_world_retail_clu.png")

fig_world_retail_clu.png

あまりうまくいっている印象はないですが、そのまま進めてみましょう。

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_retail[i] == 0:
        Cyan.append(columns[i])
    elif labels_retail[i] == 1:
        Blue.append(columns[i])
    elif labels_retail[i] == 2:
        Purple.append(columns[i])
    elif labels_retail[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['Australia', 'Brazil', 'Japan', 'Mexico', 'Philippines', 'Singapore', 'Taiwan', 'United States']
['Belgium', 'France', 'Ireland', 'Italy', 'Luxembourg', 'Spain', 'Switzerland', 'United Kingdom']
['Canada', 'Czech Republic', 'Denmark', 'Estonia', 'Finland', 'Germany', 'Netherlands', 'New Zealand', 'Norway', 'Slovakia', 'Sweden']
[]
[]

大まかな推移に従っていない国(Blue)、大まかな推移に従っており、基準線に近い国(Purple)、遠い国(Cyan)の3つに分類されているように思います。大まかな推移に従っていない国には日本、アメリカ、東南アジア諸国、オーストラリア、ブラジル、メキシコがあります。ヨーロッパ諸国に関しては、影響の違いはあれど、基本的に各国同じような推移になっています。

grocery

fig_world_grocery_clu = plt.figure(figsize = (12,8))
ax = fig_world_grocery_clu.add_subplot(111)

columns = list(world_grocery.columns)
del columns[0]
x = world_grocery["date"]

for i in range(len(columns)):
    y = world_grocery[columns[i]]
    if labels_grocery[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_grocery[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_grocery[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_grocery[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_grocery_clu")

fig_world_grocery_clu.savefig("fig_world_grocery_clu.png")

fig_world_grocery_clu.png

食料品に関しては各国ベースライン付近を推移しているため、あまりクラスタリングの意味はなさそうです。

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_grocery[i] == 0:
        Cyan.append(columns[i])
    elif labels_grocery[i] == 1:
        Blue.append(columns[i])
    elif labels_grocery[i] == 2:
        Purple.append(columns[i])
    elif labels_grocery[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['Australia', 'Canada', 'Denmark', 'Estonia', 'Finland', 'Japan', 'Netherlands', 'Singapore', 'Sweden', 'Taiwan', 'United Kingdom', 'United States']
['France', 'Italy', 'Luxembourg', 'Slovakia', 'Spain']
['Belgium', 'Brazil', 'Czech Republic', 'Germany', 'Ireland', 'Mexico', 'New Zealand', 'Norway', 'Philippines', 'Switzerland']
[]
[]

特にクラスタリング結果に特徴はないようです。

park

fig_world_park_clu = plt.figure(figsize = (12,8))
ax = fig_world_park_clu.add_subplot(111)

columns = list(world_park.columns)
del columns[0]
x = world_park["date"]

for i in range(len(columns)):
    y = world_park[columns[i]]
    if labels_park[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_park[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_park[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_park[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_park_clu")

fig_world_park_clu.savefig("fig_world_park_clu.png")

fig_world_park_clu.png

Cyanがベースライン以下のものだけをグループ化してくれると嬉しかったですが、比較的うまく分類できている気がします。

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_park[i] == 0:
        Cyan.append(columns[i])
    elif labels_park[i] == 1:
        Blue.append(columns[i])
    elif labels_park[i] == 2:
        Purple.append(columns[i])
    elif labels_park[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['Denmark', 'Finland', 'Sweden']
['Australia', 'Belgium', 'Brazil', 'Czech Republic', 'France', 'Ireland', 'Italy', 'Japan', 'Luxembourg', 'Mexico', 'New Zealand', 'Philippines', 'Singapore', 'Spain', 'Switzerland', 'Taiwan', 'United Kingdom', 'United States']
['Canada', 'Estonia', 'Germany', 'Netherlands', 'Norway', 'Slovakia']
[]
[]

BlueとPurpleの国にほとんど違いはないようです。BlueとPurpleの国にはヨーロッパ諸国とカナダなど、雪国が多いです。1月に公園の人出がかなり少なかったからだと推察されます。

station

fig_world_station_clu = plt.figure(figsize = (12,8))
ax = fig_world_station_clu.add_subplot(111)

columns = list(world_station.columns)
del columns[0]
x = world_station["date"]

for i in range(len(columns)):
    y = world_station[columns[i]]
    if labels_station[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_station[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_station[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_station[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_station_clu")

fig_world_station_clu.savefig("fig_world_station_clu.png")

fig_world_station_clu.png

こちらもあまりうまくいっている印象はないですね。

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_station[i] == 0:
        Cyan.append(columns[i])
    elif labels_station[i] == 1:
        Blue.append(columns[i])
    elif labels_station[i] == 2:
        Purple.append(columns[i])
    elif labels_station[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['Brazil', 'Czech Republic', 'Estonia', 'France', 'Germany', 'Luxembourg', 'Mexico', 'Slovakia', 'Switzerland']
['Australia', 'Canada', 'Finland', 'Ireland', 'Netherlands', 'New Zealand', 'Philippines', 'United Kingdom']
['Belgium', 'Denmark', 'Italy', 'Japan', 'Norway', 'Singapore', 'Spain', 'Sweden', 'Taiwan', 'United States']
[]
[]

特段地理的な違いは含まれていなさそうです。政策の違いなどが、ここに現れている可能性があります。

workplace

fig_world_workplace_clu = plt.figure(figsize = (12,8))
ax = fig_world_workplace_clu.add_subplot(111)

columns = list(world_workplace.columns)
del columns[0]
x = world_workplace["date"]

for i in range(len(columns)):
    y = world_workplace[columns[i]]
    if labels_workplace[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_workplace[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_workplace[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_workplace[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_workplace_clu")

fig_world_workplace_clu.savefig("fig_world_workplace_clu.png")

fig_world_workplace_clu.png

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_workplace[i] == 0:
        Cyan.append(columns[i])
    elif labels_workplace[i] == 1:
        Blue.append(columns[i])
    elif labels_workplace[i] == 2:
        Purple.append(columns[i])
    elif labels_workplace[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['Australia', 'Brazil', 'Czech Republic', 'France', 'Germany', 'Italy', 'Japan', 'Mexico', 'New Zealand', 'Singapore', 'Slovakia', 'Spain', 'Switzerland', 'Taiwan']
['Belgium', 'Denmark', 'Finland', 'Luxembourg', 'Netherlands', 'Norway', 'Sweden']
['Canada', 'Estonia', 'Ireland', 'Philippines', 'United Kingdom', 'United States']
[]
[]

雪国が固まっている気もしますが、あまり地理的な要因はなさそうです。

residential

fig_world_residential_clu = plt.figure(figsize = (12,8))
ax = fig_world_residential_clu.add_subplot(111)

columns = list(world_residential.columns)
del columns[0]
x = world_residential["date"]

for i in range(len(columns)):
    y = world_residential[columns[i]]
    if labels_residential[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_residential[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_residential[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_residential[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=0, color = "red")
plt.title("world_residential_clu")

fig_world_residential_clu.savefig("fig_world_residential_clu.png")

fig_world_residential_clu.png

比較的うまくクラスタリングできています。

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_residential[i] == 0:
        Cyan.append(columns[i])
    elif labels_residential[i] == 1:
        Blue.append(columns[i])
    elif labels_residential[i] == 2:
        Purple.append(columns[i])
    elif labels_residential[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['Belgium', 'Canada', 'Ireland', 'Luxembourg', 'Philippines', 'Singapore', 'United Kingdom']
['Australia', 'Brazil', 'Denmark', 'Germany', 'Japan', 'Mexico', 'Netherlands', 'New Zealand', 'Norway', 'Sweden', 'Switzerland', 'Taiwan', 'United States']
['Czech Republic', 'Estonia', 'Finland', 'France', 'Italy', 'Slovakia', 'Spain']
[]
[]

時系列クラスタリング結果まとめ

・小売:ヨーロッパ諸国はほとんど同じような推移をしている。
・公園:雪国かそれ以外かという地理的な影響を強く受けている。

4. Mobility trends reports(Apple)

データの整形

お馴染みのライブラリをインストールします。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa import stattools as tsat
import statsmodels.graphics.api as smg
import statsmodels.graphics.tsaplots as tsap

import statsmodels.api as sm
import seaborn as sns

csvファイルをインポートし、データフレーム型に変換します。

world_driving_csv = pd.read_csv("world_driving_apple.csv")
world_transit_csv = pd.read_csv("world_transit_apple.csv")
world_walking_csv = pd.read_csv("world_walking_apple.csv")

world_driving_apple = pd.DataFrame(world_driving_csv)
world_transit_apple = pd.DataFrame(world_transit_csv)
world_walking_apple = pd.DataFrame(world_walking_csv)

欠損値を前後の値から補完します。

world_driving = world_driving_apple.interpolate()
world_transit = world_transit_apple.interpolate()
world_walking = world_walking_apple.interpolate()

データの可視化

driving

fig_world_driving = plt.figure(figsize = (12,8))
ax = fig_world_driving.add_subplot(111)

columns = list(world_driving.columns)
del columns[0]
x = world_driving["date"]

for i in range(len(columns)):
    y = world_driving[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=100, color = "red")
plt.title("world_driving")

fig_world_driving.savefig("fig_world_driving.png")

fig_world_driving.png

コロナが流行し始めた4月~5月あたりは、全ての人出が減少しているせいか、車での移動も減少していますが、それ以降は基本的にコロナ前より利用されている傾向にあります。密を避ける形の移動方法として車が一つの手段になったからだと考えられます。一方で基準線を常に下回っている国もあるみたいです。

transit

fig_world_transit = plt.figure(figsize = (12,8))
ax = fig_world_transit.add_subplot(111)

columns = list(world_transit.columns)
del columns[0]
x = world_transit["date"]

for i in range(len(columns)):
    y = world_transit[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=100, color = "red")
plt.title("world_transit")

fig_world_transit.savefig("fig_world_transit.png")

fig_world_transit.png

電車の利用は2021年4月あたりまでは基準線を下回っていましたが、それ以降は増加傾向にあります。

walking

fig_world_walking = plt.figure(figsize = (12,8))
ax = fig_world_walking.add_subplot(111)

columns = list(world_walking.columns)
del columns[0]
x = world_walking["date"]

for i in range(len(columns)):
    y = world_walking[columns[i]]
    plt.plot(x,y, lw = 0.5)

plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=100, color = "red")
plt.title("world_walking")

fig_world_walking.savefig("fig_world_walking.png")

fig_world_walking.png

コロナ流行当初は減少し、それ以降は基準線を上回る推移になっています。公共交通機関を利用しない移動方法は徒歩くらいしかないですからね。ただし、国によっては移動自体が減っているのか、常に基準線を下回る国もあります。

時系列クラスタリング

from tslearn.utils import to_time_series_dataset
from tslearn.clustering import TimeSeriesKMeans
import pandas as pd
#クラスタリングに日付が邪魔なので、いったん削除する
world_driving_ = world_driving.drop(columns = "date")
world_transit_ = world_transit.drop(columns = "date")
world_walking_ = world_walking.drop(columns = "date")

driving

今回も3つのクラスタに分類します。

ts_driving = to_time_series_dataset(world_driving_.T)
km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_driving = km.fit_predict(ts_driving)
fig_world_driving_clu = plt.figure(figsize = (12,8))
ax = fig_world_driving_clu.add_subplot(111)

columns = list(world_driving.columns)
del columns[0]
x = world_driving["date"]

for i in range(len(columns)):
    y = world_driving[columns[i]]
    if labels_driving[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_driving[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_driving[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_driving[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=100, color = "red")
plt.title("world_driving_clu")

fig_world_driving_clu.savefig("fig_world_driving_clu.png")

fig_world_driving_clu.png

#グループ分け
Blue = []
Cyan = []
Orange = []
Red = []
Purple = []
for i in range(len(columns)):
    if labels_driving[i] == 0:
        Cyan.append(columns[i])
    elif labels_driving[i] == 1:
        Blue.append(columns[i])
    elif labels_driving[i] == 2:
        Purple.append(columns[i])
    elif labels_driving[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['Estonia', 'Finland', 'Japan', 'Norway', 'Sweden']
['Australia', 'Brazil', 'Luxembourg', 'Mexico', 'Netherlands', 'New Zealand', 'Philippines', 'Singapore', 'Taiwan']
['Belgium', 'Canada', 'Czech Republic', 'Denmark', 'France', 'Germany', 'Ireland', 'Italy', 'Slovakia', 'Spain', 'Switzerland', 'United Kingdom', 'United States']
[]
[]

transit

ts_transit = to_time_series_dataset(world_transit_.T)
km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_transit = km.fit_predict(ts_transit)
fig_world_transit_clu = plt.figure(figsize = (12,8))
ax = fig_world_transit_clu.add_subplot(111)

columns = list(world_transit.columns)
del columns[0]
x = world_transit["date"]

for i in range(len(columns)):
    y = world_transit[columns[i]]
    if labels_transit[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_transit[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_transit[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_transit[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=100, color = "red")
plt.title("world_transit_clu")

fig_world_transit_clu.savefig("fig_world_transit_clu.png")

fig_world_transit_clu.png

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_transit[i] == 0:
        Cyan.append(columns[i])
    elif labels_transit[i] == 1:
        Blue.append(columns[i])
    elif labels_transit[i] == 2:
        Purple.append(columns[i])
    elif labels_transit[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['Belgium', 'Estonia', 'France', 'Germany', 'Italy', 'Slovakia', 'Spain']
['Brazil', 'Czech Republic', 'Denmark', 'Finland', 'Ireland', 'Luxembourg', 'Mexico', 'Netherlands', 'Norway', 'Sweden', 'Switzerland', 'United Kingdom', 'United States']
['Australia', 'Canada', 'Japan', 'New Zealand', 'Philippines', 'Singapore', 'Taiwan']
[]
[]

walking

ts_walking = to_time_series_dataset(world_walking_.T)
km = TimeSeriesKMeans(n_clusters=3, metric="dtw")
labels_walking = km.fit_predict(ts_walking)
fig_world_walking_clu = plt.figure(figsize = (12,8))
ax = fig_world_walking_clu.add_subplot(111)

columns = list(world_walking.columns)
del columns[0]
x = world_walking["date"]

for i in range(len(columns)):
    y = world_walking[columns[i]]
    if labels_walking[i] == 0:
        plt.plot(x,y, lw = 0.5, color = "cyan")
    elif labels_walking[i] == 1:
        plt.plot(x,y, lw = 0.5, color = "blue")
    elif labels_walking[i] == 2:
        plt.plot(x,y, lw = 0.5, color = "purple")
    elif labels_walking[i] == 3:
        plt.plot(x,y, lw = 0.5, color = "red")
    else:
        plt.plot(x,y, lw = 0.5, color = "orange")
        
plt.xticks([0, 100, 200, 300, 400, 500, 600, 700], rotation=45)
plt.axhline(y=100, color = "red")
plt.title("world_walking_clu")

fig_world_walking_clu.savefig("fig_world_walking_clu.png")

fig_world_walking_clu.png

#グループ分け
Blue = []
Cyan = []
Purple = []
Red = []
Orange = []
for i in range(len(columns)):
    if labels_walking[i] == 0:
        Cyan.append(columns[i])
    elif labels_walking[i] == 1:
        Blue.append(columns[i])
    elif labels_walking[i] == 2:
        Purple.append(columns[i])
    elif labels_walking[i] == 3:
        Red.append(columns[i])
    else:
        Orange.append(columns[i])
print(Blue)
print(Cyan)
print(Purple)
print(Red)
print(Orange)
['Belgium', 'Canada', 'Denmark', 'Estonia', 'Germany', 'Italy', 'Mexico', 'Norway', 'Slovakia', 'Spain', 'United Kingdom', 'United States']
['Australia', 'New Zealand', 'Philippines', 'Singapore']
['Brazil', 'Czech Republic', 'Finland', 'France', 'Ireland', 'Japan', 'Luxembourg', 'Netherlands', 'Sweden', 'Switzerland', 'Taiwan']
[]
[]
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1