Pseudo Labeling(擬似ラベリング)を使ってみる

Kaggle Instant Gratificationで使われていた Pseudo Labeling(擬似ラベリング)について紹介します。参考: Pseudo Labeling - QDA - [0.969]

Pseudo Labeling(擬似ラベリング)とは?

Pseudo Labelingとは、ラベルのついたデータ(trainデータ)で学習したモデルを利用して、未ラベルのデータ(testデータ)を推論した結果のうち、確度の高いものをラベル付きのデータとして追加して再度モデルを学習させるプロセスを指します。

今回のコンペでは40の特徴量に対して、512行のデータセットを使ってモデルを学習させる必要があり明らかにデータ数が足りないため、擬似ラベリングを行い学習データを増やすことでスコアを伸ばすことができました。

実際のコード

データは こちら から。

ラベルのついたデータ(trainデータ)でモデルを学習

import numpy as np
import pandas as pd
import os
from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis
from sklearn.model_selection import StratifiedKFold
from sklearn.feature_selection import VarianceThreshold
from sklearn.metrics import roc_auc_score

train = pd.read_csv('../input/train.csv')
test = pd.read_csv('../input/test.csv')

cols = [c for c in train.columns if c not in ['id', 'target', 'wheezy-copper-turtle-magic']]
oof = np.zeros(len(train))
preds = np.zeros(len(test))

for i in range(512):

    train2 = train[train['wheezy-copper-turtle-magic']==i]
    test2 = test[test['wheezy-copper-turtle-magic']==i]
    idx1 = train2.index
    idx2 = test2.index
    train2.reset_index(drop=True, inplace=True)
    
    sel = VarianceThreshold(threshold=1.5).fit(train2[cols])
    train3 = sel.transform(train2[cols])
    test3 = sel.transform(test2[cols])
    
    skf = StratifiedKFold(n_splits=11, random_state=42, shuffle=True)
    for train_index, test_index in skf.split(train3, train2['target']):
        
        clf = QuadraticDiscriminantAnalysis(reg_param=0.5)
        clf.fit(train3[train_index,:],train2.loc[train_index]['target'])
        oof[idx1[test_index]] = clf.predict_proba(train3[test_index,:])[:,1]
        preds[idx2] += clf.predict_proba(test3)[:,1] / skf.n_splits
       
print('QDA scores CV =',round(roc_auc_score(train['target'], oof) ,5))
QDA scores CV = 0.96532

未ラベルのデータ(testデータ)を推論した結果を擬似ラベルとして追加

test['target'] = preds

擬似ラベルのうち、予測確度の高いものを学習データに追加してモデルを学習

oof = np.zeros(len(train))
preds = np.zeros(len(test))

for k in range(512):

    train2 = train[train['wheezy-copper-turtle-magic']==k] 
    train2p = train2.copy()
    idx1 = train2.index 
    test2 = test[test['wheezy-copper-turtle-magic']==k]
    
    # 擬似ラベルのうち、予測確度の高いものを学習データに追加する
    test2p = test2[ (test2['target']<=0.01) | (test2['target']>=0.99) ].copy()
    test2p.loc[ test2p['target']>=0.5, 'target' ] = 1
    test2p.loc[ test2p['target']<0.5, 'target' ] = 0 
    train2p = pd.concat([train2p,test2p],axis=0)
    train2p.reset_index(drop=True,inplace=True)
    
    sel = VarianceThreshold(threshold=1.5).fit(train2p[cols])     
    train3p = sel.transform(train2p[cols])
    train3 = sel.transform(train2[cols])
    test3 = sel.transform(test2[cols])
        
    skf = StratifiedKFold(n_splits=11, random_state=42, shuffle=True)
    for train_index, test_index in skf.split(train3p, train2p['target']):
        test_index3 = test_index[ test_index<len(train3) ]
        
        clf = QuadraticDiscriminantAnalysis(reg_param=0.5)
        clf.fit(train3p[train_index,:],train2p.loc[train_index]['target'])
        oof[idx1[test_index3]] = clf.predict_proba(train3[test_index3,:])[:,1]
        preds[test2.index] += clf.predict_proba(test3)[:,1] / skf.n_splits
              
print('Pseudo Labeled QDA scores CV =',round(roc_auc_score(train['target'], oof) ,5))
Pseudo Labeled QDA scores CV = 0.96769

CVスコアがわずかながら上がっていることが確認できました。