前処理（特徴量エンジニアリング）

# この記事の狙い・目的
機械学習を取り入れたAIシステムの構築は、
①データ分析→ ②データセット作成（前処理）→ ③モデルの構築・適用
というプロセスで行っていきます。
その際「前処理」の段階では、データ分析の考察を踏まえて、精度の高いデータセットが作れるよう様々な対応が必要となります。
このブログでは、「前処理（特徴量エンジニアリング）」の工程について初めから通して解説していきます。

# プログラムの実行環境
Python3
MacBook pro（端末）
PyCharm（IDE）
Jupyter Notebook（Chrome）
Google スライド（Chrome）

# データ確認
```Python
# データ取得
boston_df = pd.read_csv("./boston.csv", sep=',')

# データ確認
boston_df.shape
boston_df.head()
boston_df.info()
boston_df.describe()
```
![スクリーンショット 2021-10-22 15.31.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/19291963-0d1b-0716-5b8c-40724c77bdc6.png)

# 精度評価
```Python

from sklearn.ensemble import RandomForestRegressor as RFR # ランダム・フォレスト（回帰）
from sklearn.model_selection import train_test_split # データ分割
from sklearn.metrics import r2_score, mean_squared_error, mean_absolute_error, mean_squared_log_error # 各評価指標

def learning(model, df):
    # データ分割
    X = df.drop('MEDV',axis=1)
    y = df['MEDV']
    X_train,X_test,y_train,y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    # 学習、予測
    rfr_model = model
    rfr_model.fit(X_train, y_train)
    y_pred = rfr_model.predict(X_test).round(decimals=1)

    # 評価    
    print('決定係数（R2） = ', r2_score(y_test, y_pred).round(decimals=3))
    print('平均絶対誤差（MAE） = ', mean_absolute_error(y_test, y_pred).round(decimals=3))
    print('平均二乗誤差（MSE） = ', mean_squared_error(y_test, y_pred).round(decimals=3))
    print('対数平均二乗誤差（MSLE） = ', mean_squared_log_error(y_test, y_pred).round(decimals=3))
    print('平均二乗平方根誤差（RMSE） = ', np.sqrt(mean_squared_error(y_test, y_pred)).round(decimals=3))
    print('対数平方平均二乗誤差（RMSLE） = ', np.sqrt(mean_squared_log_error (y_test, y_pred)).round(decimals=3))
    
    return rfr_model, y_test, y_pred

# 実行
rfr_model, y_test, y_pred = learning(RFR(random_state=42), boston_df)

# 結果
# 決定係数（R2） =  0.892
# 平均絶対誤差（MAE） =  2.04
# 平均二乗誤差（MSE） =  7.902
# 対数平均二乗誤差（MSLE） =  0.02
# 平均二乗平方根誤差（RMSE） =  2.811
# 対数平方平均二乗誤差（RMSLE） =  0.142
```
非線形モデルでまずまずの評価

# 特徴量重要度
## ランダム・フォレスト版
```Python
def rfr_importance(df):
    # データ分割
    X = df.drop(columns='MEDV', axis=1)
    y = df['MEDV']
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

    # モデリング
    clf_rf = RFR()
    clf_rf.fit(X_train, y_train)
    y_pred = clf_rf.predict(X_test)

    # 評価
    print('平均二乗平方根誤差（RMSE） = {:>.3f}'.format(np.sqrt(mean_squared_error(y_test, y_pred))))

    # 重要度
    fimp = clf_rf.feature_importances_

    # データフレームに変換
    imp_df = pd.DataFrame()
    imp_df['項目名'] = df.columns[:-1]
    imp_df['重要度'] = fimp.round(decimals=3).astype(str)
    
    return imp_df

# 実行
imp_df = rfr_importance(boston_df)
imp_df.sort_values(by='重要度', ascending=False)
```
![スクリーンショット 2021-10-22 16.00.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/bb093c25-1c10-7cd9-8b68-3db42168fbd5.png)

## XGBoost版
```Python

import xgboost as xgb

def boost_importance(df):
    # データ分割
    X = df.drop(columns='MEDV', axis=1)
    y = df['MEDV']
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

    # パラメータ
    xgb_params = {"objective": "reg:linear", "eta": 0.1, "max_depth": 6, "silent": 1}
    num_rounds = 100

    # XGBoost用のデータセットの作成
    dtrain = xgb.DMatrix(X_train, label=y_train)

    # 学習
    gbdt = xgb.train(xgb_params, dtrain, num_rounds)

    # 重要度
    _, ax = plt.subplots(figsize=(12, 4))
    # パラメーター：gain 予測精度をどれだけ改善させたることができるできたか（平均値）
    xgb.plot_importance(gbdt, ax=ax, importance_type='gain')
    
# 実行
boost_importance(boston_df)
```
![スクリーンショット 2021-10-22 16.00.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/122bb3f3-c111-8fc4-3cb6-7b4c0f2b4da5.png)

## 線形回帰モデル版
```Python
from sklearn.linear_model import Ridge, RidgeCV, ElasticNet, LassoCV, LassoLarsCV
from sklearn.model_selection import cross_val_score

def linear_importance(df):
    X = df.drop(columns='MEDV', axis=1)
    y = df['MEDV']
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

    def rmse_cv(model):
        rmse= np.sqrt(-cross_val_score(model, X_train, y_train, scoring="neg_mean_squared_error", cv = 5))
        return(rmse)

    # model_ridge = Ridge().fit(X_train, y_train)
    model_lasso = LassoCV().fit(X_train, y_train)
    print(f'スコア： {rmse_cv(model_lasso).mean().round(decimals=3)}')

    coef = pd.Series(model_lasso.coef_, index = X_train.columns)
    print("選択項目数： " + str(sum(coef != 0)) + "、除外項目数： " +  str(sum(coef == 0)))

    plt.figure(figsize=[8,4])
    imp_coef = coef.sort_values()
    imp_coef.plot(kind = "barh").grid()
    plt.title("Lassoモデルの回帰係数")
    
# 実行
linear_importance(boston_df)
```
![スクリーンショット 2021-10-22 16.01.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/bc4159b3-41aa-cc5e-1f58-7be9eb8d5c81.png)

## ランダム・フォレスト ＋ LIME版
```Python
import lime
import lime.lime_tabular

def explain_importance(df):
    # データ分割
    X = df.drop(columns='MEDV', axis=1)
    y = df['MEDV']
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 0)

    # ランダム・フォレスト（回帰）
    model = RFR(max_depth=6, random_state=0, n_estimators=10)
    model.fit(X_train, y_train)

    # パラメータ
    RFR(bootstrap=True, criterion='mse', max_depth=6,
                          max_features='auto', max_leaf_nodes=None,
                          min_impurity_decrease=0.0, min_impurity_split=None,
                          min_samples_leaf=1, min_samples_split=2,
                          min_weight_fraction_leaf=0.0, n_estimators=10,
                          n_jobs=None, oob_score=False, random_state=0, verbose=0,
                          warm_start=False)
    # 予測
    y_pred = model.predict(X_test)
    # 評価
    mse = mean_squared_error(y_test, y_pred)**(0.5)
    print(f'MSE: {mse}')
    # 予測の判断根拠を示す（LIME）
    explainer = lime.lime_tabular.LimeTabularExplainer(X_train.values, feature_names=X_train.columns.values.tolist(),
                                                      class_names=['MEDV'], verbose=True, mode='regression', random_state=0)
    # 解釈結果（予測結果への影響）を表示する
    j = 5
    exp = explainer.explain_instance(X_test.values[j], model.predict, num_features=6)
    exp.show_in_notebook(show_table=True)

# 実行
from IPython.display import Image
explain_importance(boston_df)
plt.savefig("newplot_lime.png")
Image("./newplot_lime.png")
```
![スクリーンショット 2021-10-22 16.01.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/322d500d-bbf6-7819-8a2d-020d3db477ba.png)

分析通り、RM、LSTATは重要度が高い数値を出している。
CHASは重要度が高いと見ていたが、低い数値となっている。単体では低い数値のため何かしらの変換が必要と思われる。

# 特徴量エンジニアリング
## 対応方針
- 正規分布への変換
  - MEDV：
予測残差の正規分布性を期待する分析アルゴリズム（線形回帰など）を使用するため、必要と考える。
また、目的変数にマイナス値が既に含まれてしまっているため、Box-Cox変換を用いる。 変換結果にマイナス値を含まれてしまい、線形モデルの評価時にエラーとなるため、Yeo-Johnson変換は行わない。　　
- 外れ値
  - CRIM：
（大きく外れた）外れ値（80）を含んでいる。犯罪率80%は疑わしい値。線形モデルを使用する（予定）のため、この外れ値を除去する。
- スケーリング
  - NOX, RM, DIS, PTRATIO, LSTAT, MEDV：
（微妙な）外れ値の影響を軽減させたい
線形回帰に対しては有効でないと思われるが、非線形アルゴリズムをアンサンブルで使用する（予定）のため、有効であると考える。
- 特徴量生成
  - クラスタの重心からの距離：
（まだ試してみたことがないため）実験的に効果検証してみる。

## 正規分布への変換
```Python
# 変換前の状態
import warnings
warnings.filterwarnings('ignore')
from scipy.stats import norm
plt.figure(figsize=[8,3])
sns.distplot(boston_df['MEDV'], kde=True, fit=norm, fit_kws={'label': '正規分布'}).grid()
plt.legend();
```
![スクリーンショット 2021-10-22 16.03.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/53c891e5-9dc1-4c73-3d4b-22682a523d23.png)

### Yeo-Johnson変換
```Python
# Yeo-Johnson変換
from sklearn.preprocessing import PowerTransformer

yeo_johnson_df = boston_df.copy()
sk_yeojohnson = PowerTransformer(method='yeo-johnson') # インスタンス生成
yeojohnson_data = sk_yeojohnson.fit_transform(yeo_johnson_df[['MEDV']]) # 変換
yeo_johnson_df['MEDV'] = yeojohnson_data

import warnings
warnings.filterwarnings('ignore')
from scipy.stats import norm
plt.figure(figsize=[8,3])
sns.distplot(yeo_johnson_df['MEDV'], kde=True, fit=norm, fit_kws={'label': '正規分布'}).grid()
plt.legend()
```
![スクリーンショット 2021-10-22 16.03.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/36cc3129-8a1c-bfc8-5463-864f86bb50b6.png)
ランダムフォレストには効果があったが、線形モデルには適用できない。評価の過程で目的変数に負値を扱えないため。

### Box-Cox変換
```Python
# Box-Cox変換 
from scipy.special import boxcox1p

boxcox_df = boston_df.copy()
lam=0.15
boxcox_df['MEDV'] = boxcox1p(boxcox_df['MEDV'], lam)

# 描画
plt.figure(figsize=[8,3])
sns.distplot(boxcox_df['MEDV'], kde=True, fit=norm, fit_kws={'label': '正規分布'}).grid()
```
![スクリーンショット 2021-10-22 16.03.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/87a53de7-b59e-66c7-7630-e95215a4c22e.png)
分布の偏りが軽減された。しかし非線形モデルには逆効果だった。

## 外れ値処理
```Python
# 確認
plt.figure(figsize=[10,2])
sns.boxplot(data=boston_df, x='CRIM').grid()

# 外れ値除去
boston_df.shape
boston_df = boston_df[boston_df['CRIM']<40]
boston_df = boston_df.reset_index()
boston_df.shape

# (506, 15)
# (500, 15)
```
![スクリーンショット 2021-10-22 16.05.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/5f190a58-73b5-5306-bdff-e68ddc03fe58.png)

```Python
plt.figure(figsize=[10,2])
sns.boxplot(data=boston_df, x='B').grid()

# 外れ値除去
boston_df.shape
boston_df = boston_df[boston_df['B']>10]
boston_df = boston_df.reset_index()
boston_df.shape

# (500, 15)
# (493, 15)
```
![スクリーンショット 2021-10-22 16.06.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/088bed5c-665b-1be1-82a6-7fac52739190.png)

## スケーリング
```Python
col = ['NOX', 'RM', 'DIS', 'PTRATIO', 'LSTAT', 'MEDV']
boston_df[col].hist(bins=10, figsize=(10,8))

from sklearn.preprocessing import StandardScaler
# 標準化
scaler = StandardScaler()
boston_df['NOX'] = scaler.fit_transform(boston_df[['NOX']])

# 描画
plt.figure(figsize=[8,3])
sns.distplot(boston_df['NOX'], kde=True, fit=norm, fit_kws={'label': '正規分布'}).grid();
```
![スクリーンショット 2021-10-22 16.08.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/21f6ac9e-fb0c-16f9-2cca-3607a4d68ca7.png)
![スクリーンショット 2021-10-22 16.08.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/0bb9d6ba-eff8-df17-57d4-cec5caf56e38.png)
RM, DIS, PTRATIO, LSTAT, MEDVは、標準化しても精度に影響がなかったため、そのままとする。

## 特徴量生成
### クラスタリング、主成分分析
```Python
# クラスター数の探索（k-means++）
from sklearn.cluster import KMeans

def elbow(df):
    wcss = []
    for i in range(1, 10):
        kmeans = KMeans(n_clusters = i, init = 'k-means++', max_iter = 300, n_init = 30, random_state = 0)
        kmeans.fit(df.iloc[:, :])
        wcss.append(kmeans.inertia_)

    plt.figure(figsize=[8,4])
    plt.plot(range(1, 10), wcss)
    plt.title('エルボー法')
    plt.xlabel('クラスター数')
    plt.ylabel('クラスター内平方和（WCSS）')
    plt.grid()
    plt.show()

# 実行
elbow(boston_df)
```
![スクリーンショット 2021-10-22 16.10.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/926c776c-db2b-a155-d114-aaa4b460a1ce.png)

```Python
# 主成分分析
from sklearn.decomposition import PCA

# 寄与率
pca = PCA(n_components=3)
pca.fit(boston_df)
plt.figure(figsize=[8,4])
plt.grid()
plt.bar([n for n in range(1, len(pca.explained_variance_ratio_)+1)], pca.explained_variance_ratio_)
```
![スクリーンショット 2021-10-22 16.10.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/fbaf360e-7dc8-82ca-05b0-3e473161de59.png)

```Python
# 累積寄与率
contribution_ratio = pca.explained_variance_ratio_
accumulation_ratio = np.cumsum(contribution_ratio)
cc_ratio = np.hstack([0, accumulation_ratio])

plt.figure(figsize=[8,4])
plt.plot(accumulation_ratio, "-o")
plt.xlabel("主成分")
plt.ylabel("累積寄与率")
plt.grid()
plt.show()

contribution_ratios = pd.DataFrame(pca.explained_variance_ratio_)
contribution_ratios.round(decimals=2).astype('str').head()
print(f"累積寄与率：　{contribution_ratios[contribution_ratios.index<5].sum().round(decimals=2).astype('str').values}");

# 結果：累積寄与率：　['0.98']
```
![スクリーンショット 2021-10-22 16.11.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/d9ae6913-18dc-d0e4-6283-229218a07eb9.png)
第３主成分までで寄与率は98%。クラスター数=3とする。

```Python
# クラスタリング（k-means）
from sklearn.preprocessing import StandardScaler

def clustering(df, num):
    sc = StandardScaler()
    sc.fit_transform(df)
    data_norm = sc.transform(df)

    cls = KMeans(n_clusters = num)
    result = cls.fit(data_norm)
    pred = cls.fit_predict(data_norm)

    plt.figure(figsize=[8, 4])
    sns.scatterplot(x=data_norm[:,0], y=data_norm[:,1], c=result.labels_)
    plt.scatter(result.cluster_centers_[:,0], result.cluster_centers_[:,1], s=250, marker='*', c='blue')
    plt.grid('darkgray')
    plt.show()

# 実行
clustering(boston_df, 3)
```
![スクリーンショット 2021-10-22 16.11.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/d859eab6-ff6b-f745-27ef-5e762cd93eaf.png)
うまく分割できないため、主成分分析を行う。

```Python
## クラスタリング（k-means）＋主成分分析
from sklearn.decomposition import PCA

def cross(df, num):
    df_cls = df.copy()
    sc = StandardScaler()
    clustering_sc = sc.fit_transform(df_cls)
    
    # n_clusters：クラスター数
    kmeans = KMeans(n_clusters=num, random_state=42)
    clusters = kmeans.fit(clustering_sc)
    df_cls['cluster'] = clusters.labels_

    x = clustering_sc
    # n_components：削減結果の次元数
    pca = PCA(n_components=num)
    pca.fit(x)
    x_pca = pca.transform(x)
    pca_df = pd.DataFrame(x_pca)
    pca_df['cluster'] = df_cls['cluster']

    for i in df_cls['cluster'].unique():
       tmp = pca_df.loc[pca_df['cluster'] == i]
       plt.scatter(tmp[0], tmp[1])
    plt.grid()
    plt.show()

# 実行
cross(boston_df, 3)
```
![スクリーンショット 2021-10-22 16.11.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/5f4b733f-8a98-ca73-a901-f7b2a872480a.png)
今度はうまく分割することができた。
３つのクラスタと、その重心からの距離を算出する。

```Python
# 重心からの距離
def get_center_distance(df):
    num_cluster=3 # cluster数
    clusters = KMeans(n_clusters=num_cluster, random_state = 42)
    clusters.fit(df)
    centers = clusters.cluster_centers_

    columns = df.columns
    clust_features = pd.DataFrame(index = df.index)
    for i in range(len(centers)):
        clust_features['クラスタ' + str(i + 1) + 'との距離'] = (df[columns] - centers[i]).applymap(abs).apply(sum, axis = 1)
    return clust_features

# 実行
clust_features = get_center_distance(boston_df)
boston_df[clust_features.columns] = clust_features
boston_df.head()
```
![スクリーンショット 2021-10-22 16.11.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/2971ba87-45dd-c072-7c00-b909d71ed015.png)

### オーバーサンプリング

```Python
# SMOTE
from imblearn.over_sampling import SMOTE

column = 'CHAS'
sm = SMOTE(random_state=42)
X = boston_df.drop(columns=column, axis=1)
y = boston_df[column]
X_sample, Y_sample = sm.fit_resample(X, y)

over_sampling = pd.DataFrame()
over_sampling = X_sample
over_sampling[column] = Y_sample

value_counts = over_sampling[column].value_counts()

df = pd.DataFrame()
df['ラベル'] = value_counts.index
df['件数'] = value_counts.values
ratio=[]
ratio.append((value_counts.values[0] / len(over_sampling[column]) * 100).round(decimals=2).astype('str'))
ratio.append((value_counts.values[1] / len(over_sampling[column]) * 100).round(decimals=2).astype('str'))
df['割合'] = [f'{ratio[0]}%', f'{ratio[1]}%']
print(f"全レコード数：{len(over_sampling[column])}")
df

# 全レコード数：916
```
![スクリーンショット 2021-10-22 16.11.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/9b31a20b-3d1f-7169-da5d-94e352f304f1.png)
「CHAS」に対するオーバーサンプリングは、ランダムフォレストに対しては効果がある。その際「重心からの距離」がない方が精度が良い。
ただし、線形モデルに対しては、大幅な精度の悪化を招く。一旦、不採用とする。

### カウント・エンコーディング
```Python
count_map = boston_df['CHAS'].value_counts().to_dict()
count_map

df = boston_df.copy()
df['CHASカウント'] = df['CHAS'].map(count_map)
df[['CHAS', 'CHASカウント']].head()
df = df.drop(columns='CHAS', axis=1)
sns.distplot(df['CHASカウント'])

# 結果：{0: 458, 1: 35}
```
![スクリーンショット 2021-10-22 16.11.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/7d70cf46-7c28-251d-8b6d-b332b32319a9.png)
CAHSは住宅価格帯が異なるため、影響があると思ったが、得に影響はなかった。
出現頻度を学習させ、大小を明確にすれば影響が出ると考えたが、むしろ精度が悪化した。
一旦、このカウント・エンコーディングを採用するかは保留とする。

# 再評価
```Python
# 実行
rfr_model, y_test, y_pred = learning(RFR(random_state=42), boston_df)
```
決定係数（R2） =  0.924
平均絶対誤差（MAE） =  1.761
平均二乗誤差（MSE） =  5.588
対数平均二乗誤差（MSLE） =  0.018
平均二乗平方根誤差（RMSE） =  2.364
対数平方平均二乗誤差（RMSLE） =  0.134

```Python
# 線形回帰（重回帰）
from sklearn.linear_model import LinearRegression as LR
rfr_model, y_test, y_pred = learning(LR(), boston_df)
```
決定係数（R2） =  0.811
平均絶対誤差（MAE） =  2.919
平均二乗誤差（MSE） =  13.928
対数平均二乗誤差（MSLE） =  0.048
平均二乗平方根誤差（RMSE） =  3.732
対数平方平均二乗誤差（RMSLE） =  0.219

```Python
# 線形モデル
from sklearn.linear_model import Ridge
rfr_model, y_test, y_pred = learning(Ridge(), boston_df)
```
決定係数（R2） =  0.81
平均絶対誤差（MAE） =  2.924
平均二乗誤差（MSE） =  13.977
対数平均二乗誤差（MSLE） =  0.048
平均二乗平方根誤差（RMSE） =  3.739
対数平方平均二乗誤差（RMSLE） =  0.219

```Python
# 線形モデル
from sklearn.linear_model import Lasso
rfr_model, y_test, y_pred = learning(Lasso(), boston_df)
```
決定係数（R2） =  0.745
平均絶対誤差（MAE） =  3.172
平均二乗誤差（MSE） =  18.792
対数平均二乗誤差（MSLE） =  0.042
平均二乗平方根誤差（RMSE） =  4.335
対数平方平均二乗誤差（RMSLE） =  0.204

```Python
# 線形回帰（重回帰）
from sklearn.linear_model import ElasticNet
rfr_model, y_test, y_pred = learning(ElasticNet(), boston_df)
```
決定係数（R2） =  0.759
平均絶対誤差（MAE） =  3.112
平均二乗誤差（MSE） =  17.745
対数平均二乗誤差（MSLE） =  0.04
平均二乗平方根誤差（RMSE） =  4.212
対数平方平均二乗誤差（RMSLE） =  0.201


全体的に精度の向上が見られる。

# 特徴選択
```Python
# 実行
imp_df = rfr_importance(boston_df)
imp_df = imp_df.sort_values(by='重要度', ascending=False).reset_index().set_index("項目名")
imp_df = imp_df.drop(columns="index", axis=1)
imp_df
```
![スクリーンショット 2021-10-22 16.19.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/8e84831f-2cc3-c638-06d6-149b1aced8bb.png)

```Python
# 実行
boost_importance(boston_df)
```
![スクリーンショット 2021-10-22 16.19.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/26d51693-7d2f-12a2-29ff-8c5525c6b3e2.png)

```Python
# 実行
linear_importance(boston_df)
```
![スクリーンショット 2021-10-22 16.19.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/7c8bff96-96d9-d83e-7d4f-d1a79052519e.png)

```Python
explain_importance(boston_df)
```
![スクリーンショット 2021-10-22 16.22.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569276/2fa550f0-c47d-44ed-0742-dd9aea71721e.png)

# 結果を踏まえて再評価
```Python
features = boston_df.drop(columns=['INDUS', 'CRIM', 'level_0', 'index', 'クラスタ3との距離']).columns

# 実行
rfr_model, y_test, y_pred = learning(RFR(random_state=42), boston_df[features])
```
決定係数（R2） =  0.929
平均絶対誤差（MAE） =  1.712
平均二乗誤差（MSE） =  5.248
対数平均二乗誤差（MSLE） =  0.017
平均二乗平方根誤差（RMSE） =  2.291
対数平方平均二乗誤差（RMSLE） =  0.129

```Python
# 線形回帰（重回帰）
from sklearn.linear_model import LinearRegression as LR
rfr_model, y_test, y_pred = learning(LR(), boston_df[features])
```
決定係数（R2） =  0.827
平均絶対誤差（MAE） =  2.803
平均二乗誤差（MSE） =  12.766
対数平均二乗誤差（MSLE） =  0.036
平均二乗平方根誤差（RMSE） =  3.573
対数平方平均二乗誤差（RMSLE） =  0.189

```Python
# 線形モデル
from sklearn.linear_model import Ridge
rfr_model, y_test, y_pred = learning(Ridge(), boston_df[features])
```
決定係数（R2） =  0.827
平均絶対誤差（MAE） =  2.799
平均二乗誤差（MSE） =  12.736
対数平均二乗誤差（MSLE） =  0.036
平均二乗平方根誤差（RMSE） =  3.569
対数平方平均二乗誤差（RMSLE） =  0.189

```Python
# 線形モデル
from sklearn.linear_model import Lasso
rfr_model, y_test, y_pred = learning(Lasso(), boston_df[features])
```
決定係数（R2） =  0.767
平均絶対誤差（MAE） =  3.124
平均二乗誤差（MSE） =  17.171
対数平均二乗誤差（MSLE） =  0.032
平均二乗平方根誤差（RMSE） =  4.144
対数平方平均二乗誤差（RMSLE） =  0.179

```Python
# 線形回帰（重回帰）
from sklearn.linear_model import ElasticNet
rfr_model, y_test, y_pred = learning(ElasticNet(), boston_df[features])
```
決定係数（R2） =  0.773
平均絶対誤差（MAE） =  3.073
平均二乗誤差（MSE） =  16.698
対数平均二乗誤差（MSLE） =  0.031
平均二乗平方根誤差（RMSE） =  4.086
対数平方平均二乗誤差（RMSLE） =  0.176


新宿の例といい、犯罪率は住宅価格との関係はないのかもしれない。
CHASは「０⇆１」で住宅価格が異なっていたため、影響はあると思われたが、「CHAS」単体では影響があまりなかった。

# まとめ
実際に様々な手法を試して見て、効果があったもの、なかったものがあった。特に外れ値はどこまでを外れ値とするのかが判断が付けられず、モデル構築時の評価も加味して決めていきたい。
また過学習かどうかをまだ評価できていないため、モデル構築時（前）に確認することにします。

# 最後に
他の記事はこちらでまとめています。是非ご参照ください。
##
https://qiita.com/tk-tatsuro/items/b72e418724ceb78e4af9
##

# 解析結果
[実装結果：GitHub/boston_regression_preprocessing.ipynb](https://github.com/tk-tatsuro/data_science/blob/master/20211018_boston_regression/boston_regression_preprocessing.ipynb)
[データセット：Boston House Prices-Advanced Regression Techniques](https://www.kaggle.com/fedesoriano/the-boston-houseprice-data)

# 参考資料
##
https://www.oreilly.co.jp/books/9784873118680/
##