[Kaggle] Predict Future Engineeringをやってみる

## はじめに
ゴールデンウィークに外出ができなかったので、kaggleの「Predict Future Sales」に挑戦してみました。

このお題は、日ごとに集計されたデータ（2013.1〜2015.10）から来月（2015.11）の商品の売上個数を予測するものです。

今回のデータの特徴は、

・とにかくデータが量が多い
・学習データとテストデータとでshopの種類とitemの種類が異なる
・学習データは日毎で、予測するのは月の売上個数なので、形式をテストデータに合わせる必要がある
・時系列の要素があるのでラグをとった特徴量を追加する必要がある


では、やっていきます。

今回はこれを参考にやっていきました。
[kaggle: Feature engineering, xgboost](https://www.kaggle.com/dlarionov/feature-engineering-xgboost)

## ライブラリのインポート
```python3
import copy
import numpy as np
import pandas as pd
from itertools import product

import matplotlib.pyplot as plt
import seaborn as sns

from lightgbm.sklearn import LGBMRegressor
from lightgbm import plot_importance
from sklearn.preprocessing import LabelEncoder

pd.set_option('display.max_rows', 100)
```

## データの読み込み
```python3
day_train_data = pd.read_csv('path/sales_train.csv')
month_test_data = pd.read_csv('path/test.csv')
item_categories = pd.read_csv('path/item_categories.csv')
items = pd.read_csv('path/items.csv')
shops = pd.read_csv('path/shops.csv')
```

## データの修正
今回はday_train_dataにある'date'は使わないので、先に削除していきます。

```python3
day_train_data.drop('date', axis=1, inplace=True)
```

### big_category_idとsub_category_idの作成
item_categoriesの'item_category_name'を確認してみると、'-'の前後でカテゴリーが分かれています。

```python3
item_categories['item_category_name'].head()


# [出力結果]
# 0    PC - Гарнитуры/Наушники
# 1           Аксессуары - PS2
# 2           Аксессуары - PS3
# 3           Аксессуары - PS4
# 4           Аксессуары - PSP
# Name: item_category_name, dtype: object
```

これを分解してlabel encodingしていきます。また、同じような名前がついたものもあるので、修正していきます。

```python3
item_categories['split_name'] = item_categories['item_category_name'].str.split('-')
item_categories['big_category_name'] =\
     item_categories['split_name'].map(lambda x: x[0].strip())
item_categories['sub_category_name'] =\
     tem_categories['split_name'].map(lambda x: x[1].strip() if len(x) > 1 else x[0].strip())

item_categories.loc[item_categories['big_category_name'] == 'Чистые носители(штучные)', 'big_category_name'] = 'Чистые носители (шпиль)'

# label encoding
item_categories['big_category_id'] = LabelEncoder().fit_transform(item_categories['big_category_name'])
item_categories['sub_category_id'] = LabelEncoder().fit_transform(item_categories['sub_category_name'])

# データの整理
item_categories = item_categories[['item_category_id', 'big_category_id', 'sub_category_id']]
```

###city_idの作成と修正
カテゴリーと同様に、shopsの'shop_name'から都市の情報が得られるので、変数にしていきます。
ついでに、入力ミスもあるので、それも修正していきます。

```python3
shops.loc[shops['shop_name'] == 'Сергиев Посад ТЦ "7Я"', 'shop_name'] = 'СергиевПосад ТЦ "7Я"'

shops['city_name'] = shops['shop_name'].map(lambda x: x.split(' ')[0])
shops.loc[shops['city_name'] == '!Якутск', 'city_name'] = 'Якутск'

# label encoding
shops['city_id'] = LabelEncoder().fit_transform(shops['city_name'])

# データの整理
shops = shops[['shop_id', 'city_id']]
```

###shop_idの修正
'shop_name'を見てみると、同じような名前になっています。kaggleのNotebooksを確認すると、どうやら同じっぽいので、修正していきます。これ以外にも後何個か存在します。

```python3
shops[(shops['shop_id'] == 0) | (shops['shop_id'] == 57)]
```
[出力結果]

|  |  |  |
|:--|:--|:--|
| shop_id | shop_name |
| 0 | !Якутск Орджоникидзе, 56 фран | 0 |
| 57 | Якутск Орджоникидзе, 56 | 57 |

修正するファイルは、day_train_dataとmonth_test_dataです。今回のプログラムでは、shopsの方はいじらない方がいいと思います。（後でマージとかをやるので、データ量地獄に陥ります。）

```python3
# shop_idの修正
day_train_data.loc[day_train_data['shop_id'] == 0, 'shop_id'] = 57
month_test_data.loc[month_test_data['shop_id'] == 0, 'shop_id'] = 57

day_train_data.loc[day_train_data['shop_id'] == 1, 'shop_id'] = 58
month_test_data.loc[month_test_data['shop_id'] == 1, 'shop_id'] = 58

day_train_data.loc[day_train_data['shop_id'] == 10, 'shop_id'] = 11
month_test_data.loc[month_test_data['shop_id'] == 10, 'shop_id'] = 11
```

###item_priceとitem_cnt_dayの修正
item_priceとitem_cnt_dayで大きく値が外れているデータを削除していきます。
また、item_priceにマイナスの値があるので、同じ時期に同じ場所で売られているアイテムの中央値で修正をしていきます。

```python3
# 外れ値の削除
day_train_data.drop(day_train_data[day_train_data['item_price'] >= 100000].index, inplace=True)
day_train_data.drop(day_train_data[day_train_data['item_cnt_day'] > 1000].index, inplace=True)

# item_priceのエラー値を修正
median = day_train_data[(day_train_data['date_block_num'] == 4) & (day_train_data['shop_id'] == 32) & (day_train_data['item_id'] == 2973) & (day_train_data['item_price'] >= 0)]['item_price'].median()
day_train_data.loc[day_train_data['item_price'] < 0, 'item_price'] = median
```

### データセットの作成
データセットの作成を行なっていきたいと思います。今回作成するデータセットは、day_train_dataとmonth_test_dataを合体させた不完全なパネルデータ??的な感じでです。また、予測するのは、month_test_dataにあるshopごとのitemなので、month_test_dataをdate_block_numの分だけコピーして縦にくっつけるような完全なパネルデータを作成するのもありだと思います。
ただ、その方法をやると、day_train_dataの一部が無駄になってしまうので、今回は前者の方でやっていきたいと思います。

```python3
# data_setの作成
data_set = []
cols = ['date_block_num', 'shop_id', 'item_id']
for date_num in range(34):
    sales = day_train_data[day_train_data['date_block_num'] == date_num]
    data_set.append(np.array(list(product([date_num],
                                          sales['shop_id'].unique(),
                                          sales['item_id'].unique()))))

data_set = pd.DataFrame(np.vstack(data_set), columns=cols)
data_set.sort_values(cols, inplace=True)
data_set = data_set.reset_index(drop=True)

# month_test_dataのmerge
month_test_data['date_block_num'] = 34
month_test_data['date_block_num'] = month_test_data['date_block_num']
month_test_data['shop_id'] = month_test_data['shop_id']
month_test_data['item_id'] = month_test_data['item_id']

data_set = pd.concat([data_set, month_test_data], ignore_index=True, sort=False, keys=cols)

# data_set = data_set + shops [city_id]
data_set = pd.merge(data_set, shops, on=['shop_id'], how='left')

# data_set = data_set + items [item_category_id]
data_set = pd.merge(data_set, items[['item_id', 'item_category_id']], on=['item_id'], how='left')

# data_set = data_set + item_categories [big_category_id, sub_category_id]
data_set = pd.merge(data_set, item_categories, on=['item_category_id'], how='left')
```

### item_cnt_monthの作成
day_train_dataから月の売上個数を作成していきたいと思います。
この変数が目的変数となります。kaggleを見てみると、この変数をクリップした方が予測精度が上がるらしいです。

```python3
# item_sales_dayの作成
day_train_data['item_sales_day'] = day_train_data['item_price'] * day_train_data['item_cnt_day']

# item_cnt_monthの作成とmerge
merge_data = day_train_data.groupby(['date_block_num', 'shop_id', 'item_id'], as_index=False)['item_cnt_day'].agg('sum').rename(columns={'item_cnt_day': 'item_cnt_month'})

data_set = pd.merge(data_set, merge_data, on=cols, how='left')
data_set['item_cnt_month'] = data_set['item_cnt_month'].fillna(0).clip(0, 20)
```
月ごとのitem_cnt_monthをグラフに出してみます。

```python3
plot_data = day_train_data.groupby(['date_block_num'], as_index=False)['item_cnt_day'].agg('sum').rename(columns={'item_cnt_day': 'item_cnt_month'})

plt.figure(figsize=(20, 10))
sns.lineplot(data=plot_data, x='date_block_num', y='item_cnt_month')
```


![date_cnt_month.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614282/e36ad219-93e0-2844-cf7a-69d1f2f7420f.png)

年々、減少傾向にあり、毎年12月に同じような感じで売上個数が上がっていて、周期性が確認できます。
こういうところを変数として入れてあげると精度が上がりそうです。
変動分解でもっと細かくみていきたいと思います。

```python3
import statsmodels.api as sm
res = sm.tsa.seasonal_decompose(plot_data['item_cnt_month'], freq=12)

plt.subplots_adjust(hspace=0.3)
plt.figure(figsize=(15, 9))
plt.subplot(411)
plt.plot(res.observed, lw=.6, c='darkblue')
plt.title('observed')
plt.subplot(412)
plt.plot(res.trend, lw=.6, c='indianred')
plt.title('trend')
plt.subplot(413)
plt.plot(res.seasonal, lw=.6, c='indianred')
plt.title('seasonal')
plt.subplot(414)
plt.plot(res.resid, lw=.6, c='indianred')
plt.title('residual')
```

ここで一旦、データをキャストしていきます。

```python3
data_set.fillna(0, inplace=True)
data_set['date_block_num'] = data_set['date_block_num'].astype(np.uint8)
data_set['shop_id'] = data_set['shop_id'].astype(np.uint8)
data_set['item_id'] = data_set['item_id'].astype(np.uint16)
data_set['item_cnt_month'] = data_set['item_cnt_month'].astype(np.float16)
data_set['ID'] = data_set['ID'].astype(np.uint32)
data_set['city_id'] = data_set['city_id'].astype(np.uint8)
data_set['item_category_id'] = data_set['item_category_id'].astype(np.uint8)
data_set['big_category_id'] = data_set['big_category_id'].astype(np.uint8)
data_set['sub_category_id'] = data_set['sub_category_id'].astype(np.uint8)
```


![residual.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614282/5f97cb6a-2276-125f-a3e6-eb901874c6f7.png)

これを見ると、傾向や季節性があるのがよく分かりますね。

## Feature Engineering
この関数は今回たくさん使っていきますが、一時的にメモリをたくさん使うので注意です。

```python3
def feature_lags(df, lags, lag_col):
    tmp = df[['date_block_num', 'shop_id', 'item_id', lag_col]]
    for lag in lags:
        shifted = tmp.copy()
        
        shifted.columns = ['date_block_num', 'shop_id', 'item_id', str(lag_col) + '_lag_' + str(lag)]
        
        shifted['date_block_num'] += lag
        shifted = shifted[shifted['date_block_num'] <= 34]
        
        df = pd.merge(df, shifted, on=['date_block_num', 'shop_id', 'item_id'], how='left', copy=False)

    return df
```

### item_cnt_monthのfeature engineering

```python3
#target_lags
data_set = feature_lags(df=data_set, lags=[1, 2, 3, 6, 12], lag_col='item_cnt_month')


# date_avg_item_cnt
date_avg_item_cnt = data_set.groupby(['date_block_num'], as_index=False)['item_cnt_month'].agg('mean').rename(columns={'item_cnt_month': 'date_avg_item_cnt'})

data_set = pd.merge(data_set, date_avg_item_cnt, on=['date_block_num'], how='left')

data_set = feature_lags(df=data_set, lags=[1], lag_col='date_avg_item_cnt')
data_set.drop(['date_avg_item_cnt'], axis=1, inplace=True)


# date_item_avg_item_cnt
date_item_avg_item_cnt = data_set.groupby(['date_block_num', 'item_id'], as_index=False)['item_cnt_month'].agg('mean').rename(columns={'item_cnt_month': 'date_item_avg_item_cnt'})

data_set = pd.merge(data_set, date_item_avg_item_cnt, on=['date_block_num', 'item_id'], how='left')

data_set = feature_lags(df=data_set, lags=[1], lag_col='date_item_avg_item_cnt')
data_set.drop(['date_item_avg_item_cnt'], axis=1, inplace=True)


# date_shop_avg_item_cnt
date_shop_avg_item_cnt = data_set.groupby(['date_block_num', 'shop_id'], as_index=False)['item_cnt_month'].agg('mean').rename(columns={'item_cnt_month': 'date_shop_avg_item_cnt'})

data_set = pd.merge(data_set, date_shop_avg_item_cnt, on=['date_block_num', 'shop_id'], how='left')

data_set = feature_lags(df=data_set, lags=[1], lag_col='date_shop_avg_item_cnt')
data_set.drop(['date_shop_avg_item_cnt'], axis=1, inplace=True)


# date_category_avg_item_cnt
date_category_avg_item_cnt = data_set.groupby(['date_block_num', 'item_category_id'], as_index=False)['item_cnt_month'].agg('mean').rename(columns={'item_cnt_month': 'date_category_avg_item_cnt'})

data_set = pd.merge(data_set, date_category_avg_item_cnt, on=['date_block_num', 'item_category_id'], how='left')

data_set = feature_lags(df=data_set, lags=[1], lag_col='date_category_avg_item_cnt')
data_set.drop(['date_category_avg_item_cnt'], axis=1, inplace=True)


# date_shop_category_avg_item_cnt
date_shop_category_avg_item_cnt = data_set.groupby(['date_block_num', 'shop_id', 'item_category_id'], as_index=False)['item_cnt_month'].agg('mean').rename(columns={'item_cnt_month': 'date_shop_category_avg_item_cnt'})

data_set = pd.merge(data_set, date_shop_category_avg_item_cnt, on=['date_block_num', 'shop_id', 'item_category_id'], how='left')

data_set = feature_lags(df=data_set, lags=[1], lag_col='date_shop_category_avg_item_cnt')
data_set.drop(['date_shop_category_avg_item_cnt'], axis=1, inplace=True)


# date_shop_bigcat_avg_item_cnt
date_shop_bigcat_avg_item_cnt = data_set.groupby(['date_block_num', 'shop_id', 'big_category_id'], as_index=False)['item_cnt_month'].agg('mean').rename(columns={'item_cnt_month': 'date_shop_bigcat_avg_item_cnt'})

data_set = pd.merge(data_set, date_shop_bigcat_avg_item_cnt, on=['date_block_num', 'shop_id', 'big_category_id'], how='left')

data_set = feature_lags(df=data_set, lags=[1], lag_col='date_shop_bigcat_avg_item_cnt')
data_set.drop(['date_shop_bigcat_avg_item_cnt'], axis=1, inplace=True)


# date_shop_subcat_avg_item_cnt
date_shop_subcat_avg_item_cnt = data_set.groupby(['date_block_num', 'shop_id', 'sub_category_id'], as_index=False)['item_cnt_month'].agg('mean').rename(columns={'item_cnt_month': 'date_shop_subcat_avg_item_cnt'})

data_set = pd.merge(data_set, date_shop_subcat_avg_item_cnt, on=['date_block_num', 'shop_id', 'sub_category_id'], how='left')

data_set = feature_lags(df=data_set, lags=[1], lag_col='date_shop_subcat_avg_item_cnt')
data_set.drop(['date_shop_subcat_avg_item_cnt'], axis=1, inplace=True)


# date_bigcat_avg_item_cnt
date_bigcat_avg_item_cnt = data_set.groupby(['date_block_num', 'big_category_id'], as_index=False)['item_cnt_month'].agg('mean').rename(columns={'item_cnt_month': 'date_bigcat_avg_item_cnt'})

data_set = pd.merge(data_set, date_bigcat_avg_item_cnt, on=['date_block_num', 'big_category_id'], how='left')

data_set = feature_lags(df=data_set, lags=[1], lag_col='date_bigcat_avg_item_cnt')
data_set.drop(['date_bigcat_avg_item_cnt'], axis=1, inplace=True)


# date_subcat_avg_item_cnt
date_subcat_avg_item_cnt = data_set.groupby(['date_block_num', 'sub_category_id'], as_index=False)['item_cnt_month'].agg('mean').rename(columns={'item_cnt_month': 'date_subcat_avg_item_cnt'})

data_set = pd.merge(data_set, date_subcat_avg_item_cnt, on=['date_block_num', 'sub_category_id'], how='left')

data_set = feature_lags(df=data_set, lags=[1], lag_col='date_subcat_avg_item_cnt')
data_set.drop(['date_subcat_avg_item_cnt'], axis=1, inplace=True)


# date_city_avg_item_cnt
date_city_avg_item_cnt = data_set.groupby(['date_block_num', 'city_id'], as_index=False)['item_cnt_month'].agg('mean').rename(columns={'item_cnt_month': 'date_city_avg_item_cnt'})

data_set = pd.merge(data_set, date_city_avg_item_cnt, on=['date_block_num', 'city_id'], how='left')

data_set = feature_lags(df=data_set, lags=[1], lag_col='date_city_avg_item_cnt')
data_set.drop(['date_city_avg_item_cnt'], axis=1, inplace=True)


# date_item_city_avg_item_cnt
date_item_city_avg_item_cnt = data_set.groupby(['date_block_num', 'item_id', 'city_id'], as_index=False)['item_cnt_month'].agg('mean').rename(columns={'item_cnt_month': 'date_item_city_avg_item_cnt'})

data_set = pd.merge(data_set, date_item_city_avg_item_cnt, on=['date_block_num', 'item_id', 'city_id'], how='left')

data_set = feature_lags(df=data_set, lags=[1], lag_col='date_item_city_avg_item_cnt')
data_set.drop(['date_item_city_avg_item_cnt'], axis=1, inplace=True)
```

### item_salesのfature engineering

```python3
# item_avg_item_price
item_avg_item_price = day_train_data.groupby(['item_id'], as_index=False)['item_price'].agg('mean').rename(columns={'item_price': 'item_avg_item_price'})

data_set = pd.merge(data_set, item_avg_item_price, on=['item_id'], how='left')


# date_item_avg_item_price
date_item_avg_item_price = day_train_data.groupby(['date_block_num', 'item_id'], as_index=False)['item_price'].agg('mean').rename(columns={'item_price': 'date_item_avg_item_price'})

data_set = pd.merge(data_set, date_item_avg_item_price, on=['date_block_num', 'item_id'], how='left')


lags = [1, 2, 3, 4, 5, 6]
data_set = feature_lags(df=data_set, lags=lags, lag_col='date_item_avg_item_price')

for lag in lags:
    data_set['delta_price_lag_' + str(lag)]  = (data_set['date_item_avg_item_price_lag_' + str(lag)] - data_set['item_avg_item_price'] / data_set['item_avg_item_price'])

def select_trend(row):
    for lag in lags:
        if row['delta_price_lag_' + str(lag)]:
            return row['delta_price_lag_' + str(lag)]
    return 0    

data_set['delta_price_lag'] = data_set.apply(select_trend, axis=1)
data_set['delta_price_lag'].fillna(0, inplace=True)


# 使わないデータの削除
features_to_drop = ['item_avg_item_price', 'date_item_avg_item_price']
for lag in lags:
    features_to_drop += ['date_item_avg_item_price_lag_' + str(lag)]
    features_to_drop += ['delta_price_lag_' + str(lag)]
    
data_set.drop(features_to_drop, axis=1, inplace=True)
```

### item_sales_dayのfeature engineering

```python3
date_shop_sales = day_train_data.groupby(['date_block_num', 'shop_id'], as_index=False)['item_sales_day'].agg('sum').rename(columns={'item_sales_day': 'date_shop_sales'})

data_set = pd.merge(data_set, date_shop_sales, on=['date_block_num', 'shop_id'], how='left')

shop_avg_sales = day_train_data.groupby(['shop_id'], as_index=False)['item_sales_day'].agg('mean').rename(columns={'item_sales_day': 'shop_avg_sales'})

data_set = pd.merge(data_set, shop_avg_sales, on=['shop_id'], how='left')

data_set['delta_sales'] = (data_set['date_shop_sales'] - data_set['shop_avg_sales']) / data_set['shop_avg_sales']
data_set = feature_lags(df=data_set, lags=[1], lag_col='delta_sales')
data_set.drop(['date_shop_sales', 'shop_avg_sales', 'delta_sales'], axis=1, inplace=True)
```

### 月データと月の日数

```python3
data_set['month'] = data_set['date_block_num'] % 12

days = pd.Series([31,28,31,30,31,30,31,31,30,31,30,31])
data_set['day'] = data_set['month'].map(days)
data_set['day'] = data_set['day'].astype(np.uint8)
```

## train_dataとtest_dataの作成

data_setからデータを分ける前にmergeによるNaNに0を入れておきます。

```python3
data_set.fillna(0, inplace=True)
```

これでdata_setの完成です。
data_setの情報を載せておきます。
これをキャストしていないと倍以上のデータ量になっていると思います。

```python3
data_set.info()

""" out
 <class 'pandas.core.frame.DataFrame'>
Int64Index: 11128004 entries, 0 to 11128003
Data columns (total 29 columns):
date_block_num                           uint8
shop_id                                  uint8
item_id                                  uint16
item_cnt_month                           float16
ID                                       uint32
city_id                                  uint8
item_category_id                         uint8
big_category_id                          uint8
sub_category_id                          uint8
item_cnt_month_lag_1                     float16
item_cnt_month_lag_2                     float16
item_cnt_month_lag_3                     float16
item_cnt_month_lag_6                     float16
item_cnt_month_lag_12                    float16
date_avg_item_cnt_lag_1                  float16
date_item_avg_item_cnt_lag_1             float16
date_shop_avg_item_cnt_lag_1             float16
date_category_avg_item_cnt_lag_1         float16
date_shop_category_avg_item_cnt_lag_1    float16
date_shop_bigcat_avg_item_cnt_lag_1      float16
date_shop_subcat_avg_item_cnt_lag_1      float16
date_bigcat_avg_item_cnt_lag_1           float16
date_subcat_avg_item_cnt_lag_1           float16
date_city_avg_item_cnt_lag_1             float16
date_item_city_avg_item_cnt_lag_1        float16
delta_price_lag                          float64
delta_sales_lag_1                        float64
month                                    uint8
day                                      uint8
dtypes: float16(17), float64(2), uint16(1), uint32(1), uint8(8)
memory usage: 764.1 MB
"""
```

次にtrain_dataとtest_dataを作成していきます。

```python3
target_col = 'item_cnt_month'
exclude_cols = ['ID', target_col]

feature_cols = []
for col in train_data.columns:
    if col not in exclude_cols:
        feature_cols.append(col)

x_train = train_data[train_data['date_block_num'] <= 32][feature_cols]
y_train = train_data[train_data['date_block_num'] <= 32][target_col]
x_val = train_data[train_data['date_block_num'] == 33][feature_cols]
y_val = train_data[train_data['date_block_num'] == 33][target_col]
x_test = test_data[feature_cols]
```

## LightGBMによる学習
まずは、チューニングさせずにデフォルトでやっていきたいと思います。

```python3
ts = time.time()

gbm = LGBMRegressor(n_jobs=-1)
gbm.fit(x_train, y_train,
       eval_metric='rmse',
       eval_set=(x_val, y_val))

time.time() - ts

# rmse: 0.948226
# time:23.153272
```
チューニングなしだと0.948226でした。時間も30秒以内でランダムフォレストとかよりもだいぶ早く学習してくれました。

次に、max_depthとn_estimatorsを変えてやっていきたいと思います。

```python3
ts = time.time()

gbm = LGBMRegressor(n_estimators=10000, max_depth=10, n_jobs=-1)
gbm.fit(x_train, y_train,
        early_stopping_rounds=20,
        eval_metric='rmse',
        eval_set=(x_val, y_val),
        verbose=1)

time.time() - ts

# Early stopping, best iteration is: [105] valid_0's rmse: 0.943153
# time30.228255
```
n_estimatorsが105の時がベストスコアとなりました。
あんまりrmseに変化はないですね。

feature_importancesを可視化してみます。
date_item_avg_item_cnt_lag_1が一番効いてますね。

![feature_importances.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614282/2b15d568-c2c2-29d0-615d-5abdb9fcc01a.png)



このモデルでpredictした結果をkaggleに提出しました。

結果は、0.96079でした。

## 終わりに
今回は、kaggleのNotebooksを参考にデータを作り予測してみました。

まだ、ハイパーパラメーターのチューニングをしっかりやっていないので、
次回は、optunaというライブラリのLightGBM lunarでチューニングをしていきたいと思います。