Amazon の「この商品を買った人はこちらも買っています」、Netflix の「あなたへのおすすめ」、スマホ写真アプリの「人物別アルバム」、迷惑メールの自動仕分け ── 一見バラバラに見えるこれらの機能、裏側の仕組みは驚くほど共通しています。「似てるかどうか」を機械が数字で判定する技術 = や類似検索の土台です。
代表的な手法が (K近傍法) と ()。両方とも「距離 = 似てる度」を使うので混同されがちですが、目的は真逆。この違いが分かると、 ベンダーの提案書も、自社で何ができるかも、急に見通しが良くなります。
数式・統計の予備知識ゼロでもOK。「営業部から似た案件あった?と聞かれて毎回手作業で探してる事業企画」「顧客セグメントを切れと言われて何から始めるか悩むマネージャ」「AI提案書の用語が分からず判断に困る経営層」 ── そんな方に向けて、コードと図で直感に訴える構成です。
本記事のコードを全部つなげた実行可能ノートブックを `/notebooks/ab-13-similarity.ipynb` として配布しています。ダウンロード後、Google Colab の「ファイル → ノートブックをアップロード」から開くと、上から順にセルを実行するだけで散布図やレコメンドの結果が出ます。
1. 「似てる度」って機械はどう測る?
人間は「ふくふく」と「ふくふぐ」を見れば一瞬で「似てる」と分かりますが、機械は 数字に変換して距離を測る しかありません。代表的な 3 つの物差しがあります( / / ユークリッド距離)。
| 物差し | イメージ | 向く例 |
|---|---|---|
| ユークリッド距離 | 地図上の直線距離 | 数値の(年齢・購入額) |
| 矢印の向きが揃ってるか | 嗜好ベクトル・文章の意味() | |
| 何文字書き換えれば同じになるか | 名寄せ・タイポ検出 |
import numpy as npfrom sklearn.metrics.pairwise import cosine_similarityimport Levenshtein
# ① ユークリッド距離a = np.array([3, 4]); b = np.array([6, 8])print(f"ユークリッド距離: {np.linalg.norm(a - b):.2f}") # 5.00
# ② コサイン類似度: 嗜好(5商品への評価)が似てるかuser1 = np.array([[5, 4, 0, 1, 2]])user2 = np.array([[4, 5, 1, 0, 1]]) # 似た嗜好user3 = np.array([[0, 1, 5, 5, 4]]) # 真逆の嗜好print(f"u1 vs u2: {cosine_similarity(user1, user2)[0][0]:.3f}") # 0.880 (似てる)print(f"u1 vs u3: {cosine_similarity(user1, user3)[0][0]:.3f}") # 0.318 (違う)
# ③ 編集距離: 名寄せでよく使うprint(Levenshtein.distance("ふくふく", "ふくふぐ")) # 1 (1文字差)print(Levenshtein.distance("ふくふく", "ふくふくテック")) # 3 (3文字追加)「似てる」の測り方は1つではなく、扱うデータと目的に応じて選ぶ。数値データなら距離、文章なら意味の方向、文字列なら編集回数 ── と覚えておけば十分です。
2. K近傍 ── 答え合わせ済み辞書を引く
シナリオ: 過去の顧客に「優良 / 一般」のラベルが付いている。新規顧客が来たとき、似てる過去客 5 人を探して、その 5 人の多数決でラベルを当てる。
これが K近傍法(K-Nearest Neighbors)。「K=5」の K は「近い何人を見るか」。
from sklearn.datasets import make_blobsfrom sklearn.neighbors import KNeighborsClassifier
# 過去顧客200人: x=月間訪問日数, y=月間購入額(千円), label=優良(1)/一般(0)X, y = make_blobs(n_samples=200, centers=[[3, 5], [10, 25]], cluster_std=2.5, random_state=42)X = np.clip(X, 0, None)
# モデル学習: 過去データを覚えるだけknn = KNeighborsClassifier(n_neighbors=5)knn.fit(X, y)
# 新規顧客が来た!new_customers = np.array([ [4, 6], # 訪問少 / 購入少 → 一般客? [11, 22], # 訪問多 / 購入大 → 優良客?])print(knn.predict(new_customers))# → [0 1] (一般, 優良)学習は「過去データを覚えるだけ」。予測時に「この新規客に最も近い K 人」を探して、その K 人のラベルを多数決でコピー。シンプルだが、業務の多くの場面で十分に強力です。
K-NN の業務応用
- 類似商品レコメンド:「この商品を買った人はこれも買っています」(似た購買パターンの客が買ったものを引く)
- 類似案件検索:「この案件と似た過去案件」を提案書作成時に引き出す
- スパム判定: 過去の迷惑メール / 正常メールに似てるかでフィルタ
- 写真の人物分類: スマホアプリで顔の特徴ベクトルから「同一人物」を集める
3. クラスタリング ── 仲間分け
シナリオ: 顧客のラベルがまだ無い。とりあえず「似た顧客同士で 3 グループに分けて」と機械にお願いしたい。
これが K-meansクラスタリング。「K=3」の K は「いくつのグループに分けるか」。
from sklearn.cluster import KMeans
# 同じ顧客データ。今回はラベル y を使わないkmeans = KMeans(n_clusters=3, n_init=10, random_state=42)cluster_labels = kmeans.fit_predict(X)
# 各クラスタの傾向を見るimport pandas as pddf = pd.DataFrame(X, columns=['訪問日数', '購入額(千円)'])df['cluster'] = cluster_labelsprint(df.groupby('cluster').agg(['mean', 'count']).round(1))# 出力例:# 訪問日数 購入額(千円)# mean count mean count# cluster# 0 3.5 98 5.6 98 ← ライト層# 1 9.0 72 22.4 72 ← VIP層# 2 11.8 30 27.1 30 ← スーパーVIP層機械は「優良/一般」のラベルを知らないのに、似た者同士でちゃんと塊を見つけてくれる。しかし「クラスタ0が何者か」「クラスタ1がVIPか」は機械には分からない。データを見て名前を付け、施策に翻訳するのは人間の役割です。
クラスタリングの業務応用
- 顧客セグメンテーション: マーケ施策をセグメント別に出し分け
- 商品グルーピング: 売上パターンが似た商品をまとめてカテゴリ再設計
- 異常検知: どのクラスタにも属さない孤立点を「異常」として検出
- ペルソナ抽出: アンケートデータから「どんな顧客タイプがいるか」を発見
4. 並べて比較 ── 同じデータ、目的が真逆
| 観点 | K近傍 (K-NN) | クラスタリング (K-means) |
|---|---|---|
| 教師 | あり(正解ラベル必要) | なし |
| 目的 | 予測 / 分類 | 構造発見 / グループ分け |
| 入力 | 新規データ + 過去のラベル付きデータ | ラベルなしデータの集合 |
| 出力 | 新規データのラベル予測 | 各データの所属グループID |
| Kの意味 | 近い何人を見るか | いくつのグループに分けるか |
| 業務例 | 類似商品レコメンド・優良客判定・スパム判定 | 顧客セグメント・異常検知・商品グルーピング |
両方とも「距離=似てる度」を使うところが共通。しかし目的は真逆。K-NN は「過去の答えを引く」、クラスタリングは「答えなしで構造を見つける」。これが分かれば、AI関連の提案書もぐっと読みやすくなります。
5. 気づかずに使ってる場面
実は身の回りのサービスは、この2手法(とその親戚)の応用だらけです。
| サービス・機能 | 中身は? |
|---|---|
| Amazon「この商品を買った人は…」 | K-NN(似た購買履歴の客の購買を引く) |
| Netflix「あなたへのおすすめ」 | K-NN + クラスタリング(嗜好クラスタ × 類似ユーザ) |
| スマホ写真の人物別アルバム | K-NN(顔ベクトル空間で同一人物を集める) |
| 迷惑メール自動仕分け | K-NNなど(過去の正解ラベルから判定) |
| での社内文書検索 | K-NN(質問のembeddingに近い文書を引く ─ 大規模K-NNそのもの) |
| 異常な購買パターン検知 | クラスタリング(どのクラスタにも属さない外れ点) |
6. 自社で試すなら ── 3段階のロードマップ
| 段階 | やること | 想定期間 |
|---|---|---|
| ① まず体感 | 本記事の Colab ノートブックを開いて、自分の手で動かす。サンプルデータで挙動を理解 | 1日 |
| ② 自社データで実験 | 顧客マスタや購買履歴 100〜1000 行 を で抜き出し、ノートブックに差し込み。クラスタが意味を持つか試す | 1〜2週間 |
| ③ 業務組み込み | 週次バッチでセグメント更新、レコメンドAPI化、ダッシュボードに組み込み等。本格構築 | 1〜3ヶ月 |
似てるかどうかを測るには 数値化 が必須。文字列(性別、職種など)はダミー変数化、購入額や訪問頻度は スケールを揃える(標準化) ことで、距離の意味が公平になります。「年齢」と「年収」を同じ重みで扱うと年収だけが効いてしまうので注意。
まとめ
- 「似てる」を機械でやるには数字に変換して距離を測る(ユークリッド・コサイン・編集距離など)
- K-NN = 答え合わせ済み辞書を引く: 過去の正解ラベルをコピー(予測・分類)
- クラスタリング = ラベルなしで仲間分け: 構造を発見(セグメント・異常検知)
- 両方とも距離を使うので混同されるが 目的は真逆
- Netflix・Amazon・スマホ・迷惑メール ── 身の回りはこの2手法の応用だらけ
次回予告
EP.14 では、ベクトル検索とRAG ── 文章の「意味」で似てるを探す技術。社内文書を AI に答えさせる仕組みの基盤を、同じく素人目線で扱います。
名寄せ(編集距離・ファジーマッチ)の実装詳細 → 前処理シリーズ EP.06「名寄せの基礎:完全一致からファジーマッチングへ」。embedding モデルの選び方 → RAG実装ハマりどころ図鑑 EP.03「Embedding モデル選定の意外な落とし穴」。
この記事の感想を教えてください
あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。