1. はじめに
機械学習を活用してビジネスの課題を解決することは、多くの企業にとって重要な戦略となっています。本記事では、Databricks を使用して、顧客の離反(Churn)予測モデルを構築する方法を解説します。ロジスティック回帰モデルを用いて予測を行い、その過程で発生したエラーとその解決方法についても詳しく説明します。
2. データの準備
まず、Databricks環境にデータを読み込みます。ここでは、顧客の属性や利用履歴に関するデータセットを使用します。
# 必要なライブラリをインポート
from pyspark.sql import SparkSession
from pyspark.ml.feature import StringIndexer, OneHotEncoder, VectorAssembler, StandardScaler
from pyspark.ml.classification import LogisticRegression
from pyspark.ml import Pipeline
import pandas as pd
import matplotlib.pyplot as plt
# データの読み込み
data = spark.read.csv("dbfs:/FileStore/path/to/your/customer_data.csv", header=True, inferSchema=True)
# データの確認
data.show(5)
注意点:
- データパス
"dbfs:/FileStore/path/to/your/customer_data.csv"
は、実際のデータファイルのパスに置き換えてください。 - データセットには以下のようなカラムが含まれていると仮定します。
- 数値特徴量:
monthly_charges
,total_charges
,tenure
- カテゴリ特徴量:
contract_type
,payment_method
- 目的変数:
churn
(1:離反、0:継続)
- 数値特徴量:
3. データの前処理
モデルを構築する前に、データの前処理を行います。カテゴリ変数のエンコーディングや特徴量のベクトル化、標準化を行います。
3.1 カテゴリ変数のエンコーディング
# カテゴリ特徴量と数値特徴量のカラム名
categorical_cols = ['contract_type', 'payment_method']
numerical_cols = ['monthly_charges', 'total_charges', 'tenure']
label_col = 'churn'
StringIndexerとOneHotEncoderの設定
# StringIndexerの設定とフィット
indexer_models = []
for col in categorical_cols:
indexer = StringIndexer(inputCol=col, outputCol=col+"_indexed", handleInvalid='keep')
model = indexer.fit(data)
indexer_models.append(model)
data = model.transform(data)
# カテゴリ数の取得
category_sizes = {}
for idx, col in enumerate(categorical_cols):
labels = indexer_models[idx].labels
category_count = len(labels)
if indexer_models[idx]._java_obj.getHandleInvalid() == "keep":
category_count += 1 # 未知のカテゴリを考慮
category_sizes[col+"_indexed"] = category_count
# OneHotEncoderの設定とフィット
encoded_input_cols = [col+"_indexed" for col in categorical_cols]
encoded_output_cols = [col+"_encoded" for col in categorical_cols]
encoder = OneHotEncoder(inputCols=encoded_input_cols, outputCols=encoded_output_cols, dropLast=False)
encoder_model = encoder.fit(data)
data = encoder_model.transform(data)
3.2 特徴量のベクトル化と標準化
# エンコード後のカテゴリ特徴量名の作成
feature_names = numerical_cols.copy()
for idx, col in enumerate(categorical_cols):
num_categories = category_sizes[col+"_indexed"]
for i in range(num_categories):
feature_names.append(f"{col}_encoded_{i}")
# 特徴量のベクトル化
assembler = VectorAssembler(inputCols=numerical_cols + encoded_output_cols, outputCol="unscaled_features")
data = assembler.transform(data)
# 特徴量の標準化
scaler = StandardScaler(inputCol="unscaled_features", outputCol="features", withMean=True, withStd=True)
scaler_model = scaler.fit(data)
data = scaler_model.transform(data)
4. モデルの構築と評価
4.1 ロジスティック回帰モデルの訓練
# データの分割
train_data, test_data = data.randomSplit([0.7, 0.3], seed=42)
# ロジスティック回帰モデルの作成と訓練
lr = LogisticRegression(featuresCol='features', labelCol=label_col, maxIter=10)
lr_model = lr.fit(train_data)
4.2 エラーの発生と原因
モデルの係数と特徴量名を結合して、特徴量の重要度を解析しようとしましたが、以下のエラーが発生しました。
# モデルの係数を取得
coefficients_array = lr_model.coefficients.toArray()
# 特徴量名と係数を結合
coefficients_df = pd.DataFrame({
'Feature': feature_names,
'Coefficient': coefficients_array
})
エラーメッセージ:
ValueError: All arrays must be of the same length
原因の分析:
feature_names
の長さと**coefficients_array
の長さ**が一致していないため、DataFrameの作成時にエラーが発生しています。- これは、
StringIndexer
のhandleInvalid='keep'
の設定により、未知のカテゴリが追加され、カテゴリ数が増加したためです。
4.3 エラーの解決方法
解決策:
- カテゴリ数を正確に把握し、特徴量名のリストを正しく構築する必要があります。
StringIndexerModel
のlabels
属性から正確なカテゴリ数を取得し、handleInvalid='keep'
による追加カテゴリも考慮します。
修正後のコード:
# カテゴリ数の取得(修正版)
category_sizes = {}
for idx, col in enumerate(categorical_cols):
labels = indexer_models[idx].labels
category_count = len(labels)
if indexer_models[idx]._java_obj.getHandleInvalid() == "keep":
category_count += 1 # 未知のカテゴリを考慮
category_sizes[col+"_indexed"] = category_count
# エンコード後のカテゴリ特徴量名の作成(修正版)
feature_names = numerical_cols.copy()
for col in categorical_cols:
num_categories = category_sizes[col+"_indexed"]
for i in range(num_categories):
feature_names.append(f"{col}_encoded_{i}")
特徴量名と係数の長さの確認:
print(f"Number of features: {len(feature_names)}")
print(f"Number of coefficients: {len(coefficients_array)}")
これにより、両者の長さが一致することを確認できます。
4.4 モデルの再訓練と評価
# 係数の絶対値を計算し、影響度でソート
coefficients_df['AbsCoefficient'] = coefficients_df['Coefficient'].abs()
coefficients_df = coefficients_df.sort_values(by='AbsCoefficient', ascending=False).reset_index(drop=True)
# 結果の表示
coefficients_df
5. 特徴量の重要度の解析
# 特徴量の重要度を可視化
%matplotlib inline
plt.figure(figsize=(10, max(6, int(len(coefficients_df)/2))))
plt.barh(coefficients_df['Feature'], coefficients_df['Coefficient'])
plt.xlabel('Coefficient Value')
plt.title('Feature Importance based on Coefficients')
plt.gca().invert_yaxis()
plt.show()
解釈のポイント:
- 正の係数: 特徴量が増加すると、顧客が離反する可能性が高くなる。
- 負の係数: 特徴量が増加すると、顧客が継続する可能性が高くなる。
6. まとめ
本記事では、Databricksを使用して顧客離反予測モデルを構築する過程で発生したエラーとその解決方法について解説しました。カテゴリ変数のエンコーディング時に生じる特徴量名と係数の不一致問題を解決することで、モデルの解釈性を高めることができました。
7. 追加のポイントと注意事項
- データの品質確認: 欠損値や異常値が存在する場合、モデルの性能に影響を与えるため、適切な対処が必要です。
- モデルの改善:
- ハイパーパラメータの調整や交差検証の実施により、モデルの性能を向上させることができます。
- 他のアルゴリズム(例: ランダムフォレスト、勾配ブースティング)を試すことも有効です。
- 特徴量エンジニアリング: 新たな特徴量の作成や不要な特徴量の削除により、モデルの精度を向上させることができます。
- ビジネスへの応用: モデルの結果をビジネス上の意思決定に活用し、顧客離反の予防策を立案することが重要です。
関連リンク:
コメント