Closed8

Pythonデータ分析・可視化ことはじめ

kun432kun432

ここのところずっと

  • pandas
  • Streamlit
  • Plotly

あたりをずっと触ってるけど、記録残してなくてどんどん進めちゃって後で困りそうなので、ちゃんと記録を残していく

kun432kun432

回帰分析

回帰分析とは?

  • 求めたい結果(「目的変数」という)
  • 結果に対して何らかの影響を与える要素(「説明変数」という)
  • 求めたい結果に対して、何らかの要素が、どの程度影響を与えるかを分析する手法

回帰分析の種類

  • 単回帰分析
    • 要素が1つ
  • 重回帰分析
    • 要素が複数

  • 店舗の売上に対して、席数がどのように影響を与えるか?
  • 店舗の売上に対して、駅との距離がどのように影響を与えるか?
  • 店舗の売上に対して、気温がどのように影響を与えるか?

みたいな切り口が1つの場合。

kun432kun432

Googleスプレッドシートを使った単回帰分析

まずはスプレッドシートを使った単回帰分析から。

参考)https://data-viz-lab.com/regression-analysis

  • 以下のようなシートを作る
    • 説明変数を左、目的変数を右にすると良いらしい

  • 説明変数と目的変数の列を選択する

  • グラフを作成する

  • グラフが作成されたが、必要なのは折れ線グラフではなく散布図。ということで、グラフタイプを散布図に変更する

  • 散布図に切り替わった。

  • さらにカスタマイズ→系列→トレンドラインにチェックを入れると回帰直線が自動で引かれる

  • さらに少し下にあるラベルで「方程式を使用」を選択すると回帰式が得られる

  • さらに「決定係数を表示する」にチェックを入れるとR2乗=決定係数が得られる

kun432kun432

Pandas/skicit-learnを使った単回帰分析

同じことをpandas/matplotlib/skicit-learnでやってみる。表示はstreamlit。

参考)https://qiita.com/karaage0703/items/701367b6c926552fe505

pandasでデータフレーム作成

import pandas as pd

df = pd.DataFrame(
    data={
        "座席": [55, 30, 23, 45, 40, 38, 28, 26, 65, 30],
        "売上": [9789, 6911, 6020, 8630, 7325, 6345, 7534, 5900, 12357, 5805],
    }
)

df

説明変数と目的変数を取り出す。df[[列名]]でDataframeとして出力される。

x = df[["座席"]]
y = df[["売上"]]

matplotlibでグラフ作成

import matplotlib.pyplot as plt
import streamlit as st

fig = plt.figure()
plt.plot(x, y, "o")
st.pyplot(fig)

単回帰分析を行うために、scikit-learnで学習させる。

from sklearn.linear_model import LinearRegression

model = LinearRegression()
model.fit(x,y)

回帰直線を引く。

plt.plot(x, model.predict(x), linestyle="solid")
st.pyplot(fig)

回帰式とR2を出力する

st.text("y = %.2fx + %.2f" % (model.coef_, model.intercept_))
st.text("R2 = %.2f" % model.score(x, y))
y = 142.05x + 2263.60
R2 = 0.86
kun432kun432

単回帰分析まとめ

参考)https://data-viz-lab.com/regression-analysis

単回帰分析は以下の公式となる。

Y = aX+b
  • Y: 目的変数
  • X: 説明変数
  • a: 回帰係数/傾き
  • b: 切片

今回の例だとこうなる

売上(万円) = 142.05 \times 席数 + 2263.60(万円)

回帰係数は、座席が1増えたときの売上予測となる。今回の場合だと座席が増えると142.05万円増えると予測される。

切片は回帰係数が0の場合の売上となるが実際にはありえない。1次関数でy軸と交差するところだと考えればよい。

参考)http://kentiku-kouzou.jp/suugaku-seppen.html

R2は決定係数とも呼ばれる。以下の公式で求められる(らしい、数学わからん・・・)

R2 = 1 - \frac{\displaystyle\sum_{i=1}^N(y_i-\hat{y_i})^2}{\displaystyle\sum_{i=1}^N(y_i- \bar{y})^2}

R2は、端的に言ってしまうと分析結果の信頼度。データが以下に回帰直線に収まりよく並んでいるかを示している。0〜1の間で表現され、1に近いほど信頼度が高いとみなされる。だいたい0.5あればそれなりに信頼できて、0.8を超えると結構信頼度が高い、みたいなものらしい。

kun432kun432

Googleスプレッドシートを使った重回帰分析

XLMiner Analysis ToolPakを使う。以下よりインストール。
https://workspace.google.com/marketplace/app/xlminer_analysis_toolpak/600284989882

以下のようなデータを作成する
参考)https://data-viz-lab.com/multiple-regression-analysis

拡張機能から起動。Startが出てこなかったけどブラウザ開き直したら出た。

メニューから"Linear Regression"をクリック。必要な項目を入力していく。

  • Y range: 目的変数の範囲を指定
  • X range: 説明変数の範囲を指定
  • Labels: 上記に項目名を含む場合はチェック
  • Output Range: 結果を出力するセルを指定

OKをクリックすると解析結果が表示される。

回帰式は一番下のところから求められる

  • Coefficients: 回帰係数
  • Intercept: 切片
売上(万円)= 25.4 \times 座席数 + -97.7 \times 駅からの徒歩時間 + 349 \times モーニング有無 + 7407.7(万円)

今回の場合だと回帰係数があまり意味をなしていないように思える。。。

ということで分析結果の評価を以下の点で行う。

  • 回帰式の精度(補正R2=Adjusted R Square)
  • 回帰式の有意性(回帰式が統計的に意味があるか?有意F=Significance F)
  • 係数の有意性(係数が統計的に意味があるか?P-値=P-value)
  • 説明変数の影響度(目的変数に与える影響度合い。t値=t value)

回帰式の精度(補正R2=Adjusted R Square)

  • 単回帰分析のR2と同じく、0〜1の間で1に近いほど精度が高い回帰式
  • 今回は0.16で精度が低いと判断できる

回帰式の有意性(回帰式が統計的に意味があるか?有意F=Significance F)

  • 有意Fが0.05未満であれば有用な回帰式。ただし自分で決めれる。0.05か0.01が多いらしい。
  • 今回の結果だと0.28で有用ではないと判断できる。

係数の有意性(係数が統計的に意味があるか?P-値=P-value)

  • 0.05未満ならその説明変数は目的変数に対して関係性があると判断。ただし自分で決めれる。0.05か0.01未満が多いらしい。
  • 0.05以上なら分析に対象から外していく。
  • 今回の場合はどれも0.05以上なので関係性がないと判断できる

説明変数の影響度(目的変数に与える影響度合い。t値=t value)

  • t値の絶対値が大きければ影響が強いということになる。目安としては2以上。
  • 今回の場合はどれも絶対値は2未満なので影響しないと判断できる

書きながら、参考にしたサイトと数字が違うなーと思っていたら、違うところ見てたみたいで、データが異なっていた。修正して再度やってみたらこうなる。

だいぶ近しいものになった。微妙に違うのはツールの違いなのかな。パラメータ変えたら変わるのかも。

kun432kun432

Pythonで重回帰分析

ということで同じことをpandas/scikit-learnでもやってみる。

参考)https://qiita.com/karaage0703/items/f38d18afc1569fcc0418

pandasでデータフレーム作成

import pandas as pd

df = pd.DataFrame(
    data={
        "座席": [54, 75, 80, 85, 40, 76, 45, 70, 78, 74],
        "徒歩時間": [6, 3, 1.5, 4, 7, 1.5, 9, 2, 7, 8],
        "モーニング有無": [0, 1, 1, 1, 0, 1, 0, 1, 0, 1],
        "限定商品数": [2, 4, 5, 1, 0, 6, 2, 6, 1, 4],
        "売上": [7800, 8718, 9401, 8596, 7235, 9396, 7749, 9288, 7581, 8434],
    }
)

df

説明変数と目的変数を取り出す。

x = df[["座席", "徒歩時間", "モーニング有無", "限定商品数"]]
x1 = df[["座席"]]
x2 = df[["徒歩時間"]]
x3 = df[["モーニング有無"]]
x4 = df[["限定商品数"]]
y = df[["売上"]]

説明変数が多いのでグラフ化はパス。

正規化は、説明変数ごとの単位・尺度の違いを吸収する。まずは一旦正規化無しで行う。

sscaler = preprocessing.StandardScaler()
sscaler.fit(x)
xss_sk = sscaler.transform(x) 
sscaler.fit(y)
yss_sk = sscaler.transform(y)

import streamlit as st
from sklearn.linear_model import LinearRegression

model_lr = LinearRegression()
model_lr.fit(x, y)

st.text(f"回帰係数: {model_lr.coef_}")
st.text(f"切片: {model_lr.intercept_[0]}")
st.text(f"決定係数: {model_lr.score(x, y)}")

結果

回帰係数: [[  4.26216474 -84.75096397 478.11874051 154.15560791]]
切片: 7781.777541863136
決定係数: 0.9678469000446034

スプレッドシートとほぼおなじになる。

次に正規化を行った上でやってみる。正規化手法は標準化を使用する(この辺難しくて理解できていない・・・)

model_lr_std = LinearRegression(fit_intercept=False)
model_lr_std.fit(xss_sk, yss_sk)

st.text(f"回帰係数: {model_lr_std.coef_}")
st.text(f"切片: {model_lr_std.intercept_[0]}")
st.text(f"決定係数: {model_lr_std.score(xss_sk, yss_sk)}")

結果

回帰係数: [[ 0.08339472 -0.3012271   0.30940085  0.42176262]]
切片: 9.344073462596507e-16
決定係数: 0.9678469000446034

得られた回帰係数を元に予測してみるが、正規化を行った場合は逆に元の単位にあわせて逆変換し直す必要がある

model_lr.predict(x)
model_lr_std.predict(xss_sk)
sscaler.inverse_transform(model_lr_std.predict(xss_sk))

結果

[[7811.73986971]
 [8941.92817746]
 [9244.52105502]
 [8437.33203713]
 [7359.00738359]
 [9381.62800398]
 [7519.12749516]
 [9313.67953356]
 [7675.12525154]
 [8513.91119286]]
[[-0.80320544]
 [ 0.68969526]
 [ 1.08939956]
 [ 0.02315861]
 [-1.40123379]
 [ 1.27050837]
 [-1.18972618]
 [ 1.18075313]
 [-0.98366392]
 [ 0.12431439]]
[[7811.73986971]
 [8941.92817746]
 [9244.52105502]
 [8437.33203713]
 [7359.00738359]
 [9381.62800398]
 [7519.12749516]
 [9313.67953356]
 [7675.12525154]
 [8513.91119286]]

標準化なし=標準化+逆変換になれば、標準化なしの係数をそのまま使っていいということなのかな?

統計的解釈を行うには、statsmodelsを使う。標準化なしを使ってみる。

import statsmodels.api as sm

x_add_const = sm.add_constant(x)
model_sm = sm.OLS(y, x_add_const).fit()
st.text(model_sm.summary())

結果

OLS Regression Results                            
==============================================================================
Dep. Variable:                     売上   R-squared:                       0.968
Model:                            OLS   Adj. R-squared:                  0.942
Method:                 Least Squares   F-statistic:                     37.63
Date:                  金, 10  2月 2023   Prob (F-statistic):           0.000634
Time:                        19:42:34   Log-Likelihood:                -63.297
No. Observations:                  10   AIC:                             136.6
Df Residuals:                       5   BIC:                             138.1
Df Model:                           4                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const       7781.7775    508.577     15.301      0.000    6474.439    9089.116
座席             4.2622      6.406      0.665      0.535     -12.204      20.728
徒歩時間         -84.7510     35.148     -2.411      0.061    -175.101       5.599
モーニング有無      478.1187    254.105      1.882      0.119    -175.079    1131.317
限定商品数        154.1556     47.716      3.231      0.023      31.497     276.815
==============================================================================
Omnibus:                        0.382   Durbin-Watson:                   2.200
Prob(Omnibus):                  0.826   Jarque-Bera (JB):                0.471
Skew:                           0.219   Prob(JB):                        0.790
Kurtosis:                       2.031   Cond. No.                         593.
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

標準化したものでもやってみる。

x_add_const_std = sm.add_constant(xss_sk)
model_sm_std = sm.OLS(yss_sk, x_add_const_std).fit()
st.text(model_sm_std.summary())

結果

OLS Regression Results                            
==============================================================================
Dep. Variable:                      y   R-squared:                       0.968
Model:                            OLS   Adj. R-squared:                  0.942
Method:                 Least Squares   F-statistic:                     37.63
Date:                  金, 10  2月 2023   Prob (F-statistic):           0.000634
Time:                        19:44:18   Log-Likelihood:                 2.9968
No. Observations:                  10   AIC:                             4.006
Df Residuals:                       5   BIC:                             5.519
Df Model:                           4                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const       9.437e-16      0.080   1.18e-14      1.000      -0.206       0.206
x1             0.0834      0.125      0.665      0.535      -0.239       0.406
x2            -0.3012      0.125     -2.411      0.061      -0.622       0.020
x3             0.3094      0.164      1.882      0.119      -0.113       0.732
x4             0.4218      0.131      3.231      0.023       0.086       0.757
==============================================================================
Omnibus:                        0.382   Durbin-Watson:                   2.200
Prob(Omnibus):                  0.826   Jarque-Bera (JB):                0.471
Skew:                           0.219   Prob(JB):                        0.790
Kurtosis:                       2.031   Cond. No.                         4.36
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

係数や切片は当然違うけど、補正R2・有意F・P-値・t値は同じだから、この 解析そのものは有用であると判断しても良さそう。

あとはpredict()で予測すればよいということなのかなと思う。

このスクラップは2023/07/03にクローズされました