[Python]説明変数群ごとのAICを算出する

学術系のデータ分析をPythonで行い、
**「複数の説明変数群を作成し、どの説明変数群の組み合わせが最適かAICで確認する」**というプロセスがありました。
なおAICとは、'Akaike's Information Criterion'の略で、回帰モデルが最適かどうか判断するための指標の一つです。(詳しくは[こちら](https://ja.wikipedia.org/wiki/%E8%B5%A4%E6%B1%A0%E6%83%85%E5%A0%B1%E9%87%8F%E8%A6%8F%E6%BA%96))


今回の記事では、このプロセスを効率化するためのコードを解説します。

:::note warn
投稿内容は個人の見解であり、所属する組織の公式見解ではありません。
:::

## 記事の対象者
今回の記事は、次の悩みを持つ人を対象に執筆しています。

- データ分析をPythonで実施したい
- AICの比較を効率化したい

## この記事を読むうえで必要な知識

- Pythonによるデータ分析の基礎知識を習得している
- 統計学の基礎を習得している

## ざっくりとした要件定義
###Input
- 必ず含める説明変数群
- 含めるか検討中の説明変数群

###Output
- 含めるか検討中の説明変数群を全探索し、AICを算出

アウトプットのイメージ
('ash','other_ingredients', 'color'の3つが、含めるか検討中の説明変数群の場合、)

```python
#output
[]
AIC:462.0
['ash']
AIC:451.0
['other_ingredients']
AIC:437.0
['ash', 'other_ingredients']
AIC:434.0
['color']
AIC:437.0
['ash', 'color']
AIC:430.0
['other_ingredients', 'color']
AIC:439.0
['ash', 'other_ingredients', 'color']
AIC:436.0
```

##コード
scikit-learnの[Wine recognition dataset](https://scikit-learn.org/stable/datasets/toy_dataset.html#wine-dataset)を用いて、コードを解説します。

今回の具体例では、インプットは次の通りです。

- 必ず含める説明変数<br>
**'alcohol','malic_acid'**
- 検討中の説明変数群の名称<br>
**'ash','other_ingredients','color'**


###ライブラリのインポートとデータの読み込み
```python
#ライブラリをインポート
import pandas as pd
import statsmodels.api as sm
from sklearn.datasets import load_wine
import warnings

#データの読み込み
dataset = load_wine()
df = pd.DataFrame(data=dataset.data, columns=dataset.feature_names)
df['class'] = dataset.target
```

###説明変数群ごとのAICを比較
```python
def show_AIC(x_list, y_col, df):
    '''
    対象の説明変数群、被説明変数、dfでのAICを算出する関数
    '''
    warnings.simplefilter('ignore')
    # nanを削除
    df_reg=df.copy()
    df_reg.dropna(axis=0,how="any",inplace=True)
    df_reg.reset_index(inplace=True)
    # yとXをコピー
    y=df_reg[y_col].copy()
    X=df_reg[x_list].copy()
    # 負の二項回帰モデルを使用
    model = sm.GLM(y, sm.add_constant(X), family=sm.families.NegativeBinomial())
    result = model.fit()
    print('AIC:{}'.format(result.aic.round()))

#グループ分けした辞書を作成する
x_dict = {'alc':['alcohol'],
          'acid':['malic_acid'],
          'ash':['ash','alcalinity_of_ash'],
         'other_ingredients':
         ['magnesium', 'total_phenols',  'flavanoids', 'nonflavanoid_phenols','proanthocyanins'],
         'color':['color_intensity','hue','od280/od315_of_diluted_wines']}

#必ず含める説明変数の名称を指定する
fixed_name = ['alc', 'acid']

#「必ず含める説明変数のリスト」と「含めるか検討する説明変数のdict」を作成する
fixed_list=[]
AIC_dict = x_dict.copy()

for val in fixed_name:
    temp = AIC_dict.pop(val) #popすると、AIC_dictから削除される
    fixed_list+=temp

n=len(AIC_dict)
for i in range(2 ** n):
    temp_list = []
    temp_title = []
    for j, key in enumerate(AIC_dict):  # このループが一番のポイント
        if ((i >> j) & 1):  # 順に右にシフトさせ最下位bitのチェックを行う
            #最下位bitが1の場合、対象を加える
            temp_title.append(key)
            temp_list += x_dict[key]
    print(temp_title)
    temp_list = fixed_list + temp_list
    
    show_AIC(temp_list,'class',df)
```

先ほどもお見せしましたが、結果は次のように表示されます。

```python
[]
AIC:462.0
['ash']
AIC:451.0
['other_ingredients']
AIC:437.0
['ash', 'other_ingredients']
AIC:434.0
['color']
AIC:437.0
['ash', 'color']
AIC:430.0
['other_ingredients', 'color']
AIC:439.0
['ash', 'other_ingredients', 'color']
AIC:436.0
```
一例としてAICを算出しただけなので、結果の解釈はスキップします。


##おわりに
この記事では、説明変数群を全探索しAICを算出しました。

お困りの場合は、このコードを使ってみてください。

##参考文献
[赤池情報量規準](https://ja.wikipedia.org/wiki/%E8%B5%A4%E6%B1%A0%E6%83%85%E5%A0%B1%E9%87%8F%E8%A6%8F%E6%BA%96)
[7.1. Toy datasets — scikit-learn 1.0 documentation](https://scikit-learn.org/stable/datasets/toy_dataset.html#wine-dataset)
[Python de アルゴリズム（bit全探索）](https://qiita.com/gogotealove/items/11f9e83218926211083a)
[Generalized Linear Models — statsmodels](https://www.statsmodels.org/stable/glm.html)
[statsmodels.discrete.discrete_model.NegativeBinomial — statsmodels](https://www.statsmodels.org/stable/generated/statsmodels.discrete.discrete_model.NegativeBinomial.html)