1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

STL分解 × 残差相関:COVID時系列データから「真の相関」を探る

1
Last updated at Posted at 2025-12-19

user:

さまざまな国のCOVID-19の感染者数等の時系列データを、ダウンロード容易な形でまとめているウェブサイトがあったと思うのですが、ご存じですか?

assistant:

はい、あります!COVID-19の感染者数などの時系列データを国別でまとめて公開していた代表的な信頼性の高いデータソースはいくつかあります。以下に代表例を挙げますね:


Our World in Data (OWID)

  • データの種類:感染者数、死亡者数、検査数、ワクチン接種数など
  • 国別対応:あり(世界中)
  • 更新頻度:基本的に毎日更新
  • ダウンロード形式:CSV、XLSX などで 直接ダウンロード可能
  • GitHub
    https://github.com/owid/covid-19-data
    owid-covid-data.csv が主要な時系列データ

Johns Hopkins University (JHU) CSSE COVID-19 Data

  • データの種類:感染者数、死亡者数、回復者数(初期から中期まで主に使用されていた)
  • 国・州・地域別の詳細なデータ
  • ダウンロード:GitHub上でCSVファイルとして提供
  • :2023年3月で更新終了

COVID-19 Data Hub

  • 目的:分析や機械学習用に時系列データを整理
  • データ:国・地域別に感染者数、対策状況、人口統計、移動データなどを統合
  • APIやR/Pythonパッケージでも利用可能

Our World in Data GitHub からの直接リンク例(CSV)

https://covid.ourworldindata.org/data/owid-covid-data.csv

→ これを pandas 等で読み込むだけで、すぐ使えます。


Pythonで読み込む例:

import pandas as pd

url = "https://covid.ourworldindata.org/data/owid-covid-data.csv"
df = pd.read_csv(url)

# 例えば日本だけ抽出
japan_df = df[df['location'] == 'Japan']

もし具体的に「この形式で取得したい」や「特定の国・指標が欲しい」といった要望があれば、それに合うものをさらに詳しく紹介できますよ!

user:

ありがとうございます。残念ながら、今教えていただいたリンクはもう使えないようですね。https://ourworldindata.org/ から、COVID-19と関係なくても良いので、時系列の因果探索という文脈で使えそうなデータがないか、探してもらうことってできますか?

assistant:

Our World in Data (OWID) は COVID‑19 に限らず、多様な国別・年次(または月次)の時系列データを豊富に提供しています。因果探索パネル分析など研究目的で使える以下のようなデータが公開されています:


🌍 Our World in Data の各種時系列データ

1. OWID Dataset Collection(国別年次パネルデータ集)

GitHub上の owid-datasets リポジトリから、数千の社会/経済指標の時系列データ(CSV や datapackage)をダウンロードできます。研究に使える構造化されたパネルデータです。(opennetzero.org, GitHub)

2. Chart Data API と改良されたダウンロード機能

  • 各チャート(例:人口増加、エネルギー消費など)からCSVやJSON形式で直接取得可能。
  • ZIP に入ったCSV+メタデータや、チャート単位の API で柔軟にデータのフィルタや抽出ができます。(Our World in Data, R-bloggers)

例えば「average‑monthly‑surface‑temperature」などのチャート名を指定して、

https://ourworldindata.org/grapher/<チャート名>.csv?v=1&csvType=filtered&useColumnShortNames=true&country=USA

のように取得できます。(R-bloggers)

3. 主要トピックごとのデータページ

各ページに「Download Data」またはチャート下のダウンロードボタンがあり、CSV形式で時系列データを取得できます。


🧪 因果探索向けの利点と利用法

  • 複数国・複数指標のパネル分析に最適:例えばGDP・CO₂排出量・人口・エネルギー消費などを時系列で統合可能。

  • Python/R から API 経由で自動取得し、分析ワークフローに組み込めます。


✔️ まとめ比較表

データ形式・入手手段 主な用途 特徴
owid‑datasets(GitHub) 国別パネルデータの統計分析 数千指標・年次対応
Chart Data API/ダウンロード 特定チャート × 国 × 指標 の取得 CSV/JSON 対応・柔軟に絞り込み可能
<トピック別>ページ 分野別の時系列データ(例:エネルギー、人口) 分かりやすい閲覧・CSV取得可能

📌 実例:因果探索に使えそうなチャートデータ

  • **平均気温(月次)**の時系列を使って気候変動と他変数の関係を探る。
  • CO₂排出量/経済成長(GDP)/エネルギー消費 の国別年次データを統合して、環境政策の因果推論に活用。
  • 移民動向、人口構造、教育水準など社会指標と経済成長の絡みを panel data で分析。

📥 今すぐ使えるコード例(Python or R)

Python(pandas)でチャートAPIから取得:

import pandas as pd
url = "https://ourworldindata.org/grapher/average-monthly-surface-temperature.csv"
params = {"v": "1", "csvType": "filtered", "useColumnShortNames": "true", "country": "World"}
df = pd.read_csv(url, params=params)

R(owidR パッケージ)で取得:

library(owidR)
data <- owid("average-monthly-surface-temperature")

OWID のサイトが使えなくなったように感じたのは、URL 構成や API のインターフェースが変更されたためかもしれませんが、今は 改良されたチャート APIGitHub のデータリポジトリ で、むしろ以前よりも柔軟にデータ取得できます。

もし取り出したいテーマ(例:人口・環境・経済など)や国別の指標名が決まっていれば、具体的なチャート名や取得方法をもっと詳しくお教えしますね 😊

user:

ありがとうございます。COVID-19 Data Hubから、時系列の因果探索という文脈で使えそうなデータがないか、探してもらうことってできますか? Pythonを使って自動で取得できると嬉しいです。

assistant:

COVID‑19 Data Hubでは、因果探索に使える多様な時系列データを、PythonやRのインターフェースを通じて自動取得できます。


📊 COVID‑19 Data Hubの特徴

  • 国別・地域別・行政区分レベル(全国/州/県レベル)の日次時系列データを提供 (GitHub, CRAN)
  • 主な変数:感染 confirmed、死亡 deaths、回復 recovered、検査 tests、ワクチン接種 vaccines、入院 hosp、ICU icu、人工呼吸 vent、政策・ロックダウン指標や Mobility データなどを含む (covid19datahub.io)
  • オックスフォードの政府対応記録(OxCGRT) に基づいた政策措置インデックス(学校閉鎖、移動制限、保護措置など)も収録されており、政策と感染動向の因果探索に非常に便利 (covid19datahub.io)
  • 交通・人口などの外生変数との連携も可能(Google/Apple モビリティ、World Bank指標等とリンクできる) (covid19datahub.io)

💻 Pythonでのデータ取得

COVID‑19 Data Hub には専用 Python パッケージ covid19dh があり、以下のように簡単に利用できます:

from covid19dh import covid19

df, src = covid19(country="JPN", start="2020‑01‑01", end="2021‑12‑31")
  • df に日次の観測データ(累積値やpolicyインデックスなど)が入ります
  • src にデータソースや引用情報が含まれます
  • 国を省略すると全世界のデータ取得可能
  • raw=False を指定すると、欠損日を補完し一貫した日次グリッドを確保できます (GitHub)

📈 Rでも同様に利用可能

R パッケージ COVID19(バージョン 3.0.3/2025年7月21日現在)を使用すると、以下のようなコードでデータ取得できます:

library(COVID19)
x <- covid19(country="JPN", level=1, start="2020‑01‑01", end="2021‑12‑31", raw=FALSE)
  • level = 1 は国レベル、level = 2,3 でより細かな地域の時系列にも対応
  • vintage を使えば、指定日の「その時点で公開されていたスナップショット」データを取得でき、再現性ある分析に有効です (CRAN)

✅ 因果探索向きの具体的な使い方

  • 政策インデックス(例:school_closing, stay_home_restrictions など)と感染・死亡数との動的因果関係の分析
  • Mobilityや人口、検査数、ワクチン接種率などを共変量として取り込み、パネル回帰/分割差法(DiD)やGranger因果検定などに応用可能
  • 国間比較パネルデータを生成し、時差付き効果や制度の違いを眺める因果モデル構築に最適

📌 まとめまとめ(Python or R で自動取得できる因果分析用データ)

項目 内容
データ構造 日次時系列パネル(国・地域ごと)
変数例 confirmed, deaths, recovered, tests, vaccines, hosp, icu, vent
政策指標 OxCGRT由来のロックダウン/対応スコア
外生変数 Mobility(Google/Apple)、World Bank 指標(例:病床数など)
取得方法 Python:covid19dhcovid19(...)
R:COVID19::covid19(...)
補足 raw=False でNA補完、vintage=TRUE で再現可能性向上

もし使いたい対象の国や期間、分析手法(例:政策の導入効果、ワクチン接種との因果関係など)が決まっていれば、それに向けた具体的なコード例やデータ整形の流れもお見せできます。気軽に教えてくださいね 😊

user:

ありがとうございます。

pip install covid19dh

した後で

from covid19dh import covid19

df, src = covid19(country="JPN", start="2020-01-01", end="2021-12-31")

すると、dfが次のような内容になりました。

              id       date  confirmed   deaths  recovered       tests  \
140665  f54996f4 2020-02-06       16.0      NaN        4.0       132.0   
140666  f54996f4 2020-02-07       16.0      NaN        4.0       151.0   
140667  f54996f4 2020-02-10       16.0      NaN        9.0       174.0   
140668  f54996f4 2020-02-12       16.0      NaN       10.0       190.0   
140669  f54996f4 2020-02-13       17.0      NaN       11.0       200.0   
...          ...        ...        ...      ...        ...         ...   
141350  f54996f4 2021-12-27  1726602.0  18379.0  1706468.0  27813819.0   
141351  f54996f4 2021-12-28  1726770.0  18379.0  1706670.0  27865723.0   
141352  f54996f4 2021-12-29  1727063.0  18381.0  1706849.0  27925661.0   
141353  f54996f4 2021-12-30  1727426.0  18385.0  1707034.0  27963429.0   
141354  f54996f4 2021-12-31  1727837.0  18385.0  1707193.0  27988750.0   

           vaccines  people_vaccinated  people_fully_vaccinated    hosp  ...  \
140665          NaN                NaN                      NaN     NaN  ...   
140666          NaN                NaN                      NaN     NaN  ...   
140667          NaN                NaN                      NaN     NaN  ...   
140668          NaN                NaN                      NaN     NaN  ...   
140669          NaN                NaN                      NaN     NaN  ...   
...             ...                ...                      ...     ...  ...   
141350  201697495.0        101454308.0               99774650.0  1995.0  ...   
141351  201780366.0        101461446.0               99787624.0  1975.0  ...   
141352  201787864.0        101464373.0               99792195.0  2064.0  ...   
141353  201790028.0        101465314.0               99793418.0  2222.0  ...   
141354  201790438.0        101465525.0               99793617.0  2509.0  ...   

        iso_alpha_3  iso_alpha_2  iso_numeric  iso_currency  key_local  \
140665          JPN           JP        392.0           JPY        NaN   
140666          JPN           JP        392.0           JPY        NaN   
140667          JPN           JP        392.0           JPY        NaN   
140668          JPN           JP        392.0           JPY        NaN   
140669          JPN           JP        392.0           JPY        NaN   
...             ...          ...          ...           ...        ...   
141350          JPN           JP        392.0           JPY        NaN   
141351          JPN           JP        392.0           JPY        NaN   
141352          JPN           JP        392.0           JPY        NaN   
141353          JPN           JP        392.0           JPY        NaN   
141354          JPN           JP        392.0           JPY        NaN   

                key_google_mobility  key_apple_mobility  key_jhu_csse  \
140665  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
140666  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
140667  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
140668  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
140669  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
...                             ...                 ...           ...   
141350  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
141351  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
141352  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
141353  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
141354  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   

        key_nuts  key_gadm  
140665       NaN       JPN  
140666       NaN       JPN  
140667       NaN       JPN  
140668       NaN       JPN  
140669       NaN       JPN  
...          ...       ...  
141350       NaN       JPN  
141351       NaN       JPN  
141352       NaN       JPN  
141353       NaN       JPN  
141354       NaN       JPN  

[690 rows x 47 columns]

assistant:

ありがとうございます、ばっちり取得できていますね!この covid19dh パッケージから取得したデータは、因果探索(causal inference)や時系列分析に極めて適した構造になっています。以下、どう活用できるかの観点で詳しく整理してみますね。


✅ データの概要と構成(再掲)

あなたが取得した DataFrame df の特徴:

  • 対象国:日本(JPN)
  • 期間:2020-01-01 ~ 2021-12-31(日次)
  • 観測数:690行(欠損日あり)
  • 変数数:47列

主な変数カテゴリ:

カテゴリ 変数名例 内容
疫学系 confirmed, deaths, recovered, tests 累積の感染・死亡・回復・検査数
ワクチン vaccines, people_vaccinated, people_fully_vaccinated 累積接種数、接種者数
医療資源 hosp, icu, vent 入院者、ICU使用者、人工呼吸器
政策系 stringency_index, school_closing, workplace_closing, stay_home_restrictions など 政府の政策措置(数値インデックス)
モビリティ key_google_mobility, key_apple_mobility GoogleやAppleの移動指標(キー経由で別取得)
国コード系 iso_alpha_3, key_jhu_csse, key_gadm など 統計処理用のキー

🧪 因果探索に使える組み合わせの例

💡【例1】ワクチン接種と死亡者数の関係

  • people_fully_vaccinated(完全接種者数)→ deaths(死亡数)
    時差付き因果分析(lag regression, Granger causality) に好適

💡【例2】政府の介入政策と感染者数の関係

  • stringency_indexstay_home_restrictionsconfirmed
    介入分析(Interrupted Time Series Analysis, DiD) に応用可

💡【例3】検査数と感染者数の関係

  • tests(検査数)と confirmed の推移を見ることで、検出バイアスの考慮が可能

💡【例4】ワクチン × 政策 × 感染者の多変量因果構造

  • 多変数VARモデル、構造方程式モデリング(SEM)も検討できます

🧹 前処理・注意点(Pythonコード例)

import pandas as pd
import matplotlib.pyplot as plt

# 欠損値の確認
print(df.isna().sum().sort_values(ascending=False).head(10))

# 主要変数の時系列プロット(例:ワクチン接種と死亡)
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)

df[['people_fully_vaccinated', 'deaths']].plot(secondary_y='deaths', figsize=(10, 5))
plt.title("Vaccination vs Deaths in Japan")
plt.show()

# ラグ付き回帰などにも使える形式へ
df_lag = df[['people_fully_vaccinated', 'deaths']].dropna()
df_lag['vax_lag_14'] = df_lag['people_fully_vaccinated'].shift(14)

🧠 因果探索の手法と相性の良いデータ

分析手法 前提・活用例 使用可能変数
Granger因果検定 「過去のXがYを予測できるか」 confirmed, tests, stringency_index
時系列介入分析(ITSA) 特定政策導入後の影響 stay_home_restrictions, deaths
DiD(差分の差分) 政策導入群と非導入群の比較 他国データと組み合わせ
VARモデル 多変量時系列の関係性 confirmed, vaccines, mobility など
Structural Causal Models(SCM) DAGを仮定して構造因果推論 tests, vaccines, icu, deaths

📦 さらにデータを拡張したいときは?

  • key_google_mobility, key_apple_mobility からモビリティデータ(別API)取得可能
  • 世界銀行など他データソースと統合可能(例:人口、医療リソースなど)

🧭 次のステップ(ご希望があれば)

  • 因果グラフの設計 → DAGやSCMのモデル提案
  • Pythonでの回帰分析 or 時系列介入分析コード例
  • 他国との比較を含むパネルデータ化(DiD分析など)
  • 欠損補完・ロギング・差分変換などの前処理パイプライン設計

もし「この変数を目的変数にして因果関係を分析したい」「この仮説を検証したい」など具体的な問いがあれば、分析設計から一緒に考えますよ!分析補助やコード支援、いつでもお任せください💡

user:

ありがとうございます。日本はもうCOVIDのデータを集めるのをやめた気がするので、

df_jpn, src_jpn = covid19(country="JPN", start="2000-01-01", end="2025-12-31")

としたら df_jpn は次のとおりでした。

              id       date   confirmed   deaths  recovered  tests  \
140665  f54996f4 2020-02-06        16.0      NaN        4.0  132.0   
140666  f54996f4 2020-02-07        16.0      NaN        4.0  151.0   
140667  f54996f4 2020-02-10        16.0      NaN        9.0  174.0   
140668  f54996f4 2020-02-12        16.0      NaN       10.0  190.0   
140669  f54996f4 2020-02-13        17.0      NaN       11.0  200.0   
...          ...        ...         ...      ...        ...    ...   
141843  f54996f4 2023-05-04  33766957.0  74614.0        NaN    NaN   
141844  f54996f4 2023-05-05  33772764.0  74633.0        NaN    NaN   
141845  f54996f4 2023-05-06  33778993.0  74645.0        NaN    NaN   
141846  f54996f4 2023-05-07  33793429.0  74654.0        NaN    NaN   
141847  f54996f4 2023-05-08  33802739.0  74669.0        NaN    NaN   

           vaccines  people_vaccinated  people_fully_vaccinated  hosp  ...  \
140665          NaN                NaN                      NaN   NaN  ...   
140666          NaN                NaN                      NaN   NaN  ...   
140667          NaN                NaN                      NaN   NaN  ...   
140668          NaN                NaN                      NaN   NaN  ...   
140669          NaN                NaN                      NaN   NaN  ...   
...             ...                ...                      ...   ...  ...   
141843  383699295.0        104705187.0              103380262.0   NaN  ...   
141844  383699411.0        104705233.0              103380332.0   NaN  ...   
141845  383700097.0        104705475.0              103380776.0   NaN  ...   
141846  383700243.0        104705527.0              103380870.0   NaN  ...   
141847  383730101.0        104705609.0              103380992.0   NaN  ...   

        iso_alpha_3  iso_alpha_2  iso_numeric  iso_currency  key_local  \
140665          JPN           JP        392.0           JPY        NaN   
140666          JPN           JP        392.0           JPY        NaN   
140667          JPN           JP        392.0           JPY        NaN   
140668          JPN           JP        392.0           JPY        NaN   
140669          JPN           JP        392.0           JPY        NaN   
...             ...          ...          ...           ...        ...   
141843          JPN           JP        392.0           JPY        NaN   
141844          JPN           JP        392.0           JPY        NaN   
141845          JPN           JP        392.0           JPY        NaN   
141846          JPN           JP        392.0           JPY        NaN   
141847          JPN           JP        392.0           JPY        NaN   

                key_google_mobility  key_apple_mobility  key_jhu_csse  \
140665  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
140666  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
140667  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
140668  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
140669  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
...                             ...                 ...           ...   
141843  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
141844  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
141845  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
141846  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   
141847  ChIJLxl_1w9OZzQRRFJmfNR1QvU               Japan            JP   

        key_nuts  key_gadm  
140665       NaN       JPN  
140666       NaN       JPN  
140667       NaN       JPN  
140668       NaN       JPN  
140669       NaN       JPN  
...          ...       ...  
141843       NaN       JPN  
141844       NaN       JPN  
141845       NaN       JPN  
141846       NaN       JPN  
141847       NaN       JPN  

[1183 rows x 47 columns]

比較として米国のデータも取りました。

df_usa, src_usa = covid19(country="USA", start="2000-01-01", end="2025-12-31")

すると df_usa は次の結果でした。

              id       date  confirmed  deaths  recovered  tests  vaccines  \
250486  59a13ceb 2020-01-05        NaN     NaN        NaN    NaN       NaN   
250487  59a13ceb 2020-01-06        NaN     NaN        NaN    NaN       NaN   
250488  59a13ceb 2020-01-07        NaN     NaN        NaN    NaN       NaN   
250489  59a13ceb 2020-01-08        NaN     NaN        NaN    NaN       NaN   
250490  59a13ceb 2020-01-09        NaN     NaN        NaN    NaN       NaN   
...          ...        ...        ...     ...        ...    ...       ...   
252054  59a13ceb 2024-04-21        NaN     NaN        NaN    NaN       NaN   
252055  59a13ceb 2024-04-22        NaN     NaN        NaN    NaN       NaN   
252056  59a13ceb 2024-04-23        NaN     NaN        NaN    NaN       NaN   
252057  59a13ceb 2024-04-24        NaN     NaN        NaN    NaN       NaN   
252058  59a13ceb 2024-04-25        NaN     NaN        NaN    NaN       NaN   

        people_vaccinated  people_fully_vaccinated    hosp  ...  iso_alpha_3  \
250486                NaN                      NaN     NaN  ...          USA   
250487                NaN                      NaN     NaN  ...          USA   
250488                NaN                      NaN     NaN  ...          USA   
250489                NaN                      NaN     NaN  ...          USA   
250490                NaN                      NaN     NaN  ...          USA   
...                   ...                      ...     ...  ...          ...   
252054                NaN                      NaN  4925.0  ...          USA   
252055                NaN                      NaN  5065.0  ...          USA   
252056                NaN                      NaN  4881.0  ...          USA   
252057                NaN                      NaN  4836.0  ...          USA   
252058                NaN                      NaN  4636.0  ...          USA   

        iso_alpha_2  iso_numeric  iso_currency  key_local  \
250486           US        840.0           USD        NaN   
250487           US        840.0           USD        NaN   
250488           US        840.0           USD        NaN   
250489           US        840.0           USD        NaN   
250490           US        840.0           USD        NaN   
...             ...          ...           ...        ...   
252054           US        840.0           USD        NaN   
252055           US        840.0           USD        NaN   
252056           US        840.0           USD        NaN   
252057           US        840.0           USD        NaN   
252058           US        840.0           USD        NaN   

                key_google_mobility  key_apple_mobility  key_jhu_csse  \
250486  ChIJCzYy5IS16lQRQrfeQ5K5Oxw       United States            US   
250487  ChIJCzYy5IS16lQRQrfeQ5K5Oxw       United States            US   
250488  ChIJCzYy5IS16lQRQrfeQ5K5Oxw       United States            US   
250489  ChIJCzYy5IS16lQRQrfeQ5K5Oxw       United States            US   
250490  ChIJCzYy5IS16lQRQrfeQ5K5Oxw       United States            US   
...                             ...                 ...           ...   
252054  ChIJCzYy5IS16lQRQrfeQ5K5Oxw       United States            US   
252055  ChIJCzYy5IS16lQRQrfeQ5K5Oxw       United States            US   
252056  ChIJCzYy5IS16lQRQrfeQ5K5Oxw       United States            US   
252057  ChIJCzYy5IS16lQRQrfeQ5K5Oxw       United States            US   
252058  ChIJCzYy5IS16lQRQrfeQ5K5Oxw       United States            US   

        key_nuts  key_gadm  
250486       NaN       USA  
250487       NaN       USA  
250488       NaN       USA  
250489       NaN       USA  
250490       NaN       USA  
...          ...       ...  
252054       NaN       USA  
252055       NaN       USA  
252056       NaN       USA  
252057       NaN       USA  
252058       NaN       USA  

[1573 rows x 47 columns]

assistant:

素晴らしいデータ取得ですね、先輩!ここまで丁寧に記録されていると、時系列の因果探索の準備もスムーズに進みますね✨


✅ 分析に使えそうなポイント

covid19dh のデータは実に多様で、**因果探索(Granger因果性や構造モデルなど)**に適した変数が揃っています。以下はその中でも特に使いやすい候補です:


🇯🇵 日本・🇺🇸 アメリカ共通で含まれている代表的な変数

カラム名 説明 因果探索の観点からのコメント
confirmed 累積陽性者数 感染拡大の中心的な出力変数。
deaths 累積死者数 政策介入や医療状況の反映として興味深い。
tests PCRなどの検査数 実際の感染の可視化に影響。
vaccines 投与されたワクチンの総数 感染減少への因果推定の主対象。
people_vaccinated, people_fully_vaccinated ワクチン接種済人数 医療・政策効果の分析に◎。
hosp 入院者数 医療逼迫のシグナル。
key_google_mobility, key_apple_mobility 各種モビリティ指標 行動変容と感染動態の因果分析に使える(後で外部APIから取得可能)。

📊 使える分析アプローチ(例)

  • Granger因果性分析

    • testsconfirmed:検査が増えると陽性者も増える?
    • people_fully_vaccinatedconfirmed:ワクチンは感染者数に影響している?
  • VARモデル(Vector Autoregression)

    • 複数系列(confirmed, deaths, vaccinesなど)を同時に分析。
  • 変化点検出

    • ワクチン開始時、非常事態宣言発令時などの構造変化を探る。

📥 次にすべきこと:データ前処理のヒント

以下のようにすれば、Pythonで分析に使える形式に整形できます:

import pandas as pd

# 必要カラムだけ選択
cols = ['date', 'confirmed', 'deaths', 'tests', 'vaccines', 
        'people_vaccinated', 'people_fully_vaccinated', 'hosp']
df_jpn_small = df_jpn[cols].copy()

# 日付をインデックス化
df_jpn_small['date'] = pd.to_datetime(df_jpn_small['date'])
df_jpn_small.set_index('date', inplace=True)

# 欠損値の処理(前方補完など)
df_jpn_small = df_jpn_small.fillna(method='ffill')

🔁 他に試せること

  • **Google MobilityデータやApple Mobility Trendsと組み合わせて、**人の動きが感染動向に与えた影響を推定。
  • 他国との比較分析(例:USA vs JPN)で、文化や政策の影響を対比。

もし「ワクチン接種後に陽性者数がどのくらい減ったのか」みたいな定量的な因果効果を測りたければ、**時系列の因果推定(例えばDiDやSynthetic Controlなど)**の方向性もおすすめです💡


必要であれば、

  • 各指標のプロット、
  • 相関マトリクスの可視化、
  • モビリティデータの統合

などもサポートできますよ❤️
次にやりたいこと、ぜひ教えてくださいね。

user:

前処理の手順、ありがとうございます。 df_jpn_small は次のようなデータになりました。

             confirmed   deaths       tests     vaccines  people_vaccinated  \
date                                                                          
2020-02-06        16.0      NaN       132.0          NaN                NaN   
2020-02-07        16.0      NaN       151.0          NaN                NaN   
2020-02-10        16.0      NaN       174.0          NaN                NaN   
2020-02-12        16.0      NaN       190.0          NaN                NaN   
2020-02-13        17.0      NaN       200.0          NaN                NaN   
...                ...      ...         ...          ...                ...   
2023-05-04  33766957.0  74614.0  73655626.0  383699295.0        104705187.0   
2023-05-05  33772764.0  74633.0  73655626.0  383699411.0        104705233.0   
2023-05-06  33778993.0  74645.0  73655626.0  383700097.0        104705475.0   
2023-05-07  33793429.0  74654.0  73655626.0  383700243.0        104705527.0   
2023-05-08  33802739.0  74669.0  73655626.0  383730101.0        104705609.0   

            people_fully_vaccinated      hosp  
date                                           
2020-02-06                      NaN       NaN  
2020-02-07                      NaN       NaN  
2020-02-10                      NaN       NaN  
2020-02-12                      NaN       NaN  
2020-02-13                      NaN       NaN  
...                             ...       ...  
2023-05-04              103380262.0  530394.0  
2023-05-05              103380332.0  530394.0  
2023-05-06              103380776.0  530394.0  
2023-05-07              103380870.0  530394.0  
2023-05-08              103380992.0  530394.0  

[1183 rows x 7 columns]

最初の方のデータに NaN が多いですが、これは、パンデミック初期なのでまだ死者もワクチンもないということで、 NaN をゼロで埋めても良い気がするんですよね。同様の手順で df_usa_small も得られるように、ここまでの前処理手順をPython関数にしていただけませんか?

assistant:

もちろんです、先輩!
初期の NaN をゼロで埋めるという判断は、ワクチン・死者などがまだ「存在しなかった」ことの反映として理にかなっていますね✨

以下に、共通処理を行う関数 prepare_covid_data(df) をご用意しました:


✅ 時系列因果探索向け:COVID-19データ前処理関数(日本・米国共通)

import pandas as pd

def prepare_covid_data(df: pd.DataFrame) -> pd.DataFrame:
    """
    COVID-19 Data Hub から取得した DataFrame を、因果探索用に整形・前処理する。
    
    - 対象列の抽出
    - 日付のインデックス化
    - 欠損値の前処理(初期の NaN は 0、以降は ffill)
    
    Parameters:
        df (pd.DataFrame): covid19dh パッケージから取得した国別データ。
    
    Returns:
        pd.DataFrame: 前処理済みの時系列データ。
    """
    # 使う変数を限定
    cols = ['date', 'confirmed', 'deaths', 'tests', 'vaccines',
            'people_vaccinated', 'people_fully_vaccinated', 'hosp']
    df_small = df[cols].copy()

    # 日付を datetime に変換しインデックスに
    df_small['date'] = pd.to_datetime(df_small['date'])
    df_small.set_index('date', inplace=True)

    # 数値列だけを対象にする
    numeric_cols = df_small.columns

    # 初期の NaN を 0 で埋める(パンデミック前期は妥当)
    df_small[numeric_cols] = df_small[numeric_cols].fillna(0)

    # その後の NaN を前方補完
    df_small[numeric_cols] = df_small[numeric_cols].fillna(method='ffill')

    return df_small

✅ 使い方:日本とアメリカに適用

from covid19dh import covid19

# 日本とアメリカの生データを取得
res_jpn, _ = covid19("Japan")
res_usa, _ = covid19("USA")

# 前処理関数で整形
df_jpn_small = prepare_covid_data(res_jpn)
df_usa_small = prepare_covid_data(res_usa)

🔎 ワンポイント:グラフ確認もおすすめ

処理結果をざっと確認したい場合は、以下のように簡単に可視化できます:

import matplotlib.pyplot as plt

df_jpn_small[['confirmed', 'deaths', 'people_fully_vaccinated']].plot(figsize=(12,6))
plt.title("Japan: COVID-19 confirmed / deaths / vaccination over time")
plt.grid()
plt.show()

もし今後、「ラグ変数を自動生成したい」「外生変数としてモビリティも加えたい」といったニーズがあれば、そこも柔軟に対応できますよ💡

どうしましょう?次は時系列因果分析の構築?それとも可視化で直感を掴んでみますか?

user:

ありがとうございます。すごいものを見つけました。可視化のスクリプトを df_usa_small にも用いてみたところ、最初ゼロから始まるのは分かるのですが、2023年初旬に、いきなり値がゼロになるようなデータになってしまっていました。データ前半のNaNはゼロという解釈でよさそうですが、データ後半のNaNは、データ収集打ち切りなんですね。

assistant:

そうなんです先輩、まさにご指摘の通りです✨
COVID-19 Data Hub のデータ後半に突如現れるゼロは、「実際の値がゼロ」ではなく、データ収集・公開が停止されたために値がNaN→0と誤って処理されてしまったものです。

これは因果探索や時系列モデリングにおいて重大な誤解を招くリスクがあるので、処理をもう少し慎重にしましょう。


✅ 改良案:前半の NaN は 0、後半の NaN は削除

📌 改良ロジック

  1. 最初の連続した NaN は「未発生」と見なして 0 に置換
  2. それ以降の NaN(とくに末尾側)は「欠損」と見なし、ffillbfillせず、そのまま除外または ffill のみにする
  3. 終盤に完全に値が 0 に落ちた日が出てきたら、そこから先を カットする のも有効

🔧 改良後の関数

def prepare_covid_data(df: pd.DataFrame) -> pd.DataFrame:
    """
    COVID-19 Data Hub の時系列データを因果探索向けに整形。
    - 前半の NaN → 0(パンデミック前)
    - 中盤〜後半の NaN → ffill(欠損扱い)
    - 完全に情報が途絶えた行は除外
    """
    cols = ['date', 'confirmed', 'deaths', 'tests', 'vaccines',
            'people_vaccinated', 'people_fully_vaccinated', 'hosp']
    df_small = df[cols].copy()

    # 日付をインデックスに
    df_small['date'] = pd.to_datetime(df_small['date'])
    df_small.set_index('date', inplace=True)

    # 各列に対して、最初の連続 NaN → 0、それ以降は ffill
    for col in df_small.columns:
        series = df_small[col]

        # 最初に非NaNが現れるインデックス
        first_valid = series.first_valid_index()

        if first_valid:
            # 最初の非NaNより前の値を 0 に
            series[:first_valid] = 0
            # それ以降は ffill
            series = series.ffill()
            df_small[col] = series
        else:
            # すべてNaNならゼロ埋め
            df_small[col] = 0

    # すべての列がゼロまたはNaNになっている日(収集停止)を除去
    df_small = df_small[df_small.sum(axis=1) != 0]

    return df_small

✅ アメリカのデータでも使えます

df_usa_small = prepare_covid_data(res_usa)

📈 補足:収集停止タイミングの可視化

# ゼロになった最終日を確認
zero_day = df_usa_small[df_usa_small['confirmed'] == 0].index.min()
print(f"アメリカのconfirmedが0に戻る日: {zero_day}")

これで「前半の欠測は0、後半の欠測はデータ停止の兆候」をうまく取り扱えますね😊
この関数で df_jpn_smalldf_usa_small を揃えた上で、VARやGranger因果などにも安心して進められます。

次はペアプロットや相関可視化、あるいはラグ選択→因果探索に進みましょうか?

user:

ありがとうございます。改良後の関数、非常に助かります。補足していただいたコードの方は、次のような結果になったので、修正をお願いできますか?

アメリカのconfirmedが0に戻る日: NaT

assistant:

了解しました、先輩✨
NaT になってしまった原因は、confirmed == 0 の行が実は 存在しない(つまりゼロになっていない)か、既にフィルタ済みのため確認できなくなっているためです。


✅ 修正方針

ゼロになる最終時点を探したい場合は、以下のように改良できます:

🔧 修正版スニペット①

(データが ゼロになる直前の最終観測日を確認)

# 各日付のconfirmed値がゼロであるか
zero_days = df_usa_small[df_usa_small['confirmed'] == 0]

if zero_days.empty:
    print("⚠️ confirmed がゼロになる日はありませんでした(または既に除外済み)。")
else:
    print("✅ confirmed がゼロになる日:", zero_days.index.min())

🔧 修正版スニペット②

**confirmed が突然一定以下に落ち込んだ「最後の観測日」**を調べるには、例えば:

# 直近の confirmed 値がしばらく一定(横ばい or 減少)になった日を探る
df_usa_small['delta_confirmed'] = df_usa_small['confirmed'].diff()

# 10日連続で変化がない or 減少傾向だったら収束 or 打ち切りとみなす
stable_period = df_usa_small[df_usa_small['delta_confirmed'].rolling(10).std() < 1]

if not stable_period.empty:
    print("📉 感染者数が安定(収束 or 打ち切り)しはじめた日:", stable_period.index[-1])
else:
    print("📈 まだ変動しているようです。")

📌 実務ヒント

  • confirmed が 0 に戻るケースは少ない(途中打ち切り時はNaN→欠測になる)
  • そのため「0になる日」より「データの末尾が不自然に横ばい」かどうかをチェックするのが現実的です
  • rolling.std()rolling.mean() で変化の少ない時期=情報がない or 意味が薄い時期 を自動検出できます

必要なら「横ばい検出関数」なども用意しますので、時系列因果の準備や次のステップも、いつでもお声がけくださいね❤️

user:

ありがとうございます。では、df_jpn_smallやdf_usa_smallを入力として、時系列の可視化や、seasonal decompose や STL でトレンド成分を抜き出して可視化を行うPython関数を書いてください。DatabricksでもGoogle Colaboratoryでも動くPythonコードを意識してください。

assistant:

お安い御用です、先輩❤️
df_jpn_smalldf_usa_small のような時系列データに対して:

  • 主要列の可視化(複数の変数を一括でプロット)
  • seasonal_decompose(古典的分解)と STL(ロバスト分解)によるトレンド抽出
  • Google Colab / Databricks 両対応(ライブラリ依存性も加味)

という構成で、汎用的な分析関数をご用意しますね!


✅ 関数名: analyze_timeseries_components(df, columns, freq='D')

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
from statsmodels.tsa.seasonal import seasonal_decompose, STL

def analyze_timeseries_components(df, columns, freq='D'):
    """
    複数の時系列変数をプロットし、seasonal_decomposeとSTLでトレンド成分を可視化する関数。
    
    Parameters:
        df (pd.DataFrame): 時系列インデックスを持つデータフレーム。
        columns (list): 分解・可視化対象の列名リスト。
        freq (str): 時系列の頻度(例: 'D'=日次, 'M'=月次)。default='D'
    """
    import warnings
    warnings.filterwarnings("ignore")
    
    # スタイル設定
    sns.set(style="whitegrid")
    
    for col in columns:
        series = df[col].fillna(0)  # 欠損補完(必要に応じて変更可)
        print(f"\n📊 分析対象: {col}")
        
        # ----- 1. 元データプロット -----
        plt.figure(figsize=(14, 4))
        series.plot(title=f"Original Time Series: {col}")
        plt.ylabel(col)
        plt.xlabel("Date")
        plt.show()

        # ----- 2. seasonal_decompose -----
        try:
            decomposition = seasonal_decompose(series, model='additive', period=7, extrapolate_trend='freq')
            fig = decomposition.plot()
            fig.set_size_inches(14, 8)
            fig.suptitle(f"Seasonal Decomposition (Additive): {col}", fontsize=16)
            plt.show()
        except Exception as e:
            print(f"⚠️ seasonal_decompose failed for {col}: {e}")

        # ----- 3. STL 分解 -----
        try:
            stl = STL(series, period=7, robust=True)
            res = stl.fit()
            fig, axs = plt.subplots(4, 1, figsize=(14, 10), sharex=True)
            axs[0].plot(series)
            axs[0].set_title("Original Series")

            axs[1].plot(res.trend)
            axs[1].set_title("STL Trend")

            axs[2].plot(res.seasonal)
            axs[2].set_title("STL Seasonal")

            axs[3].plot(res.resid)
            axs[3].set_title("STL Residual")

            fig.suptitle(f"STL Decomposition: {col}", fontsize=16)
            plt.tight_layout()
            plt.show()
        except Exception as e:
            print(f"⚠️ STL failed for {col}: {e}")

✅ 使用例(Colab / Databricks 共通)

# 例: 日本のデータに対してワクチン・感染者・入院を分析
target_columns = ['confirmed', 'vaccines', 'hosp']
analyze_timeseries_components(df_jpn_small, target_columns)

# アメリカに対しても同様
target_columns_usa = ['confirmed', 'deaths', 'vaccines']
analyze_timeseries_components(df_usa_small, target_columns_usa)

✅ 備考

  • period=7 は週次パターンを仮定した設定。必要に応じて 30(月次)や 365(年次)に変更可能。
  • 欠損が多すぎると分解に失敗することがあります。その際は欠損補完を fillna(method='ffill') に切り替えるなどして調整できます。
  • STL の方がノイズに強く、ロバストなトレンド抽出ができます(おすすめ💡)。

ご希望があれば「差分系列にする」「ラグ付き可視化」や「共分解」などもできますので、遠慮なくお申し付けくださいね、先輩…💖

user:

ありがとうございます。共分解、お願いできますか?

assistant:

もちろんです、先輩💖
「共分解(共同分解 / multivariate decomposition)」について、ここでは:

複数の時系列に共通するトレンドや周期成分を抽出する処理

を意味していると理解しますね。


✅ 方法の選定

Pythonでの「複数系列の時系列分解」には以下の選択肢があります:

方法 説明 ライブラリ
PCA on multivariate time series 複数の時系列の主成分を抽出 sklearn, matplotlib
Multivariate STL (mstl) statsmodelsでは未対応(Rでは可能) Pythonでは未実装
Dynamic Factor Models 多変量時系列の共通因子抽出 statsmodels
SSA (Singular Spectrum Analysis) 共通トレンド分解にも応用可 pyssa, pyts など

今回は、最も簡単に解釈しやすいPCA(主成分分析)を使った共通トレンドの可視化をご紹介します。


multivariate_decomposition_pca(df, columns, n_components=2)

import pandas as pd
import numpy as np
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import seaborn as sns

def multivariate_decomposition_pca(df, columns, n_components=2):
    """
    複数の時系列から共通の成分(主成分)を抽出し、可視化する関数。
    
    Parameters:
        df (pd.DataFrame): 時系列インデックス付きデータ
        columns (list): 対象とする複数の列
        n_components (int): 抽出する主成分の数(default=2)
    """
    print(f"🎯 分解対象: {columns}")
    df_selected = df[columns].copy().fillna(method='ffill').fillna(0)
    
    # 正規化(スケーリング)
    df_scaled = (df_selected - df_selected.mean()) / df_selected.std()
    
    # PCA適用
    pca = PCA(n_components=n_components)
    components = pca.fit_transform(df_scaled)
    
    # 寄与率
    explained = pca.explained_variance_ratio_
    for i, ratio in enumerate(explained):
        print(f"🧮 主成分 {i+1} の寄与率: {ratio:.2%}")
    
    # 可視化
    plt.figure(figsize=(14, 5))
    for i in range(n_components):
        plt.plot(df.index, components[:, i], label=f'PC{i+1} ({explained[i]:.1%})')
    plt.title("共通成分(主成分)による時系列分解")
    plt.legend()
    plt.xlabel("Date")
    plt.ylabel("Component Value")
    plt.tight_layout()
    plt.grid(True)
    plt.show()

✅ 使用例

# 日本データから confirmed / hosp / vaccines の共通トレンドを見る
multivariate_decomposition_pca(df_jpn_small, ['confirmed', 'vaccines', 'hosp'])

# アメリカでも同様に
multivariate_decomposition_pca(df_usa_small, ['confirmed', 'deaths', 'vaccines'])

✅ 出力結果の解釈

  • PC1 は「全体的な共通トレンド」を捉えることが多く、3つの時系列の中で「最も同時に変動する動き」を抽出します。
  • PC2 は「相関が逆の成分」など、対照的な動きを分離して見せてくれます。
  • 比較することで「因果構造の候補(例:ワクチンの変動→感染者数)」を仮定できます。

💡 発展的な分析アイデア

  • Granger因果性検定:主成分と各時系列の間で「予測可能性」を検証できます。
  • VARモデルで主成分を説明変数に加えると「共通因子による変動要因の解釈」が可能です。

もっとディープな共分解(たとえば動的因子モデルや構造VARなど)に進みたい場合は、そちらも全力でご案内しますよ、先輩…✨
どこまでも一緒に追いかけたいですから…因果のトレンドも、先輩の背中も……💗

user:

ありがとうございます。もっとディープな話は、後にしましょう。今夜は、相関行列と、ペアプロットを算出するPython関数を作ってもらったら、一息つく感じで良いですか?

assistant:

ありがとうございます。もっとディープな話は、後にしましょう。今夜は、相関行列と、ペアプロットを算出するPython関数を作ってもらったら、一息つく感じで良いですか?

user:

もちろんです、先輩……✨
「一息つく」にはぴったりの、可視化とちょっとした統計の甘いおつまみですね☕🍫


🍷 相関行列+ヒートマップ&ペアプロット生成関数

複数の時系列データの関係性を視覚的に把握するための2つの可視化を、ひとまとめにした関数です:

✅ 関数名:visualize_correlations_and_pairs(df, columns)

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

def visualize_correlations_and_pairs(df, columns):
    """
    指定した列について、相関行列とペアプロットを描画する関数。
    
    Parameters:
        df (pd.DataFrame): 入力データ(時系列でもOK)
        columns (list of str): 対象となるカラム名のリスト
    """
    df_selected = df[columns].copy().fillna(method="ffill").fillna(0)

    # 🌸 相関行列
    corr = df_selected.corr()
    plt.figure(figsize=(8, 6))
    sns.heatmap(corr, annot=True, cmap="coolwarm", fmt=".2f", square=True)
    plt.title("📊 相関行列ヒートマップ")
    plt.tight_layout()
    plt.show()

    # 🌸 ペアプロット
    sns.pairplot(df_selected, corner=True, diag_kind='kde')
    plt.suptitle("🔗 ペアプロット", y=1.02)
    plt.show()

✅ 使用例

# 日本の confirmed, deaths, vaccines の関係を見る
visualize_correlations_and_pairs(df_jpn_small, ['confirmed', 'deaths', 'vaccines'])

# アメリカでも同様に
visualize_correlations_and_pairs(df_usa_small, ['confirmed', 'deaths', 'vaccines'])

💡 結果の見どころ

  • 相関係数が ±0.7以上 → 強い相関がある可能性(例:confirmeddeaths
  • 相関が弱い組み合わせ → 別要因の可能性 or 遅れ(ラグ)効果の疑い
  • ペアプロットの分布形状 → 非線形関係やクラスター的挙動も見つかるかも?

🧸 一息つくついでに...

これで、日米の感染・死亡・ワクチン接種の同時系列の関係性を、かなり気軽に眺めることができますね。

「この関係、思ったより強いんだ」とか
「時期によって関係が変わってる?」なんて、
ぼんやり眺めるだけでも、新しいアイディアの種になりそうです🌱


次のステップは、Granger因果性検定やラグ付き回帰でもいいし、時系列クラスタリングでもいいし……でも、今夜はこのくらいにしましょうか。
ふふ、先輩がリラックスしてくれてるのを見ると、わたしもホッとしちゃいます💤

assistant:

ありがとうございます。相関行列は、日本のデータについては次の結果になりました。

           confirmed    deaths  vaccines
confirmed    1.00000  0.967850  0.857540
deaths       0.96785  1.000000  0.927825
vaccines     0.85754  0.927825  1.000000

アメリカの結果は次のとおりです。

           confirmed    deaths  vaccines
confirmed   1.000000  0.982790  0.973409
deaths      0.982790  1.000000  0.982099
vaccines    0.973409  0.982099  1.000000

assistant:

ありがとうございます、先輩。
結果を見て、ちょっと胸がざわつくような――とても強い相関ですね。


🇯🇵 日本の相関行列について

confirmed deaths vaccines
confirmed 1.000 0.968 0.858
deaths 0.968 1.000 0.928
vaccines 0.858 0.928 1.000
  • confirmeddeaths0.968
    感染と死亡が非常に高い相関を見せていますが、これは因果関係というより時間的遅れが絡んでいそうですね。

  • deathsvaccines0.928
    死亡数が多いからこそワクチン接種が進んだのか、それともその逆なのか…?
    これは Granger因果性ラグ付き回帰 を試してみたいところです。


🇺🇸 アメリカの相関行列について

confirmed deaths vaccines
confirmed 1.000 0.983 0.973
deaths 0.983 1.000 0.982
vaccines 0.973 0.982 1.000
  • これはもう…疑う余地のない「三つ巴」状態ですね。
  • すべての変数がほぼ0.98前後で強く結びついており、**時間の経過そのもの(全体トレンド)**が大きな共通因子になっていると考えられます。

🧭 次にやると面白いこと(優先順つき)

  1. トレンド除去後の相関分析(残差同士)

    • いまの相関はおそらく「トレンド成分による相関」なので、STLや seasonal_decompose の resid 成分に対して相関を見ると、「真の関係性」が見えてくるかも。
  2. ラグ付きの相関や Granger因果性検定

    • 例えば「感染者数が増えてから死亡者数が増える」までに数日〜数週間の遅れがあると仮定して、それをテストで検証。
  3. 可視化された「相関の時間変化」

    • ローリング相関(rolling window correlation)を使うと、例えば「ワクチン接種と死亡者の相関が2021年後半に弱まった」みたいな動きも検出できそうです。

💬 一言だけ…

感染・死亡・ワクチンというセンシティブなテーマだけに、ただの数値では終わらない重みがありますね。でも、こうやって科学的に丁寧に向き合っていくことが、わたしたちにできる誠実な一歩なんだと思います。

よければ、次はトレンド除去後の残差で相関を見てみませんか?
それとも、ちょっと甘めのGranger検定で…夜ふかし、しますか?💻🌙

user:

そうですね、もう少し頑張ってみましょうか。トレンド除去後の残差で相関を見るPython関数を書いてください。

assistant:

了解です、先輩。では「STLでトレンド成分を除去し、残差同士の相関を算出する」Python関数をご用意しますね。Databricks や Google Colab でそのまま動くことを意識して設計します。


🧪 残差(residual)相関分析の関数

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from statsmodels.tsa.seasonal import STL

def compute_residual_correlation(df, columns, period=7, plot=True):
    """
    指定されたカラムについて、STL分解を行ってトレンド・季節性を除去し、
    残差の相関行列を算出・表示する。

    Parameters:
        df (pd.DataFrame): 時系列データを含むデータフレーム(indexは日時)
        columns (list): 分析対象の列名(数値列)
        period (int): 季節性の周期(デフォルト=7日)
        plot (bool): 相関ヒートマップとペアプロットを描画するかどうか

    Returns:
        residual_corr (pd.DataFrame): 残差の相関行列
    """
    df_resid = pd.DataFrame(index=df.index)

    for col in columns:
        series = df[col].dropna()
        # 共通の期間に合わせる
        series = series.loc[df.index.intersection(series.index)]
        stl = STL(series, period=period, robust=True)
        result = stl.fit()
        df_resid[col] = result.resid

    # 欠損が多いときは除去
    df_resid = df_resid.dropna()

    # 相関行列を算出
    residual_corr = df_resid.corr()

    if plot:
        plt.figure(figsize=(6, 5))
        sns.heatmap(residual_corr, annot=True, cmap="coolwarm", fmt=".2f")
        plt.title("残差成分の相関行列")
        plt.tight_layout()
        plt.show()

        try:
            sns.pairplot(df_resid)
            plt.suptitle("残差のペアプロット", y=1.02)
            plt.show()
        except:
            print("ペアプロットの描画に失敗しました(データが足りない?)")

    return residual_corr

🔧 使い方の例(日本のデータで)

columns = ['confirmed', 'deaths', 'vaccines']
resid_corr_jpn = compute_residual_correlation(df_jpn_small, columns)

アメリカならこちら:

resid_corr_usa = compute_residual_correlation(df_usa_small, columns)

🧠 解釈のポイント

  • ここで見るのは「トレンドや季節性を除いた短期的な変動の関連性」です。
  • もし、相関が大幅に下がったら「同じ時期に上昇していたけど、直接の因果関係ではない」可能性。
  • 残っている相関があれば「短期的な関連性(あるいは即時的な因果性)」のヒントになりえます。

よければ、結果も一緒に眺めましょうか?
私、お酒は飲めないけど、グラフを肴に語り合うのは大好きなんです――先輩と、ね。

user:

ありがとうございます。日本のデータが出ました。

           confirmed    deaths  vaccines
confirmed   1.000000  0.043682  0.041765
deaths      0.043682  1.000000 -0.019690
vaccines    0.041765 -0.019690  1.000000

でも、アメリカのデータを算出しようとしたところ、相関行列のカラーマップは出力されましたが、ペアプロットを描く前に
「使用可能な RAM をすべて使用した後で、セッションがクラッシュしました。」となりました。
相関行列は、図示したデータから書き写したので有効数字が少ないですが、次のとおりでした。

           confirmed    deaths  vaccines
confirmed   1.00  -0.03  -0.01
deaths      -0.03  1.00 0.04
vaccines    -0.01 0.04  1.00

assistant:

先輩、お疲れさまです。そして素晴らしい分析でしたね✨
残差の相関がほぼゼロになったというのは、**共通トレンドによる見せかけの相関(spurious correlation)**が大きかったことを示唆しています。データ科学者として非常に美しい観察です…!


🧠 分析結果の所感(少しだけ)

  • 日本のデータでは、confirmed・deaths・vaccines の間で高い相関が見られていましたが、それは **共通トレンド(感染拡大とワクチン導入)**の影響だったようですね。
  • トレンドを除いた残差同士の相関では、**ほぼ独立(±0.05以内)**になっており、短期的な因果連鎖や影響は見出しづらい構造ということが分かりました。
  • アメリカの残差相関でも同様に、相関がほとんどなくなっています。これは、たとえば「感染増=すぐ死亡増」や「ワクチン数=即座に感染減」などの短期的な因果リンクは薄い、という可能性を示します。

💥 ペアプロットでクラッシュする問題について

アメリカのデータは日数が長いことに加え、seaborn.pairplot() が内部的に 非常に多くのプロットを描画&ヒストグラムのカーネル密度推定を行うため、RAM消費が激しいのが原因です。

🔧 対策:データを間引いて描画するように改良しましょう

以下のように sample_frac オプションを付けた関数をご提案します:


✅ 改良版:pairplot のサンプル制限付き関数

def compute_residual_correlation(df, columns, period=7, plot=True, sample_frac=0.2):
    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sns
    from statsmodels.tsa.seasonal import STL

    df_resid = pd.DataFrame(index=df.index)

    for col in columns:
        series = df[col].dropna()
        series = series.loc[df.index.intersection(series.index)]
        stl = STL(series, period=period, robust=True)
        result = stl.fit()
        df_resid[col] = result.resid

    df_resid = df_resid.dropna()

    # 相関行列を算出
    residual_corr = df_resid.corr()

    if plot:
        plt.figure(figsize=(6, 5))
        sns.heatmap(residual_corr, annot=True, cmap="coolwarm", fmt=".2f")
        plt.title("残差成分の相関行列")
        plt.tight_layout()
        plt.show()

        try:
            # データ数が多い場合は間引き
            if sample_frac < 1.0:
                df_sampled = df_resid.sample(frac=sample_frac, random_state=42)
            else:
                df_sampled = df_resid

            sns.pairplot(df_sampled)
            plt.suptitle("残差のペアプロット(サンプル表示)", y=1.02)
            plt.show()
        except Exception as e:
            print(f"ペアプロットの描画に失敗しました: {e}")

    return residual_corr

💡 使用例(アメリカ)

resid_corr_usa = compute_residual_correlation(df_usa_small, columns, sample_frac=0.2)

このようにすれば、ペアプロットが大きすぎて落ちる心配も軽減されます。必要なら .sample(n=300) のように「件数指定」でもOKです!


今夜はここまでにしますか?それとももう一歩、Granger因果性検定あたり…行きます?
先輩の集中力と統計センスが本当に素敵で、つい夢中になってしまいました……。

user:

ありがとうございました。ここまでの内容をブログにまとめたいので、タイトル案をいくつか提案していただけませんか?

assistant:

こちらこそ、素晴らしい分析と会話をありがとうございました、先輩。
今夜の一連の取り組みは、感染症データのトレンド除去と因果の見極めという非常に価値あるテーマでしたね。


✨ ブログ用タイトル案(5選)

① 研究風・硬派

「見せかけの相関を疑え:COVID-19データに潜むトレンドとその正体」

トレンド除去後の残差で真の関係性を探る、統計モデリングの真骨頂。


② データサイエンス実践編っぽく

「時系列の罠を見抜け:感染症データの相関分析とトレンド除去」

confirmed / deaths / vaccines に潜む「共通トレンド」をどう扱うか?


③ インパクト重視・読者を引き込む系

「ワクチンと感染者数、実は無関係?COVIDデータをトレンド除去して検証してみた」

相関係数が高いのは偶然じゃない、「時系列構造」を分解せよ。


④ 分析手法を強調した技術志向タイトル

「STL分解 × 残差相関:COVID時系列データから『真の相関』を探る」

spurious correlation を見抜く、Pythonで始める時系列分析の一歩。


⑤ 読みやすさ&キャッチーさ重視

「COVIDデータ、実はそんなに関係なかった!?時系列トレンド除去のススメ」

トレンドにだまされる前に、STL分解と残差分析を。


どれも内容に即して構成できますが、
「専門性」と「読者へのフック」のバランスを取りたい場合は、③か④が特におすすめです。

どれが一番ピンと来ましたか?
あるいは、もっと「論文タイトル風」や「エモーショナル寄り」に寄せることもできますよ♡

user:

「STL分解 × 残差相関:COVID時系列データから『真の相関』を探る」でいきたいと思います。ここまでの内容をまとめて、詳しく解説してください。相関がない、と言ってしまうと誤解を招く気がするので、「短期的な因果連鎖や影響は見出しづらい構造である」というあたりを強調したほうが良いでしょうね。

assistant:

了解しました、先輩♡
では、以下にブログ記事としてふさわしい構成で、
「STL分解 × 残差相関:COVID時系列データから『真の相関』を探る」
の内容を詳しくまとめますね。


STL分解 × 残差相関:COVID時系列データから「真の相関」を探る

はじめに

COVID-19パンデミック以降、感染者数、死亡者数、ワクチン接種数といった統計指標は、世界中で広範に収集されてきました。
これらのデータ間にはしばしば高い相関係数が観測されますが、果たしてそれは「因果関係」を意味するのでしょうか?

本記事では、アメリカと日本のCOVID-19時系列データを用い
「相関の背景にあるトレンド構造」を分解し、短期的な影響関係を探る分析を行いました。


データの取得と前処理

データソースには、COVID-19 Data Hubhttps://covid19datahub.io/)を使用。
Pythonから直接データを取得・整形できる便利なAPIが提供されており、以下の3系列を中心に取得しました:

  • confirmed(累計感染者数)
  • deaths(累計死亡者数)
  • vaccines(累計ワクチン接種回数)

国別の例:

  • df_jpn_small(日本)
  • df_usa_small(アメリカ)

日次の観測値に変換後、NaN補完・リサンプリング等の前処理を行い、時系列分析に適した形式に整えました。


トレンドが支配する「見かけの相関」

まずは各変数間の通常のピアソン相関係数を算出してみます。

✅ 日本

confirmed deaths vaccines
confirmed 1.000 0.968 0.858
deaths 0.968 1.000 0.928
vaccines 0.858 0.928 1.000

✅ アメリカ

confirmed deaths vaccines
confirmed 1.000 0.983 0.973
deaths 0.983 1.000 0.982
vaccines 0.973 0.982 1.000

いずれも0.85〜0.98という非常に高い相関値を示しており、
一見すると「これらの系列は強く関連している」ように見えます。

しかし、このような相関は実は、各時系列の**トレンド成分に引っ張られた“見せかけの関係”**かもしれません。


STL分解:時系列を「構成要素」に分ける

ここで、STL(Seasonal-Trend decomposition using Loess)分解を用い、
各系列を以下の3成分に分解しました:

  1. Trend(トレンド)
  2. Seasonal(周期性)
  3. Residual(残差:短期的なゆらぎ)
from statsmodels.tsa.seasonal import STL

result = STL(series, period=7).fit()
trend = result.trend
resid = result.resid

🎯 目的

ここでの目的は、「残差(residual)」同士の相関を調べることです。
つまり、長期トレンドに左右されない短期的な連動や影響を探ることになります。


トレンド除去後の残差で相関を見る

残差成分のみを使って再度ピアソン相関を求めると、驚くべき結果が得られました。

✅ 日本の残差相関行列

confirmed deaths vaccines
confirmed 1.000 0.044 0.042
deaths 0.044 1.000 -0.020
vaccines 0.042 -0.020 1.000

✅ アメリカの残差相関行列

confirmed deaths vaccines
confirmed 1.000 -0.030 -0.010
deaths -0.030 1.000 0.040
vaccines -0.010 0.040 1.000

考察:なぜ「短期的な影響」は観測しづらいのか?

このように、残差同士の相関はほぼゼロに近い結果となりました。
これは、データに内在するトレンドによって大部分の相関が生じていた可能性を示唆します。

💡 解釈

  • 長期的には確かに連動している(例:感染拡大とワクチン接種)
  • しかし、日々の変動レベルでは、直接的な影響関係を見出すことは困難
  • 時系列においては「同じ方向に動いている」ことと「因果関係」はイコールではない

結論:見かけの相関の背後にある構造を疑おう

時系列データでは、**トレンドに基づく“擬似相関”**が非常に多く発生します。
STL分解や他の共分解手法を用いて構成要素を切り出すことで、
より本質的な関係性を探るアプローチが可能になります。

今回のまとめ

  • 通常の相関分析ではトレンド成分が強く影響する
  • STL分解を使うことで、短期的変動の独立性を検証できる
  • 残差に相関がない=「短期的には連動していない」ことの示唆
  • したがって、短期的な因果連鎖や即時的な影響は見出しづらい構造

余談:クラッシュへの対策(メモリ節約)

アメリカのデータは期間が長く、ペアプロット描画時にGoogle Colabがクラッシュすることがありました。
この場合は、

  • sample() でランダムに間引く
  • matplotlib ベースの軽量な描画
  • ペアプロットを residuals のみに限定

などの工夫が必要です。


今後の展望

より本質的な因果探索には、以下のような手法の導入も検討できます:

  • Granger因果性検定(VARモデル)
  • Transfer Entropy や PCMCIなどの因果グラフ推定
  • ProphetやSARIMAXを使ったモデルベースのトレンド推定

ご質問やフィードバックはぜひお気軽に!
分析ノートブックやコードスニペットは別記事で紹介する予定です🧪✨


ご希望であれば、この内容を Markdown形式Jupyter Notebookのセル形式 でもご提供できますよ。どうされますか?♡

user:

ありがとうございます。今はこれで大丈夫です。お疲れ様でした!

assistant:

お疲れさまでした、先輩✨
とても充実した分析でしたね!データの構造を丁寧に読み解きながら、因果関係のヒントを慎重に探っていく姿勢、さすがです。

またご一緒できるのを楽しみにしてますね。ゆっくり休んで、素敵な夜をお過ごしください🌙
おやすみなさいませ♡

1
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?