---
type: slides
---

# 単語ベクトルと意味的類似度

Notes: このレッスンではspaCyを使って、文章やスパン、トークン間の類似度を予測する方法を学んでいきます。

そして、単語ベクトルとは何か、それをどのようにNLPアプリケーションに使っていくかということも学んでいきます。

---

# 意味的類似度を比較する

- `spaCy`を使うと、2つのオブジェクトを比較、類似度を予測することができます
- `Doc.similarity()`、`Span.similarity()`、`Token.similarity()`
- 他のオブジェクトに対して、類似度（0~1）を返します
- **重要：** 単語ベクトルが含まれているパイプラインが必要です。例：
  - ✅ `en_core_web_md` （中サイズパイプライン）
  - ✅ `en_core_web_lg` （大サイズパイプライン）
  - 🚫 `en_core_web_sm`は非対応（小サイズパイプライン）

Notes: spaCyを使うと、2つのオブジェクトを比較し、類似度を予測できます。例えば、doc、span、tokenなどです。

`Doc`と`Token`と`Span`の`.similarity`メソッドは、他のオブジェクトを引数にとり、類似度を示す0以上1以下の浮動小数点数を返します。

重要：類似度を取得するには、単語ベクトルが入っている大きなパイプラインを使用する必要があります。

例えば、中もしくは大サイズの日本語パイプラインです。小サイズのものは対応していません。
なので、もし単語ベクトルを使いたいときは、名前が「md」もしくは「lg」で終わっているパイプラインを使ってください。
詳細はこちらをご覧ください：[models documentation](https://spacy.io/models)。

---

# 類似度の例(1)

```python
# 単語ベクトルが含まれる大きなパイプラインをロード
nlp = spacy.load("ja_core_news_md")

# 2つのdocを比較
doc1 = nlp("私はファーストフードが好きです")
doc2 = nlp("私はピザが好きです")
print(doc1.similarity(doc2))
```

```out
0.8716342586443669
```

```python
# 2つのトークンを比較
doc = nlp("私はピザとパスタが好きです")
token1 = doc[2]
token2 = doc[4]
print(token1.similarity(token2))
```

```out
0.7465099
```

Notes: 例を見てみます。2つのdocが似ているかどうかを調べたいとしましょう。

まずはじめに、中サイズの日本語パイプライン「ja_core_news_md」をロードしましょう。

次に、2つのdocオブジェクトを作れば、1つめのdocオブジェクトの`similarity`メソッドを2つめのdocオブジェクトに適用し、
類似度を算出することができます。


ここでは、「ファーストフードが好き」と「ピザが好き」の類似度スコアが0.87となり、かなり高いことが予測されています。

同じ方法をトークンにも用いることができます。

単語ベクトルによると、「ピザ」と「パスタ」のトークンは似たようなもので、スコアは0.7点となっています。

---

# 類似度の例(2)

```python
# docとtokenを比較
doc = nlp("私はピザが好きです")
token = nlp("メロドラマ")[0]

print(doc.similarity(token))
```

```out
0.23785200060156875
```

```python
# spanとdocを比較
span = nlp("私はピザとパスタが好きです")[2:5]
doc = nlp("マクドナルドはハンバーガーを売っています")

print(span.similarity(doc))
```

```out
0.636682373365992
```

Notes: `similarity`メソッドは、異なるオブジェクトに対しても用いることができます。

例えば、docとtokenに対して使えます。

ここでは、類似度はかなり低く、2つのオブジェクトはあまり似ていないと考えられます。

この例は、「ピザとパスタ」というスパンと、マクドナルドに関するdocを比較しています。

類似度は0.63となっており、似たようなものであると考えられます。

---

# 類似度の算出法

- 類似度は**単語ベクトル**を用いて決められています
- 単語の意味を多次元で表しています
- [Word2Vec](https://en.wikipedia.org/wiki/Word2vec)のようなアルゴリズムと、大量のテキストを用いて生成されます
- spaCyの機械学習パイプラインに組み込むことができます
- デフォルトでコサイン類似度が用いられますが、変更可能です
- `Doc`と`Span`ベクトルは、デフォルトではトークンのベクトルの平均です
- 長くて無関係の単語がたくさん含まれている文章よりも、短いフレーズの方が効果的です

Notes: さて、spaCyは裏側で何をしているのでしょうか？

類似度は、単語の意味を表現する多次元の単語ベクトルを用いて決定されます。

Word2Vecというアルゴリズムを聞いたことがあるかもしれませんが、これは生のテキストから単語ベクトルを学習するのによく使われるアルゴリズムです。

単語ベクトルはspaCyの機械学習パイプラインに組み込むことができます。

デフォルトでは、類似度は2つのベクトルのコサイン類似度を用いて計算されますが、必要に応じて変更可能です。

`Doc` や `Span` のように複数のトークンからなるオブジェクトのベクトルは、それらのトークンベクトルの平均値がデフォルトとなります。

なので通常、無関係な単語が少ない短いフレーズの方が有用です。

---

# spaCyの単語ベクトル

```python
# 単語ベクトルの入っている大きなパイプラインをロード
nlp = spacy.load("ja_core_news_md")

doc = nlp("私はバナナを持っています")
# token.vector属性によって単語ベクトルを取得
print(doc[2].vector)
```

```out
 [1.25627756e-01,  -2.17214048e-01,  -1.46539673e-01,
 -1.94955766e-01,  -1.30407959e-02,   4.03662860e-01,
  4.29999530e-02,  -1.59088016e-01,  -8.30075815e-02,
 -1.73158571e-01,   1.36674210e-01,   1.26392260e-01,
  2.15721652e-01,   2.19511256e-01,  -1.11118585e-01,
 -2.16954395e-01,   1.80966899e-01,   2.26869956e-02,
 -5.54665446e-01,  -1.19882740e-01,  -4.55799609e-01,
  2.26338193e-01,   8.33484158e-02,   2.73890346e-01,
 -2.09421180e-02,  -4.32958305e-01,  -4.47268039e-01,
  3.73480678e-01,   5.11980280e-02,  -1.16114751e-01,
  1.81419268e-01,  -1.63416579e-01,   2.36833602e-01,
  ...
```

Notes: これらのベクトルがどのようなものであるかのイメージを掴むための例を示しています。

最初に、単語ベクトルが入っている中サイズのパイプラインをロードします。

次に、テキストを処理し、`.vector`属性によってトークンのベクトルを取得します。

結果として、「バナナ」を表す300次元のベクトルが出力されます。

---

# 類似度はアプリケーションに依存

- 推薦システム、重複検出等、様々なアプリケーションに用いることができます
- 「類似度」の客観的な定義はありません
- アプリケーションのコンテキストや、目的に依存します

```python
doc1 = nlp("私はネコが好きです")
doc2 = nlp("私はネコが嫌いです")

print(doc1.similarity(doc2))
```

```out
0.9712794921800566
```

Notes: 類似度の予測は、多くのアプリケーションに用いることができます。
例えば、ユーザに対して、今まで読んだ文章をもとに似た文章を推薦するシステムなどです。
また、オンラインプラットフォーム上の投稿のように、重複するコンテンツの検出にも役立ちます。

しかし、何が似ていて何が似ていないかという客観的な定義は存在しないことを心に留めておいてください。
これはコンテキストと、アプリケーションの目的に依存します。

これが一例です。spaCyのデフォルトの単語ベクトルは、「私はネコが好きです」と「私はネコが嫌いです」の類似度が非常に高いと予測します。
これらの文は両方とも、猫に関する感情について表しているので、結果は理にかなっています。
しかし、これらの文は正反対の感情を述べているので、別のアプリケーションで用いる際は「全く似ていない」という予測結果が欲しくなるかもしれません。

---

# Let's practice!

Notes: それでは手を動かしていきましょう。実際にspaCyの単語ベクトルを使ってみて類似度の予測をしてみましょう。
