超入門:PySparkでロジスティック回帰をやってみよう

こんにちは、クラウドデータ研究所です。

今回は「ロジスティック回帰」というものを見てみます。

難しそうな名前ですが、実は身近なところでよく使われている手法です。

データちゃん
たとえば銀行が「この人はローンを返してくれるかな?」を予測したり、マーケティングで「この人は商品を買ってくれるかな?」を確率で予測したり、そういう「Yes/No を予測する」のがロジスティック回帰の得意分野です!

AIや機械学習には大きく分けて「教師あり学習」と「教師なし学習」があります。

  • 教師あり学習 → 正解付きのデータで学ぶ(例:「この人は買った/買わなかった」という履歴がある)
  • 教師なし学習 → 正解がないデータでグループを探す(例:クラスタリングで似た人をまとめる)

今回は「教師あり学習」の代表例であるロジスティック回帰について見ていきましょう。

銀行預金に申し込むかどうか?

それでは、実際に問題を見ていきましょう。

銀行がマーケティング電話をかけて、お客さんが定期預金に申し込むかどうか(target=yes/no)?」という問いに対して、ロジスティック回帰の機械学習を使用して考えていきましょう。

教師あり学習の際に、説明変数として下記の情報を使用していきます。

1. 基本情報(顧客属性)

  • age(年齢):数値。若い人・高齢の人で金融商品の興味に違いがあるか?
  • job(職業):文字データ(例:management, student, unemployed)。社会的立場によって申し込みやすさが違う。
  • marital(婚姻状況):divorced, married, single など。ライフステージが金融行動に影響。
  • education(学歴):basic, high.school, university など。金融リテラシーの proxy(代替指標)。

2. 信用・経済状況

  • default(債務不履行):yes/no。過去に返済延滞があればリスクが高い。
  • balance(平均残高):数値。顧客の経済力の指標。
  • housing(住宅ローンの有無):yes/no。既存のローン有無が預金行動に影響。
  • loan(個人ローンの有無):yes/no。同上。

3. 連絡に関する情報

  • contact(連絡手段):cellular, telephone。携帯電話の方が反応率高いか?
  • day(最後の接触日):1〜31。曜日やタイミングの影響。
  • month(最後の接触月):jan〜dec。年末や夏前など、季節性がある可能性。
  • duration(最後の通話時間・秒数):重要だが注意点あり。
    • 通話が長いほど申し込み率が高い(強い予測因子)。
    • ただし「予測の時点ではわからない未来情報」なので、現実的なモデルからは除外するのが推奨

4. 過去キャンペーン情報

  • campaign(このキャンペーンでの通話回数):数値。しつこく電話すると逆効果か?
  • pdays(前回からの経過日数):数値。999=未接触。
  • previous(過去の接触回数):数値。過去の経験が効果に影響。
  • poutcome(前回キャンペーンの結果):success, failure, nonexistent。過去の反応が予測因子になる。

実際にやっている処理を見ていきましょう!

1. SparkSession(セッションの作成)

作業部屋を用意しよう!

PySparkでは、まず最初に「作業する部屋」を用意します。これが SparkSession です。
すべての処理はこの部屋の中で行われます。

from pyspark.sql import SparkSession
spark = SparkSession.builder.master("local").appName("logistic_regression").getOrCreate()

2. データを読み込む

エクセルの表を読み込む!

CSVファイルを読み込んで、データフレーム(表形式データ)にします。

data = spark.read.csv("./bank-full.csv", header=True, inferSchema=True, sep=";")
  • header=True → 1行目を列名にする
  • inferSchema=True → 数字は数字、文字は文字として自動判別
  • sep=";" → 区切り文字がセミコロン ;

3. StringIndexer(文字を数字に変える)

Yesを1に、Noを0に変える

機械学習は文字のままだと理解できません。
そこで「文字(例:default=’yes’)」を数字(例:1や0)に変換します。

from pyspark.ml.feature import StringIndexer
default_index = StringIndexer(inputCol="default", outputCol="default_index")

4. VectorAssembler(特徴量をまとめる)


年齢、残高、ローンの有無など、たくさんの列を「特徴量」と呼びます。
これを1本の「まとめカラム(features)」に集めるのが VectorAssembler です。

いろんな情報をひとまとめにする!
from pyspark.ml.feature import VectorAssembler
assemble = VectorAssembler(
    inputCols=["age","balance","duration","campaign","previous","default_index"],
    outputCol="features"
)

5. StandardScaler(標準化)

物差しをそろえる

身長が「150cm〜190cm」、年齢が「20〜70歳」など、スケールがバラバラだと計算が偏ってしまいます。
そこで全部を「平均0・標準偏差1」に揃える処理が StandardScaler

from pyspark.ml.feature import StandardScaler
scaler = StandardScaler(inputCol="features", outputCol="scaled_features")

6. LogisticRegression(ロジスティック回帰モデル)

Yes/Noを予測する先生

このアルゴリズムは「この人がYesになる確率は何%」と予測してくれる先生です。

from pyspark.ml.classification import LogisticRegression
logistic_regression = LogisticRegression(featuresCol="scaled_features", labelCol="y1")

7. Pipeline(処理の流れをまとめる)

流れ作業のベルトコンベア

上で紹介した「文字を数字に変える→まとめる→揃える→予測する」流れを Pipeline に一気にまとめられます。

from pyspark.ml import Pipeline
pipeline = Pipeline(stages=[default_index, assemble, scaler, logistic_regression])

学習と予測

学習(train)とテスト(test)に分ける

過去データの7割で勉強 → 残り3割でテスト
train_df, test_df = df.randomSplit([0.7, 0.3], seed=1234)
fit_model = pipeline.fit(train_df)

結果を確認

  • rawPrediction → モデルが計算したスコア
  • probability → Yesになる確率(0〜1の数値)
pred_train = fit_model.transform(train_df)
pred_train.select("rawPrediction", "probability").show()

例:

probability=[0.94, 0.05] → Yesの確率 94%、Noの確率 5%

まとめ

  • ロジスティック回帰は Yes/No を予測するシンプルな手法
  • PySparkでは
    1. データを数字に変える(StringIndexer)
    2. 特徴量をまとめる(VectorAssembler)
    3. スケールを揃える(StandardScaler)
    4. モデルを当てはめる(LogisticRegression)
      Pipelineで一括実行できる
  • 難しそうに見えるけど、実際は「先生に過去データを見せて、未来を当てさせる」イメージ

最新情報をチェックしよう!