なんだかよくわからないCSVファイルで機械学習（回帰）を試すまでにしたことまとめ

# はじめに

データの分析を依頼されたのですが、秘匿情報が含まれるということから全然情報を頂けないままファイルを受け取り、初期診断をすることとなったので、その手順をまとめてみました。

前提条件として、これからこのような依頼が継続しそうなので、他のツールを使って確認するというのではなく、初期診断用のスクリプトを作成することを目的とします。

# ファイルのエンコーディングを確認

まずはファイルを開くためにエンコーディングを確認します。
ここでは、日本語圏を対象としているので、日本語を扱うエンコーディングのみを試します。

```py:
f = lambda d, e: d.decode(e) and e  
encs = ["utf-8", "shift-jis", "euc-jp", "iso2022-jp"]

datfile = open("sample.csv", "br")
data = datfile.read(256)
datfile.close()

encoding = ""

for enc in encs:
    try:
        f(data, enc)
        encoding = enc
        break
    except:
        pass

print(encoding)
```

実行してみると以下のとおりでした。

```
shift-jis
```

ということで、これはシフトJISであると認識。

# ファイルを開く

```py:
import pandas as pd

df = pd.read_csv("sample.csv", encoding=encoding)
df.info()
```

実行してみると、以下のとおりでした。

```
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3903 entries, 0 to 3902
Columns: 1468 entries, y to Data1490
dtypes: float64(1346), int64(31), object(91)
memory usage: 30.3+ MB
```

ここで、このCSVは3,903行、1,468列ということがわかりました。

# 列名の確認

以下のコマンドで列名をリスト形式で取得し、とりあえず内容を確認してみます。

```py:
cols = df.columns.tolist()
print(cols)
```

ここでは、1列目のデータが予測対象として良さそうだったので、これを予測対象にすることとしました。
これは状況により異なると思うので、ケースバイケースで確認。

# 一意の列を削除

機械学習を試すにあたり、列中の値が全て同一のものは不要なので、これを削除します。

```py:
drop_cols = []

for col in df.columns:
    if df[col].value_counts().shape[0] == 1:
        print(col)
        drop_cols.append(col)
        
df = df.drop(drop_cols, axis=1)
```

これを実行すると、不要な列の名称が表示され、最後にその列が削除されます。

# 種別が多すぎるオブジェクト列の削除

種別が多すぎる文字列はシリアル番号などあまり意味をなさないものが多いと判断し、ここでは行数の1/10以上の種別を持つオブジェクトを削除します。

```py:
drop_cols = []

i = int(df.shape[0] / 10) - 1

for col in df.columns:
    if df[col].dtype == "O":
        if df[col].value_counts().shape[0] > i:
            print(col)
            drop_cols.append(col)
        
df = df.drop(drop_cols, axis=1)
```

# オブジェクト列のOne-hotエンコーディング

オブジェクト列を発生値別にOne-hotエンコーディングし、もとのオブジェクト列を削除します。

```py:
drop_cols = []

print(df.shape)

for col in df.columns:
    if df[col].dtype == "O":
        df = df.join(pd.get_dummies(df[col], prefix=col))
        drop_cols.append(col)

df = df.drop(drop_cols, axis=1)
```

ここまで加工ができたらもう一度データの状態を確認してみます。

```
df.info()
```

上記のコマンドを実行してみると、以下の通り。

```
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3903 entries, 0 to 3902
Columns: 1417 entries, y to Data1490
dtypes: float64(1344), int64(25), uint8(48)
memory usage: 28.2 MB
```

これで、数値データのみに変換できました。

# 欠損データの削除

きちんと見ないで実行するのは気が引けますが、とりあえず欠損値がある行は削除します。

```py:
df = df.dropna()
```

# 予測値を整数値に変換

予測対象の値は整数値である必要があることから、予測対象の列が実数なら小数点以下の値を整数となるよう変換します。

まずは、値の全体像を確認します。

```py:
df[df.columns[0]].describe()
```

ここで、小数点以下第2位まで使用していれば、この列に100をかけて整数化します。

```py:
col = df.columns[0]
df[col] = df[col] * 100
```

# 入力と出力に分割

列番号を指定して入力Xと出力yに分割します。

```py:
cols = df.columns.tolist()
X_cols = cols[1:]
y_cols = [cols[0]]

X = df[x_cols].as_matrix().astype('float64')
y = df[y_cols].as_matrix().astype('int').flatten()
```

# データの加工

テストデータのランダムサンプリング（クロスバリデーション）と正規化をします。

```py:
# クロスバリデーション
from sklearn import model_selection

X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=.1, random_state=42)

# 正規化
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(X_train)

X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)
```

# 複数アルゴリズムによる学習と予測精度の検証

scikit-learnのもっている回帰用アルゴリズムで一通りの予測精度を確認してみます。

```py:
# モデルの設定

# ランダムフォレスト
from sklearn.ensemble import RandomForestRegressor, ExtraTreesRegressor
rf = RandomForestRegressor(random_state=42)
et = ExtraTreesRegressor(random_state=42)

# 勾配ブースティング
from sklearn.ensemble import GradientBoostingRegressor
gbr = GradientBoostingRegressor(random_state=42)

from sklearn.linear_model import LinearRegression
lr = LinearRegression()

from sklearn.linear_model import Ridge
ridge = Ridge(random_state=42)

from sklearn.svm import SVR
svr_rbf = SVR(kernel='rbf')

from xgboost import XGBRegressor
xgb = XGBRegressor()

from sklearn.neural_network import MLPRegressor
mlp = MLPRegressor(max_iter=1000, random_state=42)

from mlxtend.regressor import StackingRegressor
sr = StackingRegressor(regressors=[mlp, et, rf], meta_regressor=xgb)

models = [rf, et, gbr, lr, ridge, svr_rbf, xgb, mlp, sr]

for model in models:
    model.fit(X_train, y_train)
    print(model)
    print(model.score(X_test,y_test))
    print("===")
```

上記を実行し、モデルごとの精度を確認。

# 特徴量の重要度を確認

上記で学習したRandomForestのモデルから、特徴量の重要度を確認します。

```py:
df_fi = pd.DataFrame(rf.feature_importances_, index=X_cols, columns=['importance'])
df_fi.sort_values(by="importance", inplace=True)
df_fi.tail(10)
```

以上、ほとんど情報のないCSVファイルで機械学習を行うまでの手順でした。