「採用面接では完璧に見えたのに、なぜ半年で辞めてしまったのか?」
多くの人事担当者や現場マネージャーが、一度はこの問いに頭を抱えたことがあるはずです。これまでの採用判定は、面接官の経験や勘、あるいは「カルチャーフィット」という曖昧な言葉に依存しがちでした。しかし、ビジネスの現場では、勘や経験だけでは説明できない複雑な要因が絡み合っています。
実務の現場でしばしば見受けられるのは、「データはあるのに使われていない」という事実です。採用時のリファレンスチェック(経歴照会)や適性検査の結果、面接時の評価シート。これらは「採用するか否か」の判断に使われた後、デジタル倉庫で埃をかぶっていませんか?
実は、これらの「入社前のデータ」こそが、早期離職を予測する宝の山なのです。
今回は、Pythonを使ってこれらのデータを分析し、「誰が辞めそうか」だけでなく「なぜ辞めそうか」までを可視化するAIモデルを構築してみましょう。エンジニアではない人事担当者の方でもロジックが追えるよう、論理的かつ体系的に解説していきます。手元で動かせるコードも用意しましたので、ぜひ一緒に手を動かしてみてください。
1. 早期離職を「確率」で捉えるための分析設計
コードを書く前に、少しだけ思考の整理をしましょう。AIプロジェクトで最も失敗しやすいのは、「とりあえずデータを全部入れてみる」というアプローチです。目的のない分析は、解釈不能な結果しか生み出さず、ROI(投資対効果)の低下を招きます。
なぜリファレンスデータ(入社前情報)が重要なのか
早期離職(一般に入社1年〜3年以内の離職)の原因は、大きく分けて2つあります。
- リアリティ・ショック: 入社前の期待と実際の業務内容・環境とのギャップ
- 適性のミスマッチ: そもそもその職務に必要な資質が不足していた、あるいは社風に合わなかった
入社後のエンゲージメントサーベイ(パルスサーベイなど)も有効ですが、これらは「症状が出てから」の診断になりがちです。一方で、リファレンスデータや適性検査の結果は、入社前の「素の状態」を記録しています。
例えば、「新しい環境への適応力」が低いという適性検査の結果と、「前職でも人間関係構築に時間がかかった」というリファレンス情報があれば、オンボーディング(受け入れ研修)で手厚いフォローが必要だと事前に予測できますよね。
「なんとなく危ない」を定量化するメリット
ベテランの人事担当者は「この人は少し心配だ」という直感を持っています。これをAIモデル化する意義は、その直感を数値(確率)に変換し、チーム全体で共有可能な客観的指標にすることです。
- 主観: 「なんとなく危なそう」
- 定量化: 「早期離職リスクスコアが75%。主な要因は『ストレス耐性スコアの低さ』と『通勤時間の長さ』の組み合わせ」
後者であれば、具体的な対策(メンターの配置、リモートワークの推奨など)が打てます。
本記事で実装するモデルの全体像
今回は、以下の流れで「早期離職予測モデル」を構築します。
- 目的変数(Y): 入社1年以内の離職有無(0: 在籍, 1: 離職)
- 説明変数(X): 年齢、職種、適性検査スコア、リファレンス評価、面接評価など
- アルゴリズム: ランダムフォレスト(解釈しやすく、扱いやすい)
では、さっそく環境を作っていきましょう。
2. 分析環境の準備とダミーデータの生成
実務データを使う前に、まずはダミーデータで「分析の型」を作ることが大切です。個人情報保護の観点からも、まずは架空のデータでPoC(概念実証)のベースを構築しましょう。
必要なライブラリのインストール
分析にはPythonの標準的なデータサイエンスライブラリを使用します。また、ダミーデータ生成にはFaker、モデルの解釈にはshapを使います。
# ターミナルまたはコマンドプロンプトで実行
pip install pandas numpy scikit-learn shap faker
個人情報を扱わずに試すためのダミーデータ作成コード
以下のコードを実行すると、架空の社員1,000名分のデータセットが生成されます。ここでは、あえて「適性検査のスコアが低いと離職しやすい」「リファレンス評価が低いとリスクが高い」といった傾向を少し混ぜ込んで生成しています。
import pandas as pd
import numpy as np
from faker import Faker
import random
# 再現性確保のためシードを固定
random.seed(42)
np.random.seed(42)
fake = Faker('ja_JP')
# データ生成数
NUM_EMPLOYEES = 1000
def generate_dummy_data(num):
data = []
for _ in range(num):
# 基本属性
age = random.randint(22, 45)
job_type = random.choice(['Sales', 'Engineer', 'Marketing', 'Admin'])
# 入社前評価データ(1-10点満点)
# リファレンスチェックでの評価(前職の上司などからの評価)
ref_score = random.randint(1, 10)
# 適性検査:ストレス耐性
stress_tolerance = random.randint(1, 10)
# 適性検査:協調性
cooperation = random.randint(1, 10)
# 面接評価総合点
interview_score = random.randint(1, 10)
# 離職フラグ生成ロジック(シミュレーション用)
# スコアが低いほど離職リスクを高める重み付け
risk_score = (
(10 - ref_score) * 2 +
(10 - stress_tolerance) * 1.5 +
(10 - interview_score) * 1.0
)
# ランダムな要素も加える
risk_score += np.random.normal(0, 5)
# 閾値を超えたら離職(1)とする
is_turnover = 1 if risk_score > 25 else 0
data.append({
'EmployeeID': fake.unique.uuid4(),
'Age': age,
'JobType': job_type,
'ReferenceScore': ref_score,
'StressTolerance': stress_tolerance,
'Cooperation': cooperation,
'InterviewScore': interview_score,
'Turnover': is_turnover # 目的変数
})
return pd.DataFrame(data)
# データ生成実行
df = generate_dummy_data(NUM_EMPLOYEES)
# データの確認
print("データの先頭5行:")
print(df.head())
print("\n離職者数の内訳:")
print(df['Turnover'].value_counts())
データ構造の確認と前処理の基本
生成されたデータを確認してください。Turnoverが1なら離職、0なら在籍です。実務データでは離職者は全体の5〜10%程度になることが多いですが、この不均衡さが機械学習の難所でもあります。
次に、AIが理解できるようにデータを加工します。特に「職種(JobType)」のような文字情報は、数値に変換(エンコーディング)する必要があります。
# カテゴリ変数のダミー変数化(One-Hot Encoding)
df_processed = pd.get_dummies(df, columns=['JobType'], drop_first=True)
# 分析に使わないID列を削除
df_model = df_processed.drop(['EmployeeID'], axis=1)
print("加工後のカラム:")
print(df_model.columns)
3. 予測モデルの構築:ランダムフォレストの実装
ここから機械学習モデルを構築します。今回は「ランダムフォレスト」を採用します。決定木をたくさん作って多数決を取るこの手法は、精度が安定しやすく、どの変数が効いているかが分かりやすいのが特徴です。
学習データとテストデータの分割
モデルの性能を正しく測るため、データを「学習用(AIに教えるデータ)」と「テスト用(AIの実力を試すデータ)」に分けます。
from sklearn.model_selection import train_test_split
# 説明変数(X)と目的変数(y)に分割
X = df_model.drop('Turnover', axis=1)
y = df_model['Turnover']
# 学習データ8割、テストデータ2割に分割
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
ランダムフォレスト分類器の初期設定と学習
ここで重要なのが class_weight='balanced' という設定です。離職者は通常「少数派」なので、AIは「全員辞めない(全て0)」と予測してサボろうとします。この設定を入れることで、「少数派の離職データを見逃すな」とAIに指示を出せます。
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
# モデルの定義
# class_weight='balanced' で不均衡データに対応
rf_model = RandomForestClassifier(
n_estimators=100,
max_depth=5, # 木を深くしすぎない(過学習防止)
random_state=42,
class_weight='balanced'
)
# 学習実行
rf_model.fit(X_train, y_train)
# テストデータで予測
y_pred = rf_model.predict(X_test)
# 精度の確認
print("レポート:")
print(classification_report(y_test, y_pred))
実行結果の Recall(再現率)に注目してください。離職者(1)に対するRecallが高ければ、「辞める人を辞めると見抜けた割合」が高いことを意味します。人事施策としては、見逃しを減らしたいので、この数値が重要になります。
4. リスクの定量化と要因解釈(XAI)
「この人は離職します」という予測結果だけを渡されても、現場のマネージャーや人事担当者は納得しません。「なぜそうなるのか?」という根拠が必要です。
ここで重要になるのが、XAI(Explainable AI:説明可能なAI)というアプローチです。昨今、イーロン・マスク氏の企業名(xAI)としても話題になりますが、技術文脈では「AIの判断根拠を人間が理解できるようにする技術」を指します。
今回は、その中でも特に信頼性が高く実務でよく使われる SHAP(SHapley Additive exPlanations) を活用します。これはゲーム理論に基づき、「その予測結果に対して、各特徴量がプラス・マイナスどちらに、どれくらい貢献したか」を算出する手法です。
predict_probaメソッドによる離職確率の算出
まず、0か1かの単純なフラグ予測ではなく、「離職確率(%)」というスコアを算出しましょう。実務では「確率60%以上の人を要注意リストに入れる」といった柔軟な運用が可能になります。
# 確率の予測([在籍確率, 離職確率]の配列が返る)
# predict_probaは多くのscikit-learnモデルで標準的に実装されています
probs = rf_model.predict_proba(X_test)
# 離職確率(クラス1になる確率)だけを抽出
turnover_probs = probs[:, 1]
# 結果を元のデータフレームに結合して確認しやすくする
results_df = X_test.copy()
results_df['Actual_Turnover'] = y_test
results_df['Predicted_Risk'] = turnover_probs
# リスクスコアが高い順にトップ5を表示
print("離職リスク上位5名:")
print(results_df.sort_values('Predicted_Risk', ascending=False).head(5))
SHAP値を用いた「なぜそのスコアなのか」の可視化
ここがモデル活用の核心部分です。特定の一人のデータに対して、なぜリスクが高いと判定されたのか、その「内訳」を可視化します。
import shap
import pandas as pd
# SHAP Explainerの作成(ランダムフォレストなどの木構造モデルに最適化されたTreeExplainerを使用)
explainer = shap.TreeExplainer(rf_model)
shap_values = explainer.shap_values(X_test)
# 特定の従業員(例えばインデックス0の人)の要因分析
# 注意: shapのバージョンによって出力形式(リストか配列か)が異なる場合があります
# ここでは一般的にクラス1(離職)に対する貢献度を参照する想定です
print("--- リスク要因の重要度分析 ---")
# モデル全体としてどの特徴量が効いているかを簡易表示
feature_importance = pd.DataFrame(
list(zip(X.columns, rf_model.feature_importances_)),
columns=['Feature', 'Importance']
).sort_values('Importance', ascending=False)
print(feature_importance.head(10))
# ★可視化の実装(Jupyter Notebook環境用)
# 以下のコードを実行すると、個別の要因分解グラフ(Force Plot)が描画されます
# 赤いバーはリスクを高める要因、青いバーはリスクを下げる(引き留める)要因を表します
# shap.initjs()
# shap.force_plot(explainer.expected_value[1], shap_values[1][0,:], X_test.iloc[0,:])
この分析を行うと、同じ「高リスク者」であっても、理由が全く異なることが分かります。
- Aさんの場合: 「残業時間」は少ないが、「直近の評価」が急落していることがリスクを押し上げている。
- Bさんの場合: 「評価」は高いが、「勤続年数」と「給与レンジ」のバランスが市場相場と乖離していることが要因。
このように「なぜ」が分かれば、Aさんには業務量ではなく評価フィードバックの面談を設定し、Bさんには昇給やキャリアパスの提示を行うといった、個別最適化されたリテンション施策が可能になります。これこそが、AIを人事施策に組み込む最大のメリットと言えるでしょう。
5. 実務運用に向けたコードの整理と自動化
PoC(概念実証)でモデルができたら、それを実務プロセスに組み込みましょう。ただし、技術的な実装以上に、運用のルール作りが重要です。AIはあくまで手段であり、ビジネス課題の解決につなげることが目的です。
月次バッチ処理を想定したスクリプト構成
実務では、毎月新しいデータを取り込み、リスクスコアを更新する運用が一般的です。上記のコードを関数化し、以下のようなフローで実行できるように整理します。
- Data Loader: 人事DBから最新の入社者データと退職データを取得
- Preprocessing: 学習時と同じルールで前処理(重要!)
- Inference: モデルでリスクスコアを算出
- Reporting: リスク高の従業員リストとSHAP要因を人事担当者へ通知
倫理的配慮と結果の取り扱い注意点
最後に、実務導入において最も強調したい点です。この予測スコアを、評価や処遇に直接使ってはいけません。
「AIが辞めると言っているから、重要なプロジェクトから外そう」
これは「予言の自己成就」を招きます。AIによって冷遇された従業員は、本当にやる気を失って辞めてしまうでしょう。このモデルはあくまで「ケアが必要な人を見つけるためのアラート」として使うべきです。
- NG: スコアが高い人を警戒する
- OK: スコアが高い人に、より手厚いサポートを提供する
このスタンスを組織内で徹底することが、データ活用成功の鍵です。
まとめ
今回は、リファレンスデータ等の入社前情報を活用した早期離職予測モデルの構築方法をご紹介しました。
- データ準備: 現場の感覚をデータ生成ロジックに反映させる
- モデル構築: 不均衡データへの対処(class_weight)を忘れない
- 解釈性: SHAPを使って「なぜ」を説明し、現場の信頼を得る
Pythonを使えば、ブラックボックスではない、自社の文脈に合った分析ツールを内製することができます。まずは小さなデータセットから始めてみてはいかがでしょうか。
コメント