見出し画像

【SIGNATE】携帯電話の機能データからの価格帯分類

こんにちは!5月の「SIGNATEビギナーズコンペ」に参加しました!内容は携帯電話の機能データからの価格帯分類でした。公開できない情報があるので、全部の報告はできませんが、一部について報告します。

今回は、携帯電話の価格帯を(安い)0 , 1, 2, 3(高い)に分類する分類問題です。その予測モデルを作成し、未知のデータを分類して、事務局が持っている正解データと比較して、数値を比較します。

ちなみに閾値は、F1macro=0.462885であり、この敷地を超えれば、Intermediateの称号を手に入れることができます。私はギリギリ手に入れられましたwww

特徴量エンジニアリング

数値の正規化

まずは、数値の正規化を行いました。

from sklearn.preprocessing import StandardScaler

# Create a StandardScaler instance
scaler = StandardScaler()

# List of columns that you want to scale
scale_columns = ["battery_power", "ram", "int_memory", "mobile_wt"]

# Fit the scaler to the columns of the dataframe and transform
train_df[scale_columns] = scaler.fit_transform(train_df[scale_columns])

display(train_df)

正規化とは、各特徴量の平均を0、標準偏差を1にするように値を変換することで、異なる尺度で測定されたデータを比較可能にします。
上記カラムの数値の尺度が、バラバラになっていたため、このような処理を行いました。

特徴量の重要度の可視化

ここでは次のようなコードを書きました。

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import f1_score
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

# 目的変数と説明変数の定義
y = train_df['price_range']
X = train_df.drop('price_range', axis=1)

# データの分割
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=0)

# ランダムフォレスト分類器のインスタンス化
clf = RandomForestClassifier(random_state=4)

# モデルの訓練
clf.fit(X_train, y_train)

# 検証データでの予測
y_pred_val = clf.predict(X_val)

# F1スコアの計算
f1 = f1_score(y_val, y_pred_val, average='macro')
print("F1 Score: ", f1)

# 特徴量の重要度を取得
importances = clf.feature_importances_

# 特徴量の名前と重要度を結びつける
features = pd.DataFrame({'Feature': X_train.columns, 'Importance': importances})

# 重要度の高い順にソート
features.sort_values(by='Importance', ascending=False, inplace=True)

# 重要度の表示
print(features)

# 重要度の可視化
plt.figure(figsize=(10,8))
plt.title('Feature Importances')
plt.barh(range(len(features)), features['Importance'], color='b', align='center')
plt.yticks(range(len(features)), features['Feature'])
plt.xlabel('Relative Importance')
plt.show()

このコードにより、ランダムフォレストの機械学習の際に、重要度の高い特徴量(カラム)と重要度が低い特徴量(カラム)を算出することができます。
ちなみに今回は未知のテストデータの価格帯("prince_range")を予測するので、訓練データをtrain_test_splitで訓練とテストに分けて、予測モデルを作成してます。

こんな感じになりました。そんなに重要度が高いものはありませんが
"wifi", "touch_screen", "blue", "dual_sim"などは影響力が低いことが伺えます。重要度の低い特徴量は消してしまってもよさそうです。

逆効果な特徴量エンジニアリング

さて、今回やってみて、逆効果たっだ特徴量エンジニアリングですが
携帯電話の高さと幅と深さを掛けて、体積にしたり面積にしたりしてまとめると、めちゃくちゃ逆効果でしたw
また、スクリーンの大きさも面積にして、検討を行いましたが
全くと言っていいほど、スコアを上げることができませんでした。
理由はわかりませんが。。。。。

予測モデル

使用した予測モデルは、ランダムフォレストのハイパーパラメーターチューニングを行ったものです。以下のコードです。

from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import f1_score
from sklearn.model_selection import train_test_split

# 目的変数と説明変数の定義
y = train_df['price_range']
X = train_df.drop('price_range', axis=1)

# データの分割
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=0)

# ランダムフォレスト分類器のインスタンス化
clf = RandomForestClassifier(random_state=3)

# ハイパーパラメータの候補
param_grid = {
    'n_estimators': [100, 200, 300, 400, 500],
    'max_depth': [None, 5, 10, 20, 50, 100]
}

# グリッドサーチの設定
grid_search = GridSearchCV(clf, param_grid, cv=5, scoring='f1_macro')

# モデルの訓練とハイパーパラメータのチューニング
grid_search.fit(X_train, y_train)

# 最適なパラメータの表示
print("Best Parameters: ", grid_search.best_params_)

# 最適なパラメータを用いたモデルの訓練
clf_best = RandomForestClassifier(**grid_search.best_params_, random_state=0)
clf_best.fit(X_train, y_train)

# 検証データでの予測
y_pred_val = clf_best.predict(X_val)

# F1スコアの計算
f1 = f1_score(y_val, y_pred_val, average='macro')
print("F1 Score: ", f1)

このコードで、訓練データの中のテストデータのF1スコアは0.52を超えました。
しかし、多少過学習気味なのか、実際のテストデータのスコアは0.463台でした。。。

何とか閾値を超えたので、良しとしましょうw

ちなみに上記コードのrandom_stateの数値を変えると、多少結果が変わりますので、惜しいスコアを出した場合、微調整できます。

いかがでしたでしょうか。
私はビギナーでしたので、今回はビギナーズ限定コンペにさんかしましたが
今後は、ハイレベルなコンペにも挑戦していきます。

同じようにデータサイエンスに挑戦している人のお役に立てれば光栄です^^

これからもよろしくです!


この記事が気に入ったらサポートをしてみませんか?