PR

Signate Beginner向けコンペ初参加で8位入賞!スコアアップ方法

AI/MachineLearning

こんにちは、SIGNATE主催の「第46回_Beginner限定コンペ 携帯電話の機能データからの価格帯分類」で最高時3位、最終的に8位に入賞することができました!このブログ記事では、コンペに参加した経緯やスコアアップのプロセス、そして実際に使用したPythonコードを交えながら、私の体験をシェアしたいと思います。

スポンサーリンク

コンペの概要と参加のきっかけ

「第46回_Beginner限定コンペ」は、携帯電話の各種機能・スペックのデータから、その携帯電話の価格帯を予測するという課題のコンペティションです。価格帯は0から3の4クラスに分類されており、与えられた特徴量を用いて分類モデルを構築するのが目的でした。

Kaggleを含め、登録とTitanicだけして、その後本業の業務などが忙しくなり腰を据えてやる時間を取れなかった私ですが、今回少し時間に余裕ができたのとBeginner限定のコンペは学びの機会として最適だと感じ、また実データを使った課題に取り組むことで、実際のコンペの雰囲気をつかんでちょっと本腰でやろうと参加を決めました。

スポンサーリンク

探索的データ分析(EDA)

コンペに参加したら、まずは与えられたデータを探索的に分析(EDA)しました。以下のようなコードを用いて、各特徴量の分布や価格帯との関係性を可視化してみました。

import seaborn as sns
import matplotlib.pyplot as plt

def plot_matrix(data):
    columns = data.columns[:-1]
    num_columns = len(columns)

    num_rows = (num_columns + 1) // 2
    num_cols = 2

    fig, axes = plt.subplots(num_rows, num_cols, figsize=(12, 4 * num_rows))

    for i, column in enumerate(columns):
        row = i // num_cols
        col = i % num_cols

        sns.histplot(data=data, x=column, ax=axes[row, col], hue="price_range", multiple="stack", bins=10, legend=False)

        axes[row, col].set_title(f'Distribution of {column}')
        axes[row, col].set_xlabel(column)
        axes[row, col].set_ylabel('Count')

    handles, labels = axes[0, 0].get_legend_handles_labels()
    fig.legend(handles, labels, title='Price Range', loc='upper right')

    if num_columns % 2 != 0:
        fig.delaxes(axes[-1, -1])

    plt.tight_layout()
    plt.show()

この可視化により、いくつかの特徴量で価格帯ごとに分布の違いが見られることがわかりました。この知見は特徴量の選択や前処理の方針を決める上で役立ちました。

スポンサーリンク

データの前処理

EDAの結果を踏まえ、データの前処理を行いました。具体的には以下の2つの処理を実施しました。

  1. px_heightをsc_hで、px_widthをsc_wで割った新たな変数を作成し、元の変数を削除
  2. 0-1の範囲に収まらない変数について、最小値0、最大値1に正規化

これらの処理を以下の関数で実装しました。

from scipy.stats import norm

def data_cleansing(dataFrame):
    data = dataFrame.copy()
    data['sc_w'] = data['sc_w'].replace(0, 1)

    data['pxsc_h'] = data['px_height'] / data['sc_h'] * 10
    data['pxsc_w'] = data['px_width'] / data['sc_w'] * 10
    data = data.drop(['px_height', 'px_width', 'sc_h', 'sc_w'], axis=1)

    for column in data.columns:
        data[column] = (data[column] - data[column].min()) / (data[column].max() - data[column].min())

    return data

前処理の効果を確認するため、再度可視化を行ったところ、各特徴量の分布がより扱いやすい形に整えられていることが確認できました。

スポンサーリンク

モデルの選択とハイパーパラメータ調整

前処理したデータを用いて、複数の機械学習モデルを試してみることにしました。今回は以下の5つのモデルを候補に選びました。

  1. ランダムフォレスト
  2. ロジスティック回帰
  3. サポートベクターマシン(SVM)
  4. ニューラルネットワーク(多層パーセプトロン)
  5. XGBoost

各モデルのハイパーパラメータ調整には、Optunaというハイパーパラメータ自動最適化ツールを使用しました。例えば、ランダムフォレストの場合は以下のようなコードでハイパーパラメータ探索を行いました。

import optuna

def objective_rf(trial):
    params = {
        'n_estimators': trial.suggest_int('n_estimators', 50, 500),
        'max_depth': trial.suggest_int('max_depth', 2, 20),
        'min_samples_split': trial.suggest_int('min_samples_split', 2, 10),
        'min_samples_leaf': trial.suggest_int('min_samples_leaf', 1, 10),
    }
    model = RandomForestClassifier(**params, random_state=42)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    return accuracy

study_rf = optuna.create_study(direction='maximize')
study_rf.optimize(objective_rf, n_trials=100)
print("Best hyperparameters for Random Forest:", study_rf.best_params)
print("Best accuracy for Random Forest:", study_rf.best_value)

他のモデルについても同様にハイパーパラメータ探索を行い、各モデルの最適パラメータを求めました。

スポンサーリンク

モデルの評価と改善

ハイパーパラメータ調整後、各モデルの性能を評価しました。評価指標には、accuracy(正解率)とclassification report(適合率、再現率、F1スコア)を用いました。

評価の結果、ランダムフォレストとXGBoostが特に高い性能を示しました。一方で、SVMはカーネルの種類によって大きく性能が変動し、調整が難しいことがわかりました。

そこで、ランダムフォレストとXGBoostをさらに改善することに注力しました。具体的には、特徴量の重要度を確認し、重要度の低い特徴量を削除することで、モデルの汎化性能を高める工夫をしました。

スポンサーリンク

アンサンブル学習による最終提出

各モデルを改善した後、アンサンブル学習によって最終的な予測を行いました。具体的には、ランダムフォレスト、ロジスティック回帰、SVM、ニューラルネットワーク、XGBoostの予測結果を組み合わせ、多数決や平均化によって最終的な予測ラベルを決定しました。

以下は、予測結果を組み合わせるコードの一例です。

import numpy as np
from scipy import stats

def process_array(arr):
result = []
for row in arr:
unique_elements, counts = np.unique(row, return_counts=True)
if len(unique_elements) == 1:
result.append(unique_elements[0])
elif len(unique_elements) == 2:
result.append(unique_elements[np.argmax(counts)])
else:
result.append(row[2])
return np.array(result)

stacked = np.column_stack((rf_valid, lr_valid, svm_valid, nn_valid, xgb_valid))
result = process_array(stacked)

このアンサンブル学習によって、単体のモデルよりも高い性能を達成することができました。

スポンサーリンク

参考にしたおススメのUdemy講座

Signateに参加するにあたり、Udemyの講座を参考にしました。その中で役に立ったなという講座を幾つかご紹介します。

まず一つ目は、【ゼロから始めるデータ分析】 ビジネスケースで学ぶPythonデータサイエンス入門です。こちらは、Pythonでデータ分析を学べる実践的な講座です。ビジネスケースを通じて、データサイエンスの基礎から応用までを身につけられます。これからデータ分析を始める方におすすめの一作です。そしてなんといってもSignateさんが作っている講座です。

二つ目は、26個ものアルゴリズムを理論と実践で学べる【世界で91万人が受講】基礎から理解し、Pythonで実装!機械学習26のアルゴリズムを理論と実践を通じてマスターしようです。Pythonでの実装力が身につき、機械学習エンジニアとしてのスキルアップに最適な内容です。初学者から上級者まで幅広くおすすめ。

三つめは、データ分析と機械学習の基礎をPythonで学ぶ、豊富な演習問題とKaggle実践で身に付ける!『Python データ分析 & 機械学習 ~パーフェクトスターターコース』です。こちらは、コンペサイトのKaggleをテーマに豊富な演習問題とKaggle実践で実力が身につきます。丁寧な解説と充実した内容で、データサイエンティストを目指す方におすすめの一作です。

スポンサーリンク

終わりに

本記事で紹介した探索的データ分析、前処理、モデル選択、ハイパーパラメータ調整、アンサンブル学習といった一連のプロセスを通じて、データ分析コンペで良い成績を収めるためのコツの一端が掴めたのではないかと思います。

もちろん、まだまだ改善の余地は多くあります。しかし、今回の経験を糧に、さらにスキルアップを重ねていきたいと思います。

データ分析や機械学習に興味のある方々にとって、本記事が少しでも参考になれば幸いです。

コメント

タイトルとURLをコピーしました