特別講義DS Ch12 回帰分析の応用と一般化線形モデル

資料
Published on 2024-03-29 under the tag datascience, statistics, python

Table of Contents

1 数量化

前章の重回帰分析では,すべての変数が量的データでした. しかし, 質的データがある場合にはどのように処理するのでしょうか.

説明変数に質的データを含める重回帰分析を数量化1類(Quantification Method Type I)といいます.

基本的に回帰分析における質的データは0/1からなる擬似的な量的変数であるダミー変数に変換して処理しますがこのような数への変換を総じて数量化といいます.

数量化にはこの他にも,目的変数と説明変数がともに質的データの場合の数量化2類(Quantification Method Type Ⅱ), 説明変数に量的データが混ざっている場合の拡張型数量化2類などがあり,数量化3,4,5,6類なども存在します.

数量化2類に関してはロジスティック回帰,数量化3類に関しては主成分分析が同様の目的で利用されるため,これらに関しては本資料では扱いません.

例えば,以下のような身長と体重,性別,国籍からなるデータがあった場合,新たに性別,国籍の種別の列を設けて当てはまる行に1,当てはまらない行に0を入力する変換を行います.

id 体重 身長 性別 国籍
1 65 170 日本
2 58 174 米国
3 78 189 オランダ
id 体重 身長 性別 男 日本 米国 オランダ
1 65 170 1 1 0 0
2 58 174 0 0 1 0
3 78 189 1 0 0 1

まずは,身長,体重,性別からなる,こちらのサンプルデータを利用して,身長,性別から体重を予測する数量化1類を試してみましょう.

まずはデータの確認をしてみます.

import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib
import seaborn as sns
import statsmodels.api as sm

#データの確認
df = pd.read_csv('data/quantification.csv')
print(df)

"""
     Gender      Height     Weight        BMI
0      Male  166.430341  71.355369  25.639518
1    Female  164.312585  57.693236  20.834761
2      Male  176.525613  66.619089  22.987388
3      Male  167.807888  52.236903  19.457056
4      Male  179.131402  71.557172  22.652586
..      ...         ...        ...        ...
195  Female  172.033565  64.506115  21.188950
196  Female  158.857271  55.028631  23.924375
197    Male  176.701624  56.014221  20.232505
198    Male  167.925367  69.257515  24.074144
199    Male  172.024625  70.693532  25.084344
"""

データの特徴を見て見るために,クロスプロットを作成します. 質的変数を含めると上手く表現できないので除外しています.

pd.plotting.scatter_matrix(df[['Height','Weight']], range_padding=0.2)
plt.show()
クロスプロットの確認

また,男女別のプロットを同時に表示させるために,seabornjoinplotを利用してみましょう. joinplotでは,hueに質的変数のヘッダーをしていすることで,それぞれの密度プロットを表示してくれます.

#joinplotで男女別に密度プロットを表示
fig = sns.jointplot(data = df
                   ,x ="Height"
                   ,y ="Weight"
                   ,hue='Gender'
                   ,joint_kws = dict(alpha=0.5))
plt.show()
ジョインプロットの確認

男女別に異なる分布であることが分かります. データをよく見てみると,男女で傾きが異なるように見えますが,数量化1類で扱えるのは男女別の切片の差のみです. 傾きを質的データに応じて変える場合には後に扱う一般化線形モデルの技法が必要となります.

比較のためにまずは通常の単回帰を行ってみましょう.今回は量的変数が一つしか無いため,正規化や多重共線性のチェックは行っていないことに注意しましょう. 変数が複数ある場合にはそれらの処理が必要になります.

#予測モデルを作成(単回帰)
X = sm.add_constant(df['Height'])
model = sm.OLS(df['Weight'],df['Height'])
result = model.fit()
print(result.summary())

"""
                                 OLS Regression Results
=======================================================================================
Dep. Variable:                 Weight   R-squared (uncentered):                   0.980
Model:                            OLS   Adj. R-squared (uncentered):              0.980
Method:                 Least Squares   F-statistic:                              9587.
Date:                Wed, 09 Oct 2024   Prob (F-statistic):                   2.67e-170
Time:                        13:14:18   Log-Likelihood:                         -739.70
No. Observations:                 200   AIC:                                      1481.
Df Residuals:                     199   BIC:                                      1485.
Df Model:                           1
Covariance Type:            nonrobust
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Height         0.3981      0.004     97.913      0.000       0.390       0.406
==============================================================================
Omnibus:                       22.723   Durbin-Watson:                   2.211
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               27.460
Skew:                           0.793   Prob(JB):                     1.09e-06
Kurtosis:                       3.882   Cond. No.                         1.00
==============================================================================
"""

検定の結果も,予測精度もかなり高いことが分かりますが,ここに男女の違いをいれることで改善されるかをチェックしてみましょう.

数量化1類を行うためにGenderの列をダミー変数化してみます. pandasでは,get_dummies()を利用することで簡単にダミー変数が作成できます dtype='int'と指定することで,0/1のダミー変数となります.省略した場合はTrue/Falseの値となるので忘れないようにしましょう.

# カテゴリカルデータのダミー変数化
# get_dummies関数を使う(dtype='it'で0/1の数値に変換)
X = pd.get_dummies(df[['Gender','Height']],dtype='int')
print(X)
"""
         Height  Gender_Female  Gender_Male
0    166.430341              0            1
1    164.312585              1            0
2    176.525613              0            1
3    167.807888              0            1
4    179.131402              0            1
..          ...            ...          ...
195  172.033565              1            0
196  158.857271              1            0
197  176.701624              0            1
198  167.925367              0            1
199  172.024625              0            1
"""

ダミー変数を利用した重回帰分析を行います. 今回は,男女の2値なので,作成したGender_Maleのみを利用します.

#予測モデルを作成(数量化1類)
X = sm.add_constant(X)
model = sm.OLS(df['Weight'],X[['Height','Gender_Male']])
result = model.fit()
print(result.summary())

"""
                                 OLS Regression Results
=======================================================================================
Dep. Variable:                 Weight   R-squared (uncentered):                   0.985
Model:                            OLS   Adj. R-squared (uncentered):              0.985
Method:                 Least Squares   F-statistic:                              6535.
Date:                Wed, 09 Oct 2024   Prob (F-statistic):                   1.62e-181
Time:                        13:14:18   Log-Likelihood:                         -708.75
No. Observations:                 200   AIC:                                      1421.
Df Residuals:                     198   BIC:                                      1428.
Df Model:                           2
Covariance Type:            nonrobust
===============================================================================
                  coef    std err          t      P>|t|      [0.025      0.975]
-------------------------------------------------------------------------------
Height          0.3668      0.005     72.226      0.000       0.357       0.377
Gender_Male    10.3714      1.224      8.475      0.000       7.958      12.785
==============================================================================
Omnibus:                       11.918   Durbin-Watson:                   2.088
Prob(Omnibus):                  0.003   Jarque-Bera (JB):               16.036
Skew:                           0.403   Prob(JB):                     0.000329
Kurtosis:                       4.129   Cond. No.                         350.
==============================================================================
"""

Adj. R-squared (uncentered)Prob (F-statistic)の双方が改善され,よりよいモデルができていることが分かります.

このように同一データで複数のモデルを比較し,より良いモデルを選ぶことをモデル選択といいます.

今回は,R-squaredなどの値で比較していますが,本来はモデル選択においては,AICBICの値を利用した比較を行います. この観点でもAICが減少していることから数量化モデルのほうが良いことが分かります. しかし,今回はあくまで数量化の紹介が目的なのでその詳細は割愛します.

モデル選択の詳細は後の一般化線形モデルの節で扱うので,興味がある方はそちらを読んでください.

2 時系列回帰

前の節で質的データの処理を扱ったように,データの分析ではデータの種類に応じて手法を選択する必要があります.

データの発生時刻が記録されたデータを点過程(Point Process)データと言います. 代表的なものに購入された商品に関して,購入時点の日付とともに記録したPOS(Point of Sales)データなどがあります.

商品名 単価 (円) 個数 購入日時
おにぎり 120 2 2024-10-01 08:15
サンドイッチ 350 1 2024-10-01 12:30
ペットボトル水 100 3 2024-10-01 14:45
カップラーメン 220 1 2024-10-02 11:00
チョコレート 150 2 2024-10-02 15:20

決まった時間単位毎に観測項目を集計したデータ時系列(Time Series)データといいます.

例えば, 上の点過程データを日毎,月ごとなど決まった時間単位で集計することで下のような時系列データとなります.

日付 売上合計 (円) 購入点数 購入回数
2024-10-01 1060 6 3
2024-10-02 520 3 2

2.1 データの準備

以下,時系列回帰などの練習用データを準備します.

今回は,実データとして千葉商科大学の電力データを利用し,電力消費量から曜日や祝日を予測/判別してみましょう. 千葉商科大学では, 自然エネルギー100%大学の取り組みに関連して使用したエネルギーを電力の種別ごとに計測しています. 今回は2021年5月の1号館のデータを利用してみます.

ダウンロードしたデータを作業ディレクトリのデータフォルダに配置したら,いくつかの前処理を施します. まず, 元のデータを確認してみましょう.

import pandas as pd
df = pd.read_csv('./data/energy_may_1.csv')
print(df)

"""
                 Date  1-1L-1-1-1F西/1(照明):kWh  ...  1号館動力盤1_T相/76_T(その他動力):kWh  1-太陽光発電量/82(発電):kWh
0     2021/05/01 0:00                   0.000  ...                    1.605610                  0.0
1     2021/05/01 1:00                   0.000  ...                    1.555380                  0.0
2     2021/05/01 2:00                   0.000  ...                    1.617734                  0.0
3     2021/05/01 3:00                   0.000  ...                    1.612538                  0.0
4     2021/05/01 4:00                   0.000  ...                    1.569237                  0.0
..                ...                     ...  ...                         ...                  ...
739  2021/05/31 19:00                   0.175  ...                    1.978000                  0.0
740  2021/05/31 20:00                   0.115  ...                    1.844633                  0.0
741  2021/05/31 21:00                   0.000  ...                    1.806529                  0.0
742  2021/05/31 22:00                   0.000  ...                    1.811724                  0.0
743  2021/05/31 23:00                   0.000  ...                    1.872346                  0.0
"""

データが読み込めたようなのでまずは,列の情報を編集してみましょう. CSVファイルのヘッダーを確認してみると以下のようになっています.

#列を確認する
cols = list(df.columns)[1:] #Dateを除外
[print(c) for c in cols]
"""
1-1L-1-1-1F西/1(照明):kWh
1-1L-1-2-1F西/2(照明):kWh
1-1L-1-3-1F西/3(照明):kWh
1-1L-1-4-1F西/4(照明):kWh
1-1L-1-5-1F西/5(照明):kWh
1-1L-1-6-1F西/6(照明):kWh
1-1L-1-7-1F~3Fロビー/7(照明):kWh
1-1L-1-8-1F西/8(照明):kWh
1-1L-1-9-1F西/9(照明):kWh
1-1L-1-10-1F西/10(照明):kWh
1-1L-2-11-1F東/11(照明):kWh
1-1L-2-12-1F東/12(照明):kWh
1-1L-2-13-1F東/13(照明):kWh
1-1L-2-14-1F東/14(照明):kWh
1-1L-2-15-1F東/15(照明):kWh
1-1L-2-16-1F東/16(照明):kWh
1-1L-2-17-1F東/17(照明):kWh
1-1L-11-18-1101教室/18(照明):kWh
1-1L-11-19-1101教室/19(照明):kWh
1-1L-11-20-1101教室/20(照明):kWh
1-1L-11-21-1101教室/21(照明):kWh
1-1L-11-22-1101教室/22(照明):kWh
1-1L-11-23-1101教室/23(照明):kWh
1-1L-12-24-1102教室/24(照明):kWh
1-1L-12-25-1102教室/25(照明):kWh
1-1L-13-26-1103教室/26(照明):kWh
1-1L-13-27-1103教室/27(照明):kWh
1-1L-14-28-1104教室/28(照明):kWh
1-1L-14-29-1104教室/29(照明):kWh
1-1L-14-30-1104教室/30(照明):kWh
1-1L-14-31-1104教室/31(照明):kWh
1-1L-14-32-1104教室/32(照明):kWh
1-1L-14-33-1104教室/33(照明):kWh
1-2L-1-34-2F西/34(照明):kWh
1-2L-1-35-2F西/35(照明):kWh
1-2L-1-36-2F西/36(照明):kWh
1-2L-1-37-2F西/37(照明):kWh
1-2L-1-38-2F西 1201共同研究室1_2照明/38(照明):kWh
1-2L-1-39-2F西/39(照明):kWh
1-2L-1-40-2F西/40(照明):kWh
1-2L-1-41-2F西 共同研究室3~6照明/41(照明):kWh
1-2L-2-42-2F東/42(照明):kWh
1-2L-2-43-2F東/43(照明):kWh
1-2L-2-44-2F東/44(照明):kWh
1-2L-2-45-1202~1204照明/45(照明):kWh
1-2L-2-46-2F東/46(照明):kWh
1-2L-2-47-2F東/47(照明):kWh
1-2L-2-48-1205~1207照明/48(照明):kWh
1-2L-H-49-1208教室/49(照明):kWh
1-2L-I-50-1209教室/50(照明):kWh
1-2L-J-51-1210教室/51(照明):kWh
1-2L-K-52-1211教室/52(照明):kWh
1-2L-L-53-1212教室/53(照明):kWh
1-3L-1-54-3F東/54(照明):kWh
1-3L-1-55-3F東/55(照明):kWh
1-3L-1-56-3F東 ラボスクウェア1_2照明/56(照明):kWh
1-3L-1-57 共同研究室7~9/57(照明):kWh
1-3L-1-58 ラボスクウェア1_2照明/58(照明):kWh
1-3L-1-59 3F東/59(照明):kWh
1-3L-1-60 3F東/60(照明):kWh
1-3L-1-61 共同研究室10~12/61(照明):kWh
1-3L-2-62 3F西/62(照明):kWh
1-3L-2-63 3F西/63(照明):kWh
1-3L-2-64 3F西 ラボスクウェア3_4照明/64(照明):kWh
1-3L-2-65 3F西/65(照明):kWh
1-3L-2-66 共同研究室13西照明/66(照明):kWh
1-3L-2-67 ラボスクウェア3_4照明/67(照明):kWh
1-3L-2-68 3F西/68(照明):kWh
1-3L-2-69 3F西/69(照明):kWh
1-3L-2-70 3F西/70(照明):kWh
1-3L-2-71 3F西 共同研究室13東照明/71(照明):kWh
1号館電灯盤1_R相/73(主幹):kWh
1号館電灯盤2_R相/74(主幹):kWh
1号館電灯盤3_R相/75(主幹):kWh
1号館動力盤1_R相/76(その他動力):kWh
1-GHP-77/77GHP(空調熱源):m3
1号館電灯盤1_T相/73_T(照明等その他):kWh
1号館電灯盤2_T相/74_T(照明等その他):kWh
1号館電灯盤3_T相/75_T(照明等その他):kWh
1号館動力盤1_T相/76_T(その他動力):kWh
1-太陽光発電量/82(発電):kWh
"""

#利用対象部分の抽出
print(list(set([c[c.find('(') : c.find(')')+1] for c in cols])))
# >>> ['(発電)', '(照明)', '(空調熱源)', '(照明等その他)', '(その他動力)', '(主幹)']

このデータでは1号館を「1F西/1,1F西/2」など分電盤毎に分割し,かつ電力の利用対象を「照明,主幹,空調熱源,照明等その他,その他動力,発電」の5種類に分けて記録しています. このうち「照明等その他」はコンセントなどの電源の利用を表しています. この分類は分析の練習用としては細かすぎるので,「照明,電源,動力,空調」の4つにまとめてみます.

# 列の整形
# 場所は無視して,照明(Lighting),電源(Others),動力(Power),空調(Air),だけに分ける

# '照明'を含む列の抽出
df['Lighting'] = sum([df[x] for x in df.filter(like='(照明)').columns])
# ''を含む列の抽出
df['Others'] = sum([df[x] for x in df.filter(like='(照明等その他)').columns])
# '動力'を含む列の抽出
df['Power'] = sum([df[x] for x in df.filter(like='(その他動力)').columns])
# ‘空調'を含む列の抽出
df['Air'] = sum([df[x] for x in df.filter(like='(空調熱源)').columns])
# 結合した列以外を削除
df = df[['Date','Lighting', 'Others', 'Power', 'Air']]

# totalを追加
df['Total'] = sum(df[x] for x in ['Lighting', 'Others', 'Power', 'Air'])
print(df)

"""
                 Date  Lighting  Others     Power  Air      Total
0     2021/05/01 0:00     0.000   6.518  2.876935    0   9.394935
1     2021/05/01 1:00     0.000   6.490  2.835366    0   9.325366
2     2021/05/01 2:00     0.000   6.558  2.982589    0   9.540589
3     2021/05/01 3:00     0.000   6.444  2.932360    0   9.376360
4     2021/05/01 4:00     0.000   6.724  2.864810    0   9.588810
..                ...       ...     ...       ...  ...        ...
739  2021/05/31 19:00     6.773  10.792  3.574950    0  21.139950
740  2021/05/31 20:00     3.743   8.120  3.257986    0  15.120986
741  2021/05/31 21:00     0.118   6.636  3.230273    0   9.984273
742  2021/05/31 22:00     0.000   6.148  3.083049    0   9.231049
743  2021/05/31 23:00     0.000   6.854  3.183508    0  10.037508
"""

一般的に,大学のイベントは時間割に沿って行われるため,電気使用量は曜日によって異なります. そこで,曜日や祝日の情報を追加して情報量を増やしてみましょう. datetime型は,.weekday属性で曜日が取得できます. .weekday0月曜日,6日曜日の数値で返ってくるので,分かりやすく文字列に変更します. また,土日をHoliday列で1とする,Holidayフラグも作成します.

# 曜日の取得
print('曜日の取得')
import datetime as dt
# 日付をインデックスに変更
print(df.index) #現在は,行数がインデックスになっている
# RangeIndex(start=0, stop=744, step=1)
print('-'*10)

#indexを日付に変更
df.set_index('Date', inplace=True)
print(df.index) # インデックスが変更できたことが確認できる
"""
Index(['2021/05/01 0:00', '2021/05/01 1:00', '2021/05/01 2:00',
       '2021/05/01 3:00', '2021/05/01 4:00', '2021/05/01 5:00',
       '2021/05/01 6:00', '2021/05/01 7:00', '2021/05/01 8:00',
       '2021/05/01 9:00',
       ...
       '2021/05/31 14:00', '2021/05/31 15:00', '2021/05/31 16:00',
       '2021/05/31 17:00', '2021/05/31 18:00', '2021/05/31 19:00',
       '2021/05/31 20:00', '2021/05/31 21:00', '2021/05/31 22:00',
       '2021/05/31 23:00'],
      dtype='object', name='Date', length=744)
"""

print('-'*10)

# 現在は日付と時間がただの文字列なので,datatime型に変換する
df.index = pd.to_datetime(df.index)
print(df.index)

"""
DatetimeIndex(['2021-05-01 00:00:00', '2021-05-01 01:00:00',
               '2021-05-01 02:00:00', '2021-05-01 03:00:00',
               '2021-05-01 04:00:00', '2021-05-01 05:00:00',
               '2021-05-01 06:00:00', '2021-05-01 07:00:00',
               '2021-05-01 08:00:00', '2021-05-01 09:00:00',
               ...
               '2021-05-31 14:00:00', '2021-05-31 15:00:00',
               '2021-05-31 16:00:00', '2021-05-31 17:00:00',
               '2021-05-31 18:00:00', '2021-05-31 19:00:00',
               '2021-05-31 20:00:00', '2021-05-31 21:00:00',
               '2021-05-31 22:00:00', '2021-05-31 23:00:00'],
              dtype='datetime64[ns]', name='Date', length=744, freq=None)
"""

print('-'*10)

# 曜日を入れる
df['weekday'] = df.index.weekday
dayOfWeek = { 0:'Mon'
            , 1:'Tue'
            , 2:'Wed'
            , 3:'Thu'
            , 4:'Fri'
            , 5:'Sat'
            , 6:'Sun'}
df['weekday'] = df['weekday'].map(dayOfWeek)

# 曜日を平日かどうかで分ける
df['Holiday'] = 0
for i in df.index:
    if 'Sat' == df.at[i,'weekday']:
        df.at[i,'Holiday'] = 1
    elif 'Sun' == df.at[i,'weekday']:
        df.at[i,'Holiday'] = 1
    else:
        df.at[i,'Holiday'] = 0
print(df)

"""
                     Lighting  Others     Power  Air      Total weekday  Holiday
Date
2021-05-01 00:00:00     0.000   6.518  2.876935    0   9.394935     Sat        1
2021-05-01 01:00:00     0.000   6.490  2.835366    0   9.325366     Sat        1
2021-05-01 02:00:00     0.000   6.558  2.982589    0   9.540589     Sat        1
2021-05-01 03:00:00     0.000   6.444  2.932360    0   9.376360     Sat        1
2021-05-01 04:00:00     0.000   6.724  2.864810    0   9.588810     Sat        1
...                       ...     ...       ...  ...        ...     ...      ...
2021-05-31 19:00:00     6.773  10.792  3.574950    0  21.139950     Mon        0
2021-05-31 20:00:00     3.743   8.120  3.257986    0  15.120986     Mon        0
2021-05-31 21:00:00     0.118   6.636  3.230273    0   9.984273     Mon        0
2021-05-31 22:00:00     0.000   6.148  3.083049    0   9.231049     Mon        0
2021-05-31 23:00:00     0.000   6.854  3.183508    0  10.037508     Mon        0
"""

1日の中でも授業時間とそうでない時間によって,消費電力の傾向は異なりそうです. 授業時間割を授業前(before_class),1~5時限,昼休み(break),授業後(after_class)として設定してみましょう.

ここまでの作業ができたら,energy_may_hour.csvとして保存してみます.

#授業時間割の情報を追加する
#2020年から
#https://www.cuc.ac.jp/dpt_grad_sch/graduate_sch/accounting/hours/index.html
#1時限    9:00~10:45
#2時限    10:55~12:40
#昼休み   12:40~13:30
#3時限    13:30~15:15
#4時限    15:25~17:10
#5時限    17:20~19:05
def time2CTime(x):
    if  9 <= x.hour <= 11:
        return '1'
    elif 11 < x.hour <= 12:
        return '2'
    elif 12 < x.hour <= 13:
        return 'break'
    elif 13 < x.hour <= 15:
        return '3'
    elif 15 < x.hour <= 17:
        return '4'
    elif 17 < x.hour <= 20:
        return '5'
    else:
        return 'after_class'

df['period'] = df.index.map(lambda x : time2CTime(x))
print(df)
"""
                     Lighting  Others     Power  Air      Total weekday  Holiday       period
Date
2021-05-01 00:00:00     0.000   6.518  2.876935    0   9.394935     Sat        1  after_class
2021-05-01 01:00:00     0.000   6.490  2.835366    0   9.325366     Sat        1  after_class
2021-05-01 02:00:00     0.000   6.558  2.982589    0   9.540589     Sat        1  after_class
2021-05-01 03:00:00     0.000   6.444  2.932360    0   9.376360     Sat        1  after_class
2021-05-01 04:00:00     0.000   6.724  2.864810    0   9.588810     Sat        1  after_class
...                       ...     ...       ...  ...        ...     ...      ...          ...
2021-05-31 19:00:00     6.773  10.792  3.574950    0  21.139950     Mon        0            5
2021-05-31 20:00:00     3.743   8.120  3.257986    0  15.120986     Mon        0            5
2021-05-31 21:00:00     0.118   6.636  3.230273    0   9.984273     Mon        0  after_class
2021-05-31 22:00:00     0.000   6.148  3.083049    0   9.231049     Mon        0  after_class
2021-05-31 23:00:00     0.000   6.854  3.183508    0  10.037508     Mon        0  after_class
"""
#保存
df.to_csv('data/energy_may_hour.csv',encoding='utf-8-sig')

今回は1時間毎に集計したデータを時系列分析に用いますが,次の章などで日ごとに集計したデータを利用するので,日毎の集計データも作成しておきましょう. datetime型ではdateによって日付が取得できます.

# 1時間ごとになっているので,一日ごとに集約
df['Day'] = df.index.date
df = df.set_index(df.index.date) # 時間の部分を削除
print(df)

"""
            Lighting  Others     Power  Air      Total         Day
2021-05-01     0.000   6.518  2.876935    0   9.394935  2021-05-01
2021-05-01     0.000   6.490  2.835366    0   9.325366  2021-05-01
2021-05-01     0.000   6.558  2.982589    0   9.540589  2021-05-01
2021-05-01     0.000   6.444  2.932360    0   9.376360  2021-05-01
2021-05-01     0.000   6.724  2.864810    0   9.588810  2021-05-01
...              ...     ...       ...  ...        ...         ...
2021-05-31     6.773  10.792  3.574950    0  21.139950  2021-05-31
2021-05-31     3.743   8.120  3.257986    0  15.120986  2021-05-31
2021-05-31     0.118   6.636  3.230273    0   9.984273  2021-05-31
2021-05-31     0.000   6.148  3.083049    0   9.231049  2021-05-31
2021-05-31     0.000   6.854  3.183508    0  10.037508  2021-05-31

[744 rows x 6 columns]
"""

同じ日付によってまとめて集計するような作業はfor文などでもできますが,pandasgroupbyメソッドが便利です. groupby('列名')で指定した列名の同じデータごとにデータを区切ってくれます.

更に, .agg({'列名':'処理方法'})を追記することでグループごとにデータを集計します.

処理方法は文字列で指定し, sum(合計),mean(平均),first(最初の値)などが利用できます.

集計したデータはenergy_may_day.csvとして保存します.

# 一日単位で集計
df = df.groupby('Day').agg({'Lighting':'sum'
                           ,'Others':'sum'
                           ,'Power':'sum'
                           ,'Air':'sum'
                           ,'Total':'sum'
                           ,'weekday':'first'
                           ,'Holiday':'first'})
df.index = pd.to_datetime(df.index)
print(df)

"""
            Lighting   Others       Power  Air       Total weekday  Holiday
Day
2021-05-01   57.8590  164.026  150.925638    1  373.810638     Sat        1
2021-05-02   61.3290  170.661  153.542773    0  385.532773     Sun        1
2021-05-03   52.5590  153.860  162.455036    0  368.874036     Mon        0
2021-05-04   27.1570  142.110  190.401666    0  359.668666     Tue        0
2021-05-05   14.9370  141.365   96.532341    0  252.834341     Wed        0
2021-05-06  151.5430  252.266  163.735893    0  567.544893     Thu        0
2021-05-07  137.5760  265.376   90.321215    4  497.273215     Fri        0
2021-05-08   96.8080  202.206  159.786805    4  462.800805     Sat        1
2021-05-09   67.1230  173.335  181.672136    4  426.130136     Sun        1
2021-05-10  124.4350  234.587  187.283113    1  547.305113     Mon        0
2021-05-11  150.7050  271.478   85.611779    1  508.794779     Tue        0
2021-05-12  115.1820  231.200  142.734788    1  490.116788     Wed        0
2021-05-13  137.8290  283.480   80.014654    1  502.323654     Thu        0
2021-05-14  125.5200  235.470  176.655242    4  541.645242     Fri        0
2021-05-15  100.0060  207.944  174.805418    6  488.755418     Sat        1
2021-05-16   62.9970  189.768  101.143069    1  354.908069     Sun        1
2021-05-17  134.4200  253.678   85.963373    4  478.061373     Mon        0
2021-05-18  139.2750  275.532   85.630823    6  506.437823     Tue        0
2021-05-19  111.7410  254.229   79.302779    3  448.272779     Wed        0
2021-05-20  134.6820  258.456   96.874422    0  490.012422     Thu        0
2021-05-21  134.7470  270.402   91.587337   15  511.736337     Fri        0
2021-05-22   85.1020  214.783   89.615409    6  395.500409     Sat        1
2021-05-23   66.4360  176.641  140.140173    4  387.217173     Sun        1
2021-05-24  140.0200  237.016  151.007045   11  539.043045     Mon        0
2021-05-25  133.2290  239.769  183.644077   14  570.642077     Tue        0
2021-05-26  111.7810  220.848  167.229426   11  510.858426     Wed        0
2021-05-27  135.5230  265.379   79.695086    1  481.597086     Thu        0
2021-05-28  132.4820  247.760  141.465190    4  525.707190     Fri        0
2021-05-29  131.5140  226.797  129.222198   12  499.533198     Sat        1
2021-05-30   70.8040  188.536  139.632687    5  403.972687     Sun        1
2021-05-31  123.7695  231.010  164.885098    6  525.664598     Mon        0
"""

df.to_csv('data/energy_may_day.csv',encoding='utf-8-sig')

作成したデータは,それぞれ時間ごと,日ごととなります. 以下,これらのデータを利用して,時系列解析を実施していきます.

2.2 古典的時系列解析

2.3

3 一般化線形モデル(執筆中)

3.1 ロジスティック回帰

今回利用するデータは時系列データであり本来回帰や判別問題を直接利用するべき対象ではありません.

時系列データはトレンドや周期などの時系列のデータ構造を考慮した,時系列分析を行うべきですが,ここでは独立したデータとして扱っています.

判別を行うための基礎的な手法として目的変数に「成功/失敗」や「0/1」などのベルヌーイ分布に従う二項の質的変数を取り,目的変数の判別を行うロジスティック回帰があります.

なお,二項以上のクラスの識別を行うロジスティック回帰を多項ロジスティック回帰といいますが,ここでは二項の場合のみを扱います.

ce0f13b2-4a83-4c1c-b2b9-b6d18f4ee6d2