一般のKaggleコンペやったら意外と上手く行った話

先日Kaggleでタイタニック以外にテーブルデータのコンペは無いものかと思って探してメダルを取りたいと思っていたのですが(のちにメダルの無いコンペと発覚)、面白いコンペがありました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/cbe4b8d1-7c1a-88e7-19c6-4af49f6db5e9.png)
多分血糖値を予想するのかなと思ったんですが、このコンペ、癖が強い。

# テーブル
## 訓練データ
まず訓練データとテストデータで変数が合っているのかわからない
```Python3
import pandas as pd
train = pd.read_csv("train.csv")
train
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/94bb0d95-1c05-4b1f-fd47-4e0007d0f91f.png)
NaNが多すぎる。
## テストデータ
```Python3
test = pd.read_csv("test.csv")
test
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/599fc34a-d16a-e442-fe51-b9413b8e4aee.png)
# 変数を合わせる
念のため変数を合わせました。
```Python3
columns = []
for col in train.columns:
    if col in test.columns:
        columns.append(col)
train = train[columns]
for col in x_test.columns:
    if col not in x_train.columns:
        x_test = x_test.drop(col, axis=1)
```
# 欠損値の補完
このデータはあまりにも欠損が多くしかも数値なので埋めようがありません。そのため欠損値を欠損値として使います。
LightGBMを使うことを前提にします。
```Python3
train = train.fillna(-9999)
test = test.fillna(-9999)
```
基本的に各変数は0以上なのでこれで問題ないでしょう。

# IDを作る
```Python3
train.index = train["id"]
train = train.drop("id", axis=1)
train
```

# ページを変数に
```Python3
train["p_num"] = train["p_num"].map(lambda x:x.split("p")[1])
train["p_num"] = train["p_num"].astype("float")
train
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/5b6d16b7-9af0-8a4c-4e2a-f2ec0c06c81c.png)

ページがfloatになりました。同じことをテストデータでもやります。

# 時間を変数に
時間にも特徴量があると仮定して時間を特徴量化しました。
```Python3
train["time"] = pd.to_datetime(train["time"])
train["H"] = train["time"].dt.hour
train["M"] = train["time"].dt.minute
train["S"] = train["time"].dt.second
train = train.drop("time", axis=1)
train
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/ea84f5d2-663a-bb68-61a3-347174e1e691.png)
これで時間を特徴量にすることができました。テストデータにも同様の処理をしました。

# 目的変数(訓練データ)を結合
変数合わせで目的変数がなくなってしまったので結合します。
```Python3
df_train = pd.read_csv("train.csv")
df_train.index = df_train["id"]
df_train = df_train.drop("id", axis=1)
train2 = pd.concat([df_train["bg+1:00"], train], axis=1)
```
これで結合ができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/d85a4c73-7144-e53e-35b1-ea41d8933dd7.png)

# 学習
ではここからようやくデータを学習させましょう。
```Python3
from lightgbm import LGBMRegressor as LGBMR

x_train = train2.drop("bg+1:00", axis=1)
y_train = train2["bg+1:00"]
x_test = test
```
このデータ、よく見ると質的変数があるためダミー変数化します。
```Python3
x_train = pd.get_dummies(x_train)
x_test = pd.get_dummies(x_test)
```
次に変数の順番を念のため合わせます。

```Python3
x_train = x_train.sort_index(axis=1)
x_test = x_test.sort_index(axis=1)
```
そしてこのまま学習させるとエラーを起こしたので時間変数(だと思う)に変数をいじりました。
```Python3
import re
x_train = x_train.rename(columns = lambda x:re.sub('[^A-Za-z0-9_]+', '', x))
x_test = x_test.rename(columns = lambda x:re.sub('[^A-Za-z0-9_]+', '', x))
```
いよいよようやく学習です
```Python3
model = LGBMR()
model.fit(x_train, y_train)
y_pred = model.predict(x_test)
```
提出用データを作ります。
```Python3
pred = pd.DataFrame(y_pred)
pred.index = x_test.index
pred.columns = ["bg+1:00"]
pred.sort_index().to_csv("submit_1.csv")
```

# 精度と順位
精度の測定はRMSEだそうてす。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/8725a49f-f45f-4586-38ff-09a8b1df7dc6.png)
ついで順位を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/5ec56952-fead-8ca9-e001-903dde278d60.png)

なんと自分の下にMasterとGrandMasterがいました。
10月2日時点では101人中30位とまずまずな結果になりました。データサイエンス初心者にしては中々いい結果なのではないでしょうか。