EP.13 で、仮想空間の人流をどう集計するかを扱いました。この回はその続きで、似た動き方をまとめる話をします。
一人ひとりの動線を眺めても、傾向は見えません。まとめると、いくつかの型が浮かびます。
1. 何を特徴として使うか
まとめるには、各プレイヤーを数字の並びで表す必要があります。何を特徴にするかで、見えるものが変わります。
| 特徴 | 見えるもの | 注意点 |
|---|---|---|
| 区画ごとの滞在時間の割合 | どこで過ごしたか | 合計で割って正規化する |
| 移動した距離の合計 | 動き回ったか | プレイ時間に比例する |
| 訪れた区画の数 | 探索の広さ | — |
| 同じ場所への再訪回数 | 拠点を持つか | — |
| 目的地までの寄り道 | 寄り道するか直行か | 経路の定義が要る |
1行目の正規化が重要です。EP.13 でも扱いましたが、プレイ時間が長い人は全部の数字が大きくなります。割合にしないと、「よく遊ぶ人」と「よく遊ばない人」に分かれるだけになります。
これは分類でよくある失敗です。最も分散の大きい変数で分かれます。滞在時間をそのまま使うと、行動の違いではなくプレイ量の違いで分類されます。知りたいのは前者のはずです。
2. まとめてみる
特徴が用意できたら、似たもの同士をまとめます。 と呼ばれる手法です。
import numpy as npfrom sklearn.cluster import KMeans
def build_features(sessions, zones): """セッションごとに、区画別の滞在割合を作る。
sessions: [{"player": id, "zone_seconds": {zone: sec, ...}}, ...] """ rows, players = [], [] for s in sessions: total = sum(s["zone_seconds"].values()) if total <= 0: continue # 合計で割って正規化する(プレイ時間の差を消す) rows.append([s["zone_seconds"].get(z, 0) / total for z in zones]) players.append(s["player"]) return np.array(rows), players
def cluster(features, n_clusters=4, seed=0): model = KMeans(n_clusters=n_clusters, n_init=10, random_state=seed) labels = model.fit_predict(features) return labels, model.cluster_centers_
def describe(centers, zones, top=3): """各グループの特徴を、滞在割合の高い区画で説明する。""" for i, c in enumerate(centers): order = np.argsort(c)[::-1][:top] parts = [f"{zones[j]} {c[j]:.0%}" for j in order] print(f" グループ{i}: " + " / ".join(parts))各グループの特徴を、滞在割合の高い区画で説明するのが要点です。数字のグループ番号だけでは、何も分かりません。「グループ0は闘技場に60%」と分かって初めて、解釈できます。
3. いくつに分けるか
分ける数に正解はありません。数値的な目安はありますが、最終的な判断基準は「説明できるか」です。
| 分け方 | 起きること |
|---|---|
| 少なすぎる(2つ) | 違うものが混ざる |
| ちょうどよい | それぞれに名前が付く |
| 多すぎる(10以上) | 似たグループが並び、区別が説明できない |
中央の行が目標です。「それぞれに名前が付く」というのは、各グループの特徴を一言で言えるということ。言えないなら、その分け方は使えません。
実務的な手順は、3〜6くらいを試して、説明できる分け方を選ぶことです。数値的な指標だけで決めると、説明できないグループが残ります。
全体の数%しかいないグループが出たら、扱いを判断してください。極端な行動の人が集まっていることもあり、それ自体が発見になります。一方、単なる外れ値の集まりなら統合するか除外します。
4. 名前を付ける
グループに名前を付けると、共有できるようになります。ただし名前は解釈なので、根拠を併記してください。
| 名前の例 | 根拠になった特徴 |
|---|---|
| 探索型 | 訪問した区画が多く、再訪が少ない |
| 拠点型 | 特定の区画に滞在が集中 |
| 直行型 | 移動距離が短く、寄り道が少ない |
| 回遊型 | 複数の区画を繰り返し行き来 |
| 滞留型 | 移動が少なく、1か所に長時間 |
根拠を併記するのが要点です。「探索型」という名前だけが独り歩きすると、人によって違う意味で使われます。数字の裏付けがあれば、認識が揃います。
そして、名前は仮のものとして扱ってください。データが変われば分かれ方も変わります。「今回のデータではこう分かれた」という前提を忘れないでください。半年後に同じ手順で分けると、違う型が出てくることは普通にあります。
5. 型ごとに見る
型が見つかったら、型ごとに他の指標を見ます。ここで初めて価値が出ます。
- 型ごとの継続率 — どの型が離れやすいか
- 型ごとの詰まり — どこで止まっているか
- 型の割合の推移 — 変更の前後で比率が変わったか
- 型ごとの体験時間 — 想定と合っているか
1番目が最も実務的です。全体の継続率が横ばいでも、型ごとに見ると差があることがあります。「探索型は継続するが、直行型は離れる」と分かれば、打ち手が具体的になります。
これは 統計入門 EP.02 や 前処理の現場 EP.19 で扱った「平均が実態を隠す」と同じ構造です。分けて見ると、平均では見えない偏りが分かります。
6. 解釈で誤らないために
最後に注意点です。まとめた結果を、実態以上に確かなものとして扱わないでください。
| やりがちな誤り | 実際は |
|---|---|
| 型は固定的なものだと考える | 同じ人でも日によって変わる |
| 型に優劣を付ける | どの型も正当な遊び方 |
| 型の数が本質的だと考える | 分け方を変えれば数も変わる |
| 型が原因だと考える | 結果として分かれただけ |
1行目が最も多い誤りです。同じプレイヤーでも、日によって、進行度によって動き方は変わります。「この人は探索型」ではなく、「このセッションは探索型の動きだった」という理解が正確です。
4行目も重要です。型が原因で継続率が違うとは限りません。統計入門 EP.06 で扱ったとおり、共通の原因があるかもしれない。型は分類であって、説明ではありません。
正規化を忘れると、行動の違いではなくプレイ量で分かれます。分ける数は説明できるかで決める(それぞれに名前が付くこと)。名前は根拠と併記し、仮のものとして扱う。価値が出るのは型ごとに他の指標を見たとき。そして型は分類であって説明ではないので、原因と取り違えないでください。
この記事の感想を教えてください
あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。