[Ubiquant Market Prediction]investment_idの数の特徴量エンジニアリング

こんにちは、tmrtjと申します。

私は現在株式会社音圧爆上げくんという会社に所属しており、プロKagglerとして活動しています。


私は現在プロKagglerとして、業務の一環で、現在Kaggleで行われているコンペの一つである[Ubiquant Market Prediction](https://www.kaggle.com/c/ubiquant-market-prediction)に参加しています。



また、Kaggle上にNoteBookとして同じ内容の記事を英語で投稿しています。
リンクは[こちら](https://www.kaggle.com/code/tmrtj9999/number-of-investment-ids-feature-engineering)です。

# はじめに
[以前公開した記事](https://qiita.com/tmrtj9999/items/15abb2ba3a6ea124dcbc)で各time_idごとに与えられるinvestment_idの数が特徴量として効いていることを指摘しました。

簡単に要約すると、与えられるtime_idごとのinvestment_idの数は、その時々の相場の状況を反映していると考えられるので、これを特徴量として加えることは相場全体の状況をモデルに学習させることが可能になるので、精度の向上が見込めるというものです。

<br>
前回記事を投稿した際に、ある方から、自分も同じことに気づき、このinvestment_idを用いた特徴量を作っているというコメントをもらいました。

<br>

そこで、今回は、その方に倣い、このinvestment_idの数を使った特徴量エンジニアリングを行いたいと思います。



# 実装

まずはデータを読み込んでDataFrameにします。
データは[こちら](https://www.kaggle.com/code/tmrtj9999/number-of-investment-ids-feature-engineering/data)にあります。

```
import os
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
%matplotlib inline

import warnings
warnings.filterwarnings('ignore')

import lightgbm as lgbm
from lightgbm import *

df = pd.read_parquet('../input/num-investment2/num_investment2.parquet')

df.head(3)

```
<br>
<br>
今回はあらかじめ特徴量エンジニアリングをしておいたデータセットを読み込んでいます。
num_investment は各time_idに与えられるinvestment_idの数です。
<br>
<br>
今回作った特徴量は次の8つです。

shift1~5 : 1~5つ前のtime_idのnum_investment

MA3~5 : 3~5つのtime_idのnum_investmentの移動平均


<br>
<br>
次に、DataFrameをtrainデータとvalデータに分割します。
また、メモリの関係でデータ量を半分ほどに減らしています。

```
from sklearn.model_selection import KFold, train_test_split

df = df.tail(1500000)


features = [f'f_{i}' for i in range(300)] + ['num_investment'] + ['shift1'] + ['shift2'] + ['shift3'] + ['shift4'] + ['shift5'] + ['MA3'] + ['MA4'] + ['MA5']
target = 'target'
 

df_features = df[features]


X_train, X_val, Y_train, Y_val = train_test_split(df_features, df[target], train_size=0.95, shuffle=False)

df = [[]]
df_features = [[]]
```

<br>
<br>
LightGBMを訓練します。

```
import warnings
import numpy as np
import lightgbm as lgb
from scipy.stats import pearsonr

warnings.simplefilter('ignore')

lgb_train = lgb.Dataset(X_train, Y_train)
lgb_eval = lgb.Dataset(X_val, Y_val, reference=lgb_train)

params = {'seed': 1,
          'verbose' : -1,
           'objective': "regression",
           'learning_rate': 0.05,
           'bagging_fraction': 0.1,
           'bagging_freq': 1,
           'feature_fraction': 0.1,
           'max_depth': 6,
           'min_child_samples': 50,
           'num_leaves': 64}
        
        
gbm = lgb.train(params,
                lgb_train,
                num_boost_round=100,
                valid_sets=lgb_eval,
                verbose_eval=False,
                early_stopping_rounds=3,
                )
```
<br>
<br>
LightGBMの特徴量重要度を表示します。

```
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report


feature = gbm.feature_importance(importance_type='gain')


f = pd.DataFrame({'number': range(0, len(feature)),
             'feature': feature[:]})
f2 = f.sort_values('feature',ascending=False)

#features' name
label = X_train.columns[0:]

#feature rank
indices = np.argsort(feature)[::-1]

for i in range(len(feature)):
    print(str(i + 1) + "   " + str(label[indices[i]]) + "   " + str(feature[indices[i]]))

```

<br>

**結果**

```
1   f_165   1197.664894104004
2   f_225   901.429506778717
3   f_265   772.9778952598572
4   f_214   673.8714933395386
5   f_162   644.2225737571716
6   f_145   632.420093536377
7   f_197   625.5912256240845
8   f_231   621.1813793182373
9   f_237   539.0640888214111
10   f_71   521.0499067306519
11   f_250   504.91419792175293
12   f_155   495.4427080154419
13   MA4   490.6195001602173
14   f_172   484.8055000305176
15   f_150   462.29086685180664
16   f_297   459.76996421813965
17   f_22   443.6003403663635
18   MA5   442.3247423171997
19   f_168   419.3555965423584
20   f_100   410.9847984313965
21   f_21   405.01240253448486
22   f_65   404.82549476623535
23   f_19   395.8521957397461
24   f_232   394.36760807037354
25   f_234   387.3837785720825
26   f_221   381.82348012924194
27   f_299   375.99611949920654
28   f_285   372.09964656829834
29   f_31   364.26818084716797
30   f_273   354.4165678024292
31   f_210   348.2259130477905
32   f_206   347.2803087234497
33   f_292   336.5254650115967
34   f_25   326.1350984573364
35   f_3   304.36549949645996
36   f_236   296.86313819885254
37   f_88   293.7746386528015
38   f_98   293.4027318954468
39   f_211   292.91850185394287
40   f_173   290.4363031387329
41   f_118   288.6689987182617
42   shift4   286.52710247039795
43   f_11   285.552517414093
44   f_216   280.37355041503906
45   f_77   278.5998010635376
46   f_286   278.07490158081055
47   f_136   277.36910247802734
48   f_83   275.51147651672363
49   f_184   273.55800914764404
50   f_257   272.6539011001587

// ... 略
```


特徴量重要度を見てわかるように、num_investmentに基づいて作った特徴量がたしかに効いていることが分かると思います。





<br>


# 最後に

株式会社音圧爆上げくんではプロKagglerを募集しています。
ご興味のある方はぜひ以下のリンクをご覧ください。
[Wantedlyリンク](https://www.wantedly.com/projects/748285)