タイタニックのデータを使って xfeat で特徴量作成 + lightGBM で学習をしてみた
(9/23 修正)制度評価指標をf1値に、lightGBMの学習モデルをLGBMClassifier()に修正
特徴量エンジニアリングのライブラリ xfeat が公開されていたのでチュートリアルを参考にkaggleのタイタニックのデータを使って特徴量を作り、lightGBMを回してみました。
【リリース】特徴量エンジニアリングのライブラリ xfeat を公開しました。データフレームから特徴量を作成するための各種エンコーダーを実装しています。cuDF を使うことでエンコーダーによっては 10~30 倍の高速化が可能となります。Code: https://t.co/IbqRET9YA2 Slides: https://t.co/8CY0IdCuJM pic.twitter.com/xM5HxRMQtj
— PFN-tech account (@preferred_jp) June 19, 2020
使用するkaggleのタイタニックのデータはこちらからダウンロードしてください。
なお、xfeat ライブラリは、git をインストールしたうえで、下記コマンドをターミナルに入力すればインストールできます。
pip install git+https://github.com/pfnet-research/xfeat.git
なお、ブログで使ったコードはこちらになります。
では内容を見てみましょう。
import pandas as pd import numpy as np import os from IPython.display import display import xfeat # xfeatのチュートリアルで紹介されているラベルエンコーダー from xfeat import SelectCategorical, LabelEncoder, Pipeline, ConcatCombination, SelectNumerical, ArithmeticCombinations, LambdaEncoder # ホールドアウト法 from sklearn.model_selection import train_test_split # lightGBM import lightgbm as lgb # 二乗平均平方根誤差 (RMSE) from sklearn.metrics import mean_squared_error
csvを読み込んでfeather形式に変換します。
feather形式は、C++で実装されており、読み込みが非常に高速とのことです。
pandasのデータフレームに対してdf.to_feather(filepath)とすることによってFeather形式でのシリアライズが可能。
path = os.getcwd() + "/" d_name = ["train", "test"] # feather形式に変換。 for i in d_name: xfeat.utils.compress_df(pd.read_csv(path + i + ".csv")).to_feather(path + i + ".ftr") # feather形式のデータを読込 dtrain = pd.read_feather("./train.ftr") dtest = pd.read_feather("./test.ftr") display(dtrain.head(3)) display(dtrain.tail(3)) display(dtrain.dtypes) display(dtest.head(3)) display(dtest.tail(3)) display(dtest.dtypes)
xfeat のラベルエンコーディング
特にカラムを指定しなくても、カテゴリカルデータ(object)なのか、数値データ(int、float等)なのかを勝手に認識してラベルエンコーディング可能なのは便利ですね。
# SelectCategorical() カテゴリカルデータ(object)のみをラベルエンコーディング # 除外するカラムをexclude_colsに指定 encoder1 = Pipeline([ SelectCategorical(exclude_cols=["Name"]), LabelEncoder(output_suffix=""), ]) display(encoder1.fit_transform(dtrain).head()) display(encoder1.fit_transform(dtest).head())
カテゴリカルデータのみのラベルエンコーディングと、複数のカテゴリカルデータを組み合わせてラベルエンコーディングを合わせて実行
# SelectCategorical() カテゴリカルデータ(object)のみをラベルエンコーディング # ConcatCombination() 複数のカテゴリカルデータを組み合わせてラベルエンコーディング # r=2 は結合するカラムの数 encoder2 = Pipeline([ SelectCategorical(exclude_cols=["Name"]), ConcatCombination(drop_origin=True, output_suffix="", r=2), LabelEncoder(output_suffix=""), ]) display(encoder2.fit_transform(dtrain).head()) display(encoder2.fit_transform(dtest).head())
4つの項目から2つを選ぶ組み合わせ 4C2 = 6 6通りが出力される
数値データのみのラベルエンコーディング
# SelectNumerical() 数値データのみをラベルエンコーディング # train.csv のみに含まれる目的変数 Survived は数値データなので、SelectNumerical() の対象となる # train.csv はSurvivedカラムを含み、test.csvは Survivedを含まないので、SelectNumericalのexclude_cols(除外するカラム)でSurvivedを指定したい場合は、 # train.csvとtest.csvそれぞれ分けてラベルエンコーディングする必要がある encoder3_1 = Pipeline([ # 除外するカラムをexclude_colsに指定 SelectNumerical(exclude_cols=["PassengerId", "Survived"]), LabelEncoder(output_suffix=""), ]) display(encoder3_1.fit_transform(dtrain).head()) encoder3_2 = Pipeline([ SelectNumerical(exclude_cols=["PassengerId"]), LabelEncoder(output_suffix=""), ]) display(encoder3_2.fit_transform(dtest).head())
数値データのみのラベルエンコーディングと、複数の数値データを加算して新しい項目を作る処理を合わせて実行
# SelectNumerical() 数値データのみをラベルエンコーディング # ArithmeticCombinations() 複数の数値データを加算して新しい項目を作る # encode3_x と同様にtrain.csv と test.csv で分ける encoder4_1 = Pipeline([ SelectNumerical(exclude_cols=["PassengerId", "Survived"]), ArithmeticCombinations( drop_origin=True, operator="+", r=2, output_suffix="", ), ]) display(encoder4_1.fit_transform(dtrain).head()) encoder4_2 = Pipeline([ SelectNumerical(exclude_cols=["PassengerId"]), ArithmeticCombinations( drop_origin=True, operator="+", r=2, output_suffix="", ), ]) display(encoder4_2.fit_transform(dtest).head())
本ブログでは省略しますが、lambdaを使った処理を組み合わせたり、処理をpickleデータに保存する方法もチュートリアルでは紹介されています。
では、学習データとして使用するデータをチョイスします。
# SelectCategorical dtrain_en1 = encoder1.fit_transform(dtrain) dtest_en1 = encoder1.fit_transform(dtest) display(dtrain_en1.head()) display(dtest_en1.head()) # SelectCategorical + ConcatCombination dtrain_en2 = encoder2.fit_transform(dtrain) dtest_en2 = encoder2.fit_transform(dtest) display(dtrain_en2.head()) display(dtest_en2.head()) # SelectNumerical dtrain_en3_1 = encoder3_1.fit_transform(dtrain) dtest_en3_2 = encoder3_2.fit_transform(dtest) display(dtrain_en3_1.head()) display(dtest_en3_2.head()) # SelectNumerical + ArithmeticCombinations dtrain_en4_1 = encoder4_1.fit_transform(dtrain) dtest_en4_2 = encoder4_2.fit_transform(dtest) display(dtrain_en4_1.head()) display(dtest_en4_2.head())
選択したデータをtrainデータ、testデータにそれぞれマージします。
# データ結合 train = pd.concat([dtrain_en1, dtrain_en2], axis=1) train = pd.concat([train, dtrain_en3_1], axis=1) train = pd.concat([train, dtrain_en4_1], axis=1) train = pd.concat([train, dtrain["Survived"]], axis=1) test = pd.concat([dtest_en1, dtest_en2], axis=1) test = pd.concat([test, dtest_en3_2], axis=1) test = pd.concat([test, dtest_en4_2], axis=1) display(train.head()) display(train.shape) display(test.head()) display(test.shape)
学習のための特徴量、およびパラメーターを設定します。
# 特徴量とするカラムのリスト features = [ "Sex", "Ticket", "Cabin", "Embarked", "SexTicket", "SexCabin", "SexEmbarked", "TicketCabin", "TicketEmbarked", "CabinEmbarked", "PclassSibSp", "PclassParch", "PclassFare", "AgeSibSp", "AgeParch", "AgeFare", "SibSpParch", "SibSpFare", "ParchFare" ]
lightGBMで学習を行っていきます。
# ホールドアウト法 X_train, X_test, y_train, y_test = train_test_split(train[features], train["Survived"], random_state=42) # 学習モデルの作成 model_lgb = lgb.LGBMClassifier() # モデルのインスタンスの作成 model_lgb.fit(X_train, y_train)
バリデーションデータについて、予測値と実績値を比較して誤差率を算定してみます。
# validationデータで誤差率を算定 val_pred = model_lgb.predict(X_test) val_score = f1_score(y_test, val_pred) print(f'f1 score は {val_score}')
出力:f1 score は 0.7314285714285713
気を取り直してテストデータで予測値を作成します。
pred = model_lgb.predict(test[features]) # gender_submission の Survived カラムを予測値に入れ替える gs["Survived"] = pred display(gs.head()) display(gs.tail())
Survived の値が小数点になってしまっているので、0、1に置き換えます
# 0.6以上の場合は 1、0.6未満の場合は 0 に置換 gs["Survived"].mask(gs["Survived"] >= 0.6, 1, inplace=True) gs["Survived"].mask(gs["Survived"] < 0.6, 0, inplace=True) display(gs.head()) display(gs.tail())
# csvへの出力 gs.to_csv(path + "submission.csv", index=False)
バリデーションデータでの結果は芳しくなかったですが、とりあえずxfeat のラベルエンコーダーを使ってlightGBMの学習ができました。
今回はタイタニックのデータを使った分類ですが、回帰でやるとどうなるか、そのうち試してみようと思います。
以上になります、最後までお読みいただきありがとうございました。
参考サイト