ジョジョの奇妙な Sentence Transformers - スタンド能力を階層的クラスタリングするッ！

今日のミッションは、自然言語で書かれたスタンド能力を sentence-transformers で embedding し、階層的クラスタリングすることッ！



# スタンド能力

スタンド能力は、[Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%89_(%E3%82%B8%E3%83%A7%E3%82%B8%E3%83%A7%E3%81%AE%E5%A5%87%E5%A6%99%E3%81%AA%E5%86%92%E9%99%BA)) のページから取ってきた表を整形して使ったッ！

```python
import pandas as pd

stand_df = pd.read_csv("./JoJoStands3.txt", delimiter="\t")
stand_df
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>スタンド名</th>
      <th>スタンド使い</th>
      <th>スタンド能力</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>ザ・フール（愚者）</td>
      <td>イギー</td>
      <td>砂のスタンド。さまざまな形状に変化させることができる。</td>
    </tr>
    <tr>
      <th>1</th>
      <td>マジシャンズレッド（魔術師の赤）</td>
      <td>モハメド・アヴドゥル</td>
      <td>鳥人型のスタンド。炎を発生させ、自由自在に操る。また、炎を生物探知機のように使用することも可...</td>
    </tr>
    <tr>
      <th>2</th>
      <td>ハイプリエステス（女教皇）</td>
      <td>ミドラー</td>
      <td>遠隔操作型スタンド。様々な鉱物・無機物に変身できる。</td>
    </tr>
    <tr>
      <th>3</th>
      <td>エンプレス（女帝）</td>
      <td>ネーナ</td>
      <td>本体の血液を付着させた相手の肉に寄生する。食物を摂取することで成長する。</td>
    </tr>
    <tr>
      <th>4</th>
      <td>エンペラー（皇帝）</td>
      <td>ホル・ホース</td>
      <td>拳銃型のスタンド。弾丸も含めてスタンドであり、軌道を自由に操作できる。</td>
    </tr>
    <tr>
      <th>5</th>
      <td>ハイエロファントグリーン（法皇の緑）</td>
      <td>花京院典明</td>
      <td>遠隔操作型。紐状に変化するほか、強力な遠距離攻撃「エメラルドスプラッシュ」を放つ。相手の体内...</td>
    </tr>
    <tr>
      <th>6</th>
      <td>ラバーズ（恋人）</td>
      <td>鋼入りのダン</td>
      <td>小型の遠隔操作型スタンド。パワーはないが、極めて長い射程を持つ。他人の脳に進入し、本体の受け...</td>
    </tr>
    <tr>
      <th>7</th>
      <td>シルバーチャリオッツ（銀の戦車）</td>
      <td>ジャン＝ピエール・ポルナレフ</td>
      <td>騎士の姿をした近距離型スタンド。レイピアによる斬撃を繰り出す。甲冑を脱ぐことで、残像が発生す...</td>
    </tr>
    <tr>
      <th>8</th>
      <td>ストレングス（力）</td>
      <td>フォーエバー</td>
      <td>船と一体化したスタンド。一般人にも視認できる。船内の全ての物を自在に操る。</td>
    </tr>
    <tr>
      <th>9</th>
      <td>ハーミットパープル（隠者の紫）</td>
      <td>ジョセフ・ジョースター</td>
      <td>イバラのスタンド。遠隔透視、念写、読心、探索などを行える。イバラで敵を縛ったり、ワイヤーのよ...</td>
    </tr>
    <tr>
      <th>10</th>
      <td>ホウィール・オブ・フォーチュン（運命の車輪）</td>
      <td>ズィー・ズィー</td>
      <td>自動車と一体化し、怪物のような姿の車に変形させる。ストレングス同様、一般人にも視認できる。</td>
    </tr>
    <tr>
      <th>11</th>
      <td>ジャスティス（正義）</td>
      <td>エンヤ婆</td>
      <td>霧状のスタンド。幻覚を引き起こしたり、傷口から侵入して人間や死体を操る。</td>
    </tr>
    <tr>
      <th>12</th>
      <td>ハングドマン（吊られた男）</td>
      <td>J・ガイル</td>
      <td>光を反射する物体に写り込み、鏡像を攻撃することで実体にも同じダメージを与える。</td>
    </tr>
    <tr>
      <th>13</th>
      <td>デス・サーティーン（死神13）</td>
      <td>マニッシュ・ボーイ</td>
      <td>大鎌を持った死神の像を持つ。眠っている者の精神をスタンド能力で作った悪夢世界へ引き込む。相手...</td>
    </tr>
    <tr>
      <th>14</th>
      <td>イエローテンパランス（黄の節制）</td>
      <td>ラバーソール</td>
      <td>スライム状のスタンド。生物を取り込むほか、衝撃や熱などエネルギーを吸収する高い防御力を持つ。...</td>
    </tr>
    <tr>
      <th>15</th>
      <td>エボニーデビル（悪魔）</td>
      <td>呪いのデーボ</td>
      <td>本体の受けた恨みをパワーに変え、人形に取り憑いて操る。本来ならスタンドを傷つけられない通常の...</td>
    </tr>
    <tr>
      <th>16</th>
      <td>タワー・オブ・グレー（灰の塔）</td>
      <td>グレーフライ</td>
      <td>クワガタムシの像を持つ小型のスタンド。スタープラチナですら掴めないほどの凄まじい速さで飛行する。</td>
    </tr>
    <tr>
      <th>17</th>
      <td>スタープラチナ（星の白金）</td>
      <td>空条承太郎</td>
      <td>近距離パワー型スタンド。パワー、スピード、精密動作性の全てに優れる。Part3終盤で時を止め...</td>
    </tr>
    <tr>
      <th>18</th>
      <td>ダークブルームーン（暗青の月）</td>
      <td>偽キャプテン・テニール</td>
      <td>水中戦を得意とする、半魚人のようなスタンド。フジツボを相手に付着させることでエネルギーを吸い取る。</td>
    </tr>
    <tr>
      <th>19</th>
      <td>サン（太陽）</td>
      <td>アラビア・ファッツ</td>
      <td>太陽そのものの像を持つスタンド。摂氏70℃以上の高温やレーザーで攻撃する。夜間であっても極め...</td>
    </tr>
    <tr>
      <th>20</th>
      <td>ジャッジメント（審判）</td>
      <td>カメオ</td>
      <td>相手から聞き出した願望を土に投影して実体化させ、操ることができる。</td>
    </tr>
    <tr>
      <th>21</th>
      <td>ザ・ワールド（世界）</td>
      <td>DIO</td>
      <td>近距離パワー型スタンド。圧倒的なパワーとスピード、精密動作性に加え、時を止める能力を持つ。時...</td>
    </tr>
    <tr>
      <th>22</th>
      <td>オシリス神</td>
      <td>ダニエル・J・ダービー</td>
      <td>「賭け」に負けた者の魂を奪い、コイン状に変える。</td>
    </tr>
    <tr>
      <th>23</th>
      <td>ホルス神</td>
      <td>ペット・ショップ</td>
      <td>冷気を操るスタンド。湖を一瞬で凍結させるほどの強いスタンドパワーを持つ。</td>
    </tr>
    <tr>
      <th>24</th>
      <td>ゲブ神</td>
      <td>ンドゥール</td>
      <td>水と同化した遠隔操作型スタンド。射程距離が極めて長い。液体状の像を自由自在に操り、ウォーター...</td>
    </tr>
    <tr>
      <th>25</th>
      <td>バステト女神</td>
      <td>マライア</td>
      <td>コンセント型の像を出現させ、触れた人間に強力な磁力を帯びさせる。</td>
    </tr>
    <tr>
      <th>26</th>
      <td>セト神</td>
      <td>アレッシー</td>
      <td>本体の影と同化したスタンド。影に触れた相手を若返らせる（胎児にまで変えられる）。知能も比例し...</td>
    </tr>
    <tr>
      <th>27</th>
      <td>クヌム神</td>
      <td>オインゴ</td>
      <td>本体と一体化したスタンド。自分の顔や姿を、体臭・指紋・声帯まで他人そっくりに変える。</td>
    </tr>
    <tr>
      <th>28</th>
      <td>トト神</td>
      <td>ボインゴ</td>
      <td>本体の所持する本と同化したスタンド。極めて近い未来を予言し、漫画の形で本に浮かび上がらせる。...</td>
    </tr>
    <tr>
      <th>29</th>
      <td>アヌビス神</td>
      <td>キャラバン・サライ</td>
      <td>実物の刀に自我を持つスタンドが乗り移った特殊な状態で、柄に触れた者の精神を乗っ取る。物体を透...</td>
    </tr>
    <tr>
      <th>30</th>
      <td>アトゥム神</td>
      <td>テレンス・T・ダービー</td>
      <td>YES・NO形式で相手の心を読む。また、「賭け」に負けた者の魂を奪い、人形に封じ込める。</td>
    </tr>
    <tr>
      <th>31</th>
      <td>クリーム</td>
      <td>ヴァニラ・アイス</td>
      <td>口内に暗黒空間を持ち、暗黒空間に触れた全てのものを消滅させる。本体を暗黒空間に隠すこともでき...</td>
    </tr>
    <tr>
      <th>32</th>
      <td>ティナー・サックス</td>
      <td>ケニーG</td>
      <td>像の有無は不明。現実感のある幻覚を見せる。</td>
    </tr>
  </tbody>
</table>
</div>

# 参考資料

こちらの資料を参考にしました。ありがとうございました。

https://nikkie-ftnext.hatenablog.com/entry/sentence-transformers-embeddings-introduction-en-ja

# 必要なライブラリのインストール

```python
!pip install sentence-transformers
!pip install japanize-matplotlib
```

# sentence-transformers の利用


```python
from sentence_transformers import SentenceTransformer, util

model = SentenceTransformer("stsb-xlm-r-multilingual")
```

# スタンド能力のデータの読み込み

```python
stand_df3 = pd.read_csv("./JoJoStands3.txt", delimiter="\t")
embeddings3 = model.encode(stand_df3["スタンド能力"], convert_to_tensor=True)
embeddings3.shape
```




    torch.Size([33, 768])




```python
stand_df4 = pd.read_csv("./JoJoStands4.txt", delimiter="\t")
embeddings4 = model.encode(stand_df4["スタンド能力"], convert_to_tensor=True)
embeddings4.shape
```




    torch.Size([28, 768])




```python
stand_df5 = pd.read_csv("./JoJoStands5.txt", delimiter="\t")
embeddings5 = model.encode(stand_df5["スタンド能力"], convert_to_tensor=True)
embeddings5.shape
```




    torch.Size([27, 768])




```python
stand_df6 = pd.read_csv("./JoJoStands6.txt", delimiter="\t")
embeddings6 = model.encode(stand_df6["スタンド能力"], convert_to_tensor=True)
embeddings6.shape
```




    torch.Size([25, 768])




```python
stand_df7 = pd.read_csv("./JoJoStands7.txt", delimiter="\t")
embeddings7 = model.encode(stand_df7["スタンド能力"], convert_to_tensor=True)
embeddings7.shape
```




    torch.Size([27, 768])




```python
stand_df8 = pd.read_csv("./JoJoStands8.txt", delimiter="\t")
embeddings8 = model.encode(stand_df8["スタンド能力"], convert_to_tensor=True)
embeddings8.shape
```




    torch.Size([30, 768])


# スタンド能力を embedding するッ！

スタンド能力を embedding するのは、ひょっとしたら ホワイトスネイク の能力かもしれない。

```python
import numpy as np

all_embeddings = np.concatenate(
    [
        e.cpu().numpy()
        for e in [
            embeddings3,
            embeddings4,
            embeddings5,
            embeddings6,
            embeddings7,
            embeddings8,
        ]
    ]
)
all_embeddings.shape
```




    (170, 768)


# 階層的クラスタリング

近い能力を持ったスタンドが近くに来るように階層的クラスタリングを行った。

```python
import japanize_matplotlib
import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import dendrogram, linkage

result1 = linkage(all_embeddings, metric="cosine", method="weighted")
plt.figure(figsize=(4, 32))
dendrogram(
    result1,
    orientation="right",
    labels=pd.concat(
        [
            stand_df3,
            stand_df4,
            stand_df5,
            stand_df6,
            stand_df7,
            stand_df8,
        ]
    )["スタンド名"].values,
    color_threshold=0.5,
)
plt.title("Dedrogram")
plt.xlabel("Threshold")
plt.grid()
plt.show()
```


    
![output_11_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/58649d27-f0ac-9415-26df-c205f03f028b.png)

なるほど、完璧な結果っすねーーッ！ ところどころ意味不明な結果になってるところに目をつぶればよーッ！