[Ubiquant Market Prediction]ユニバースに加わった銘柄の特性について

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

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


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



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







<br>
<br>

# はじめに

EDAをしているとtime_idごとにinvestment_idの数が異なることがわかります。

与えられるデータはどのように決まっているのでしょうか。

推測でしかありませんが、投資対象は実際の運用を想定して一定のルールのもとに決められているのではないかと考えられます。（すなわち、ホスト側が意図的に与えられる銘柄数を絞ったり増やしたりはしていないということです。）

なぜ銘柄数がtime_idによって異なるのかは色々な理由が考えられます。売買の停止や再開があるから、IPOがあるから、流動性が高まって投資ユニバースに加わったから、など。

今回は、このようなinvestment_idのtime_idごとの数の違いに着目します。

具体的には、新しく加わったinvestment_idについて分析し、何らかの特徴がないかを調べようと思います。




# 実装

まずはデータを読み込んでDataFrameにします。その後、省メモリ化します。

```
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/ubiquant-parquet/train_low_mem.parquet')

def reduce_mem_usage(df):
  
    start_mem = df.memory_usage().sum() / 1024**2
    print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))
    
    for col in df.columns:
        col_type = df[col].dtype
        
        if col_type != object:
            c_min = df[col].min()
            c_max = df[col].max()
            if str(col_type)[:3] == 'int':
                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
                    df[col] = df[col].astype(np.int8)
                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
                    df[col] = df[col].astype(np.int16)
                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
                    df[col] = df[col].astype(np.int32)
                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
                    df[col] = df[col].astype(np.int64)  
            else:
                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
                    df[col] = df[col].astype(np.float16)
                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
                    df[col] = df[col].astype(np.float32)
                else:
                    df[col] = df[col].astype(np.float64)
        else:
            df[col] = df[col].astype('category')

    end_mem = df.memory_usage().sum() / 1024**2
    
    print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
    print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))
     
    return df

df = reduce_mem_usage(df)
```
<br>
<br>
新しく登場したinvestment_idにフラグを立てます。具体的には、df.at[i, 'new'] = 1　とし、それ以外は0としています。

```
df['new'] = 0

inv_list = []

for i in range(0, len(df)):
    inv_id = df.at[i, 'investment_id']

    if inv_id in inv_list:
        pass

    else:
        inv_list.append(inv_id)

        if i > 2272:
            df.at[i, 'new'] = 1
```

<br>
<br>
新規出現銘柄だけのDataFrameを作成し、targetの平均を算出します。

```
df_new = df[df['new'] == 1]
df_new['target'].mean()
```
<br>
<br>

**結果**

```
-0.3015
```

これが新規に出現した銘柄のtargetの平均です。investment_id全体の平均は-0.021なのでかなり異なることがわかります。

次に、新規出現investment_idと全てのinvestment_idのtargetのヒストグラムを作ります。

```
df_new['target'].hist(bins = 100, figsize = (20,10))
```

<br>

**新規出現**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2465043/1ede9ef8-ff4c-906c-700e-ec428a9608af.png)


**全体**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2465043/a9903331-4d7c-cbec-7727-cb1283569d85.png)


比較して見てみると、かなり異なる分布をしていることがわかります。



<br>
次に、どのtime_idで新たなinvestment_idがどれだけ出現したかをカウントし可視化します。

```
#the number of newly apperaing investment_ids
from matplotlib import pyplot as plt
import pandas as pd
import matplotlib.pyplot as plt



num_investment = df_new.groupby('time_id').count()



time_id = num_investment.index
num = num_investment['investment_id']
plt.plot(time_id, num)
plt.show()

```

**結果**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2465043/855faba1-7ffa-b909-0784-83c929740e07.png)


<br>
比較用として、各time_idごとのinvestment_idの数をカウントしたものをグラフにしたものを表示します。

```
#the number of all apperaing investment_ids
from matplotlib import pyplot as plt
import pandas as pd
import matplotlib.pyplot as plt



num_investment = df.groupby('time_id').count()



time_id = num_investment.index
num = num_investment['investment_id']
plt.plot(time_id, num)
plt.show()
```

**結果**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2465043/9c844db6-0a43-fe74-ed70-44645d9e23ff.png)


一部、新規出現が集中しているtime_idはあるものの、明確な特徴は読み取れないことがわかります。

分析は以上です。
スコア向上の何らかの参考になれば幸いです。

<br>

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