気象庁の「世界の年平均気温偏差」データから、毎年どれくらい地球が温暖化しているかを調べてみましょう。データは2023年までのものです。
import pandas as pd import matplotlib.pyplot as plt URL = "https://www.data.jma.go.jp/cpdinfo/temp/list/csv/an_wld.csv" df = pd.read_csv(URL, encoding="cp932") plt.plot(df["年"], df["世界全体"], "o-") plt.xlabel("年") plt.ylabel("年平均気温偏差")
この気象庁のデータはときどきデータに注釈記号 *
が付いてエラーになることがあります。そのときは気象庁の「世界の年平均気温偏差」データに説明した方法で切り抜けてください。
よく見ると、いったん温暖化傾向が止まりますが、1980年からはほぼ直線的に増加しています。そこで、1980年以降だけを切り出して、よく調べてみましょう。
df1 = df.query("年 >= 1980") plt.plot(df1["年"], df1["世界全体"], "o-") plt.xlabel("年") plt.ylabel("年平均気温偏差")
直線をあてはめて、その傾きを求めてみましょう。
NumPy の多項式をフィットする関数 np.polyfit(x, y, 次数)
を使うのが一番簡単です。
import numpy as np slope, intercept = np.polyfit(df1["年"], df1["世界全体"], 1) print("傾き", slope, "y切片", intercept)
傾き 0.0189 くらいです。毎年 0.0189 度だけ温暖化しています。少ないようですが、100年たつと 1.89 度の上昇になります。
さきほどのグラフに直線を追加してみましょう。
plt.plot(df1["年"], df1["世界全体"], "o-") plt.xlabel("年") plt.ylabel("年平均気温偏差") plt.plot(df1["年"], df1["年"] * slope + intercept)
さらに np.polyfit(df1["年"], df1["世界全体"], 2)
とすると、2次式であてはめて、2次の係数、1次の係数、定数項を出力します。何次式でも同様にできます(解が数値的に安定しているかは別問題です)。
t検定でも紹介したpingouinパッケージを使ってみましょう。
import pingouin as pg pg.linear_regression(df1["年"], df1["世界全体"])
names coef se T ... r2 adj_r2 CI[2.5%] CI[97.5%] 0 Intercept -37.883328 2.241121 -16.903738 ... 0.871427 0.868365 -42.406094 -33.360562 1 年 0.018891 0.001120 16.871930 ... 0.871427 0.868365 0.016632 0.021151
例によって画面の幅が狭いので省略されてしまいました。値を少し丸めてみましょう。
pg.linear_regression(df1["年"], df1["世界全体"]).round(5)
names coef se T pval r2 adj_r2 CI[2.5%] CI[97.5%] 0 Intercept -37.88333 2.24112 -16.90374 0.0 0.87143 0.86837 -42.40609 -33.36056 1 年 0.01889 0.00112 16.87193 0.0 0.87143 0.86837 0.01663 0.02115
statsmodels は R と近い統計解析の機能を Python に実装するライブラリです。あらかじめ pip install statsmodels
と打ち込んでインストールしておきます。マニュアルの statsmodels.formula.api.ols および Fitting models using R-style formulas を参照してください。
import statsmodels.formula.api as smf res = smf.ols("世界全体 ~ 年", data=df1).fit() print(res.summary())
OLS Regression Results ============================================================================== Dep. Variable: 世界全体 R-squared: 0.871 Model: OLS Adj. R-squared: 0.868 Method: Least Squares F-statistic: 284.7 Date: Wed, 07 Feb 2024 Prob (F-statistic): 2.56e-20 Time: 14:24:41 Log-Likelihood: 42.480 No. Observations: 44 AIC: -80.96 Df Residuals: 42 BIC: -77.39 Df Model: 1 Covariance Type: nonrobust ============================================================================== coef std err t P>|t| [0.025 0.975] ------------------------------------------------------------------------------ Intercept -37.8833 2.241 -16.904 0.000 -42.406 -33.361 年 0.0189 0.001 16.872 0.000 0.017 0.021 ============================================================================== Omnibus: 2.175 Durbin-Watson: 1.555 Prob(Omnibus): 0.337 Jarque-Bera (JB): 1.575 Skew: 0.259 Prob(JB): 0.455 Kurtosis: 2.231 Cond. No. 3.15e+05 ============================================================================== Notes: [1] Standard Errors assume that the covariance matrix of the errors is correctly specified. [2] The condition number is large, 3.15e+05. This might indicate that there are strong multicollinearity or other numerical problems.
2次式であてはめるには数式部分を "世界全体 ~ 年 + I(年**2)"
とします。
R で同じことをする方法:
URL = "https://www.data.jma.go.jp/cpdinfo/temp/list/csv/an_wld.csv" df = read.csv(URL, fileEncoding="cp932") df1 = subset(df, 年 >= 1980) with(df1, plot(年, 世界全体, type="o", pch=16)) r = lm(世界全体 ~ 年, data=df1) abline(r) summary(r)
結果は次のように表示されます:
Call: lm(formula = 世界全体 ~ 年, data = df1) Residuals: Min 1Q Median 3Q Max -0.157424 -0.075507 -0.009075 0.063431 0.205879 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -37.88333 2.24112 -16.90 <2e-16 *** 年 0.01889 0.00112 16.87 <2e-16 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 0.09431 on 42 degrees of freedom Multiple R-squared: 0.8714, Adjusted R-squared: 0.8684 F-statistic: 284.7 on 1 and 42 DF, p-value: < 2.2e-16
2次式にするには式の部分を 世界全体 ~ 年 + I(年^2)
とします。
SciPy の scipy.stats.linregress で単回帰ができます。
from scipy import stats stats.linregress(df1["年"], df1["世界全体"])
LinregressResult(slope=0.018891472868217057, intercept=-37.88332840028189, rvalue=0.9335024093239134, pvalue=2.5605509195046824e-20, stderr=0.0011196983660876176, intercept_stderr=2.2411213832828665)
個々の値は res = stats.linregress(df1["年"], df1["世界全体"])
して res.slope
などとして取り出せます。
scikit-learn は機械学習で標準的に使われているライブラリです。この中にも線形回帰モデルが入っています。
from sklearn import linear_model model = linear_model.LinearRegression() X = df1["年"].values.reshape(-1, 1) y = df1["世界全体"].values model.fit(X, y) print(model.coef_, model.intercept_)
[0.01889147] -37.883328400281876
Python 3.10 で標準ライブラリ statistics にも線形回帰の関数が追加されました:
import statistics as st st.linear_regression(df1["年"], df1["世界全体"])
LinearRegression(slope=0.018891472868217053, intercept=-37.88332840028188)