初めて問い合わせる顧客への精度を知りたいなら、同じ顧客の行を訓練とテストに分けず、顧客IDをGroupKFoldのgroupsに渡します。 行をシャッフルしても、同じ顧客の別の問い合わせが双方に入る場合があります。分割後は、行番号に加えて顧客IDの共通部分が空であることを確かめます。

scikit-learnで交差検証を使い始め、同じ顧客から複数の行があるデータを扱う人向けです。架空の問い合わせを使い、精度を計算する手前で、評価が知りたいことに合っているかを確認します。

行を分ける方法と顧客を分ける方法を比べる

「初めての顧客」の予測を評価対象にする

窓口に入った問い合わせを、通常対応と要確認に振り分けるとします。入力は問い合わせの文面や受付チャネルで、学習用の正解は担当者の振り分け結果です。顧客によって文面のひな形、契約内容、連絡経路が似ている場合があります。顧客IDを特徴量から消しても、文面やほかの項目から同じ傾向を学ぶ余地は残ります。

新規顧客に対する精度を知るには、テスト顧客の別の問い合わせも訓練から外します。反対に、既存顧客の次回対応を予測したいときは、過去の問い合わせ履歴を使えることがあります。そのときは、未来の連絡や後日判明した結果が訓練へ入り込まないように評価を設計します。

架空12行で顧客IDの重複を再現する

下の表には6顧客が2回ずつ登場します。最初の6行が1回目、次の6行が2回目です。単純なKFold(n_splits=3)なら、最初のテストにあるA〜Dの別の行が訓練にも含まれます。モデルを訓練する前に、IDの集合だけでこの問題を見つけられます。

from sklearn.model_selection import GroupKFold, KFold

customers = list("ABCDEFABCDEF")
labels = [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
X = [[i] for i in range(len(customers))]  # 分割を確認するダミー

def group_set(indices):
    return {customers[i] for i in indices}

train, test = next(KFold(n_splits=3).split(X))
assert group_set(train) & group_set(test) == set("ABCD")

splits = list(GroupKFold(n_splits=3).split(X, labels, groups=customers))
test_counts = {customer: 0 for customer in set(customers)}
for fold, (train, test) in enumerate(splits, start=1):
    train_groups, test_groups = group_set(train), group_set(test)
    assert train_groups.isdisjoint(test_groups)
    for customer in test_groups:
        test_counts[customer] += 1
    print(fold, sorted(test_groups), len(test), sum(labels[i] for i in test))
assert set(test_counts.values()) == {1}

このコードのXは分割を目で追うためのダミーです。連番を予測モデルの特徴量として使う例ではありません。テスト顧客が何回使われたかも数えています。各回で顧客が重複しないことと、全分割を通して各顧客が1回テストに現れることは、分けて検査します。

繰り返し評価と、一度だけの取り分けを区別する

GroupKFoldの公式リファレンスとGroupShuffleSplitの公式リファレンス(2026年11月10日確認)では、前者は各グループが全分割を通してテストに1回登場する一方、後者のランダム分割では、異なる回のテストグループが重なる場合があります。

評価したい対象に応じた分割の選択
分割この表で守る単位使う場面点検すること
KFold行行を互いに独立と扱える同じ顧客が双方に入る余地
GroupKFold顧客未知顧客を順番に評価する顧客重複、陽性数、行数
GroupShuffleSplit顧客顧客を一度取り分ける/ランダムに反復test_sizeはグループ単位、反復間の重複
日時で分ける評価開始時刻将来の問い合わせを評価する正解の確定時刻、同じ顧客を許すか

例えば6顧客から3分の1をテストへ取り分けるとき、対象は2顧客です。その2顧客が全行の3分の1を持つとは限りません。問い合わせ件数の多い顧客を引けば、行数が半分以上になることもあります。評価表には顧客と行の両方を記載します。

何を顧客IDにするかをデータの入口で決める

複数の受付経路がある場合、チャットの顧客番号と電話の顧客番号が別の体系かもしれません。同じ顧客に見える名前を機械的にまとめると、別顧客を同一にするおそれがあります。反対に、同じ顧客のIDが移行で変わったなら、照合表がない限り別グループとして分かれてしまいます。

まず何を未知にするかを決め、顧客、企業、契約、案件から必要な単位を選びます。同じ会社で文書や文面の共有が多く、「未契約の企業」で評価したいなら企業単位が適しています。IDが欠損した行は件数と由来を確認し、すべて別人扱いするか同一扱いするかを自動で決めません。

陽性の偏りと、分割後に残る漏洩を確認する

陽性を持つ顧客が何社いるか数える

例の陽性はAに2件、Bに1件です。陽性は3行あっても、陽性を持つグループは2つなので、3つのテスト回のすべてに陽性を置くことはできません。分割器の設定を変える前に、陽性を持つ顧客の集合を数えます。

positive_groups = {g for g, y in zip(customers, labels) if y == 1}
assert positive_groups == {"A", "B"}
positive_counts = [sum(labels[i] for i in test) for _, test in splits]
assert 0 in positive_counts

StratifiedGroupKFoldは顧客の重複を避けながらクラス比を近づけようとする方法ですが、存在しない陽性グループは作れません。回数を減らす、評価データを増やす、算出できない指標を明記するなど、評価の目的に合わせて対応します。クラス比だけを見たいときは層化分割でクラス数を点検する方法が参考になります。

平均精度の前に分割ごとの内訳を残す

検収表の列は、分割番号、訓練顧客数、テスト顧客数、双方の共通顧客数、テスト行数、陽性行数です。共通顧客がゼロでない回があれば、その回の精度を報告する前に分割を直します。陽性ゼロの回があれば、何が測れないかを先に決め、都合よく除外しないようにします。

顧客の行数に差がある場合、問い合わせ単位の指標では、大きな顧客の影響が強くなります。運用上は「問い合わせ1件あたり」と「顧客1社あたり」のどちらを重視するかを先に相談します。分割の条件と指標の集計単位は同じ問題ではありません。

分割の前に全データで前処理を学習しない

テスト顧客の文面で語彙表を先に作る、全期間から平均値を計算して欠損を埋める、全データでカテゴリをまとめると、顧客を分離した後でもテスト側の情報が入り得ます。各回の訓練だけで学習し、その変換をテストへ適用します。StandardScalerを分割後にfitする例と同じ確認です。

モデル選びと最終評価で同じテスト顧客を繰り返し見れば、調整結果がその顧客に合ってしまう可能性があります。提出用の結果が必要な場合は、探索用と最後に一度評価する顧客群の用途を分け、どの段階で各群を見たか記録します。

既存顧客の将来も調べるなら、別の評価表を作る

未知顧客への精度と、既存顧客が来月もう一度問い合わせた場合の精度は、異なる質問です。後者では過去の履歴を入力にできても、将来に確定する担当結果は使えません。TimeSeriesSplitで正解の確定時刻を見る手順と組み合わせて考えられます。

未知顧客かつ将来を評価したい場合は、グループも時刻も条件に含める必要があります。単純に2つの分割器の名前を並べるだけでは条件を表せません。まず過去の訓練候補と未来のテスト候補を定義し、テストにする顧客の訓練候補を除外したときに、必要な件数とクラスが残るか確かめます。

分割の設計をレビューしてもらう学び方

Pythonの基礎から評価まで順に学びたい場合は、Python WinnerのAI・機械学習マスターが候補です。公式案内では機械学習の理論や実装をマンツーマンで扱います(2026年11月10日確認)。顧客単位の分割が教材に含まれるか、受講中に自分の検収表を見てもらえるかは、申込前に確認してください。

広告:【PythonWinner】

よくある質問

Q. 顧客IDを特徴量から外せば十分ですか?
A.

同じ顧客に似た文面や属性がある場合、IDを外しても共通の手掛かりが残ります。未知顧客の評価なら、分割にも顧客IDを使います。

Q. GroupKFoldは行数も均等にしますか?
A.

顧客を分割しないため、同じ行数にはならないことがあります。各回の顧客数、行数、クラスを確認してください。

Q. 同じ顧客は何回テストに入りますか?
A.

GroupKFoldでは全分割を通して1回です。GroupShuffleSplitを反復した場合は、同じ顧客が別のテスト回にも入り得ます。

Q. グループ数より多い分割は作れますか?
A.

GroupKFoldに必要な異なるグループ数はn_splits以上です。必要なグループ数を満たしていても、陽性の分布は別に確認します。

Q. 顧客IDが欠損している行はどうしますか?
A.

欠損の件数と由来を調べます。正しいグループへ戻せない行は保留や別集計とし、その扱いが評価対象を変えることを記録します。

Q. 精度が下がれば漏洩を修正できた証拠ですか?
A.

分割後の評価対象が変わるため、精度の差だけで原因は断定できません。各回の重複、前処理、ラベルの利用時点を点検します。