5chのトレンドを可視化する


[CYBIRD Advent Calendar 2023](https://qiita.com/advent-calendar/2023/cybird) 25日目担当の@ma_da_iです。
24日目は@shiso_cさんの「[ShaderGraphの話](https://qiita.com/shiso_c/private/bd7c1cacc6246d4dbb32)」でした。
コードを書かずにノードを繋ぐだけで1つの画像を色々な見せ方が出来る**ShaderGraph**
機会があれば是非、使ってみたいと思いました！！

# 自己紹介
サイバードで分析基盤エンジニアを担当してます。

今まではデータを集めるのが仕事でしたが これからは集めたデータから分析が出来るように色々とチャレンジして行こう！と思い勉強中です。

お手柔らかにお願いします。

# ログを見ても分からん...

新規ユーザが行う初日の行動と1日後継続の関係性に関して調査を進めましたが

**＿人人人人人人人人人人＿
＞　 幽霊が多すぎる!!　 ＜
￣Y^Y^Y^Y^Y^Y^Y^Y￣**

行動ログに足跡を残さない幽霊の様なユーザが大量にいる事が分かりました。

そこで **「他の視点でデータを集める必要がある」** と思い、今回は5chの書き込みを元にトレンドの分析を行いました。

これが結構便利だったので記事にしてみました。

# ザックリとした流れ

1. 5chをスクレイピングする
3. トレンドを可視化する

案外コンパクトな内容。これならド素人の自分にもなんとかなりそう!!
環境は **Google Colaboratory** を使いました。

# 5chをスクレイピングする

今回は「[呪術廻戦アンチスレ267](https://kizuna.5ch.net/test/read.cgi/wcomic/1700863841)」でトレンドを見てみます。

最近アニメも人気だしアンチは何に対して書き込んでるのか気になる...
(元々パクリとか言われてたしなぁ...)

``` python:
import pandas as pd
import requests # urlを開くためのライブラリ
from bs4 import BeautifulSoup # スクレイピングのライブラリ

# 呪術廻戦アンチスレ267
url = "https://kizuna.5ch.net/test/read.cgi/wcomic/1700863841"

request = requests.get(url)
soup = BeautifulSoup(request.content, "html.parser")
contents = soup.find_all(class_= "post-content")

texts = []
for con in contents:
  texts.append(con.text)

df = pd.DataFrame({"テキスト": texts})[1:]
df
```

<details><summary>結果はこんな感じです(抜粋でも文字量が多いので丸め込み)</summary><div>

| index | テキスト |
| --- | --- |
| 1 | ファンブック前書き https://i.imgur.com/xnIvPJT.jpg ファンブック後書き https://i.imgur.com/sLMwOuY.jpg 前担当への呪詛 https://i.imgur.com/HiaIVoW.jpg 憧れの作家のキャラクターでも雑な絵 https://i.imgur.com/nIylXqv.jpg 女キャラのイキリな性格をダメ出しされる https://i.imgur.com/71ERbQV.jpg 隙あらばタツキ https://i.imgur.com/jw2cdYf.jpg 意図しないオマージュ https://i.imgur.com/N0vEJzn.jpg ヒロアカ展の寄稿 https://i.imgur.com/qQbDez9.png 新人賞総評「ファイティン」 https://i.imgur.com/LVgKkws.jpg 休載における作者コメント https://i.imgur.com/tFKTpwg.jpg お前ん家、至る所にハンターハンター落ちてんなって言われて恥ずかしかった https://imgur.com/CmmAMgv.jpg _____________________________________ 手塚賞選考コメント【new】 https://i.imgur.com/xMKQqH3.jpg | 1|
| 2 | 『うずまき』（伊藤潤二）盗作問題 https://imgur.com/0QeROau.jpg 盗作された伊藤先生のうずまき https://imgur.com/Tira5e3.jpg 0巻うずまき（初出:ジャンプGIGA 2017 vol.4 2017/7/28発売） https://imgur.com/SQuSGxI.jpg ジャンプ2021年5,6合併号のうずまき https://imgur.com/wMaoK5P.jpg 呪術廻戦コミック16巻のうずまきおよび反転比較 https://imgur.com/0SHpjIi.jpg 芥見下々の謝罪してない謝罪文「ありがとうございました!!」（コミック16巻） https://imgur.com/ZdEFyZA.jpg 劇場版呪術廻戦0黒塗りのうずまき https://i.imgur.com/Ax3dP8i.jpg | 1|
| 3 | ●呪術廻戦9巻第75話における『バキ』構図パクリ疑惑 バキに出てくる鎖鎌の鎌は2つ付いており、片方だけならそういう動きにならない もっと言うと手首で回して速度上げる武器であり、手描けないの誤魔化そうとして腕ブンブン振っているのがモロバレ 原作ほとんど知らないのに表面だけ盗んだのが分かってパクリの芸術点高い ・ 両手武器じゃないんかい！！ 片手なんのために高速移動してるんだろw ・ 鎖鎌って鎌の反対側に分銅とかついてるもんだからパクリと断定するのは難しいかと思ったけど 画像見たらただの鎖に鎌くっつけてるだけだから反対側何もついてないんだな じゃあもうパクリ確定だわそうじゃなかったらなにもついてない鎖ぶるんぶるんしてるだけのアホになるし ・ 武器1本の鎖鎌なのに2本の鎖鎌の動き盗んだせいで刃牙読んでないのがバレるっていう https://imgur.com/xx7QPM9.jpg https://imgur.com/VfLZLSC.jpg https://imgur.com/hBhbUah.jpg https://imgur.com/bnMMoq4.jpg https://imgur.com/wP2T292.jpg https://imgur.com/z2nqSCo.jpg __________________________________ 不安の種からも https://imgur.com/9ATaE6i.jpg _________________________________ 充実海鮮 https://i.imgur.com/uMH2E5b.jpg | 1|
| 4 | ●呪術のパクり元、元ネタ、既視感あると言われた作品リスト(随時追加） 残穢、魔性の子、HUNTER×HUNTER、幽遊白書、BLEACH、ゾンビパウダー NARUTO（原作/アニメ）、サムライ8、D.Gray-man、るろうに剣心、武装錬金 地獄先生ぬーべー、シャーマンキング､銀魂、忍空、DRAGON BALL SLAM DUNK、バガボンド、ジョジョの奇妙な冒険シリーズ、ぬらりひょんの孫 キャプテン翼、進撃の巨人、東京喰種、バキシリーズ、青の祓魔師、鋼の錬金術師 烈火の炎、うしおととら、結界師、ゲットバッカーズ、天上天下 うずまき、長い夢（伊藤潤二）、エヴァンゲリオン、シン・ゴジラ 喧嘩稼業、Fateシリーズ、月姫シリーズ、バトゥーキ、魍魎戦記MADARA、多重人格探偵サイコ ジブリ作品、新世界よりシリーズ、帝都物語、魔界都市、メガテンシリーズ X（CLAMP）、弱虫ペダル、みえるひと、名探偵コナン、カルラ舞う! ハイキュー!!、犬神家の一族（市川崑監督）、東京レイヴンズ、寄生獣、彼岸島 鬼滅の刃、蝿庭のジグザグ、ONE PIECE、無限の住人、僕のヒーローアカデミア チェンソーマン、魔人探偵脳噛ネウロ、GANTZ、SKET DANCE ウルトラシリーズ、笑う犬の冒険よりセンターマン、実写版クマのプーさん 白暮のクロニクル、ペット（三宅乱丈）、サタニックスイート、不呪姫と檻の塔 ギレルモ・デル・トロ作品、キルビル、エイリアンシリーズ、See No Evil2 火ノ丸相撲、餓狼伝 | 4|
| 5 | クラウドシンキングの説明 0463 名無しさんの次レスにご期待下さい 2021/07/05 01:39:50 愚痴スレ見てたらクラウドシンキングって言葉が出ていてたけど言い得て妙すぎて爆笑した 0464 名無しさんの次レスにご期待下さい 2021/07/05 02:20:02 確かにクラウドの同期で説明可能で超ウケる 創作家としてはやはり素人同然なわけだが 0327 マロン名無しさん 2021/07/03(土) 08:57:15.06 仲間の事を心配しないのは「作者が仲間を無事だって決めたから」だよ この漫画は作者が設定を決めた瞬間にキャラクター全員にその設定が共有されるクラウドシンキングシステムを採用してるから 無事だってわかってる人を心配しないだろ？ 全く同じ理由で「作者が虎杖は二度と暴走しないって決めたから」乙骨と平気で別行動するし 「作者が呪力0は強いって決めたから」真依は突然姉の呪力を奪いに行ったんだよ キャラクターの心情でおかしいなって思ったことの8割くらいはこれで説明がつく この漫画に個人の思考なんてものは存在しない https://medaka.5ch.net/test/read.cgi/csaloon/1624856793/327 | 1|

</div></details>

スレッドのURLを変えれば簡単に切り替えができます。
まさか、こんな簡単にスクレイピングが出来るとは...pythonが凄い。感謝。

# トレンドを可視化する

トレンドの前に文章から単語のみを取得する必要があるため **MeCab** と言う形態素解析ツールを使用しました。

``` python:MeCabの準備
!apt install aptitude
!aptitude install mecab libmecab-dev mecab-ipadic-utf8 git make curl xz-utils file -y
!pip install mecab-python3==0.7

import MeCab # 形態素解析

# 文章を単語毎に分割する関数
def mecab_separate(text):

  tagger = MeCab.Tagger("-Ochasen") # 形態素解析を行うパラメータ
  node = tagger.parseToNode(text) # 実際に形態素解析を実行する

  word_list = [] # 文字列を保存する箱

  while node: # 1単語ずつ処理を実行する

    if node.feature.split(",")[0] == "名詞":
      word_list.append(node.surface) # 形態素の文字列情報を保存する

    node = node.next

  return word_list
```

今回は名詞のみに限定して文章から単語を取得するように作成しました。
使った時のイメージはこんな感じです。

``` python:呼び出し
mecab_separate("アリは今日も働いている")
```
``` :結果
['アリ', '今日']
```

長い文章も渡せば単語区切りの配列で帰ってくるので便利です。

次に **WordCloud** を使ってトレンドを確認します。
繰り返し表示される単語は大きく、珍しい単語は小さく表示されます。

``` python:トレンドの可視化
!pip install japanize-matplotlib

from wordcloud import WordCloud
import japanize_matplotlib
import matplotlib.pyplot as plt

stopwords = ['ん', 'よう', 'の', 'こと', 'さ', 'そう', 'まま', 'はず']

def create_wordcloud(df, column):

  doc = ""
  for v in df[column]:

    # 文字列から名詞のみを抽出
    word_list = mecab_separate(v)

    # 大量の名詞を空白文字区切りで連結させる
    doc += " " + " ".join(word_list)

  # 画像作成
  wordcloud = WordCloud(width=400, height=300, background_color='white', font_path=japanize_matplotlib.get_font_ttf_path(), stopwords=set(stopwords)).generate(doc)

  # Wordcloudを表示
  plt.figure(figsize=(8, 6))
  plt.imshow(wordcloud)
  plt.axis('off')
  plt.show()
```
``` python:呼び出し
create_wordcloud(df, "テキスト")
```

そして作成された画像はこんな感じです。

![呪術廻戦アンチスレ267.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631551/06cab5e2-c608-d30a-d797-e74addf9edf6.png)


「鬼滅」や「笑」が多く、正直よく分かりません...
なので、精度を上げるために少し工夫を入れました。

# トレンドの精度を上げる

文章をパターンに分けてパターン毎にトレンドを可視化する。
例えば「笑」の関連ワードを見つける事で文脈を見る事が出来る。
そうする事で分析のデータとして使いやすいものに加工が出来る。

# ザックリとした流れ(改)
1. 5chをスクレイピングする
1. 文章をグループに分ける ← new!!
1. (グループ毎に)トレンドを可視化する

# 文章をグループに分ける

言葉にすると簡単だけど機械的に実行するのは厄介...

ステップとしてはこんな感じ

1. 文章から単語を取得する
2. 単語から重要度を取得する
3. 重要度からグループに分割する

## 単語から重要度を取得する
先のMeCabで単語区切りの配列はあります。
その単語区切りの配列に対して重要度を取得します。

``` python:単語から重要度を取得する
from numpy import vectorize
from sklearn.feature_extraction.text import TfidfVectorizer

vectorizer = TfidfVectorizer(analyzer=mecab_separate) # 形態素解析を指定する
vecs = vectorizer.fit_transform(df["テキスト"]).toarray()
vecs
```

``` python:実行結果
array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       ...,
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.]])
```
文章中の単語の重要度が高ければ高いほど1に近づきます。
でも、人が見て分かりやすいものじゃないですね...
あまり深く考えずに進みます。

## 重要度からグループに分割する

今回は **KMeans** を使ってクラスタ分析をしました。
さっき取得した重要度から指定した数のグループに分けて貰います。

``` python:重要度からグループに分割する
from sklearn.cluster import KMeans

vec = KMeans(n_clusters = 5) # 5個のグループに分類する

df["グループ名"] = vec.fit_predict(vecs)
df
```

今回は5グループに分けてみました。数は適当に調整しています。

<details><summary>結果はこんな感じです(抜粋でも文字量が多いので丸め込み)</summary><div>

| index | テキスト | グループ名 |
| --- | --- | --- |
| 1 | ファンブック前書き https://i.imgur.com/xnIvPJT.jpg ファンブック後書き https://i.imgur.com/sLMwOuY.jpg 前担当への呪詛 https://i.imgur.com/HiaIVoW.jpg 憧れの作家のキャラクターでも雑な絵 https://i.imgur.com/nIylXqv.jpg 女キャラのイキリな性格をダメ出しされる https://i.imgur.com/71ERbQV.jpg 隙あらばタツキ https://i.imgur.com/jw2cdYf.jpg 意図しないオマージュ https://i.imgur.com/N0vEJzn.jpg ヒロアカ展の寄稿 https://i.imgur.com/qQbDez9.png 新人賞総評「ファイティン」 https://i.imgur.com/LVgKkws.jpg 休載における作者コメント https://i.imgur.com/tFKTpwg.jpg お前ん家、至る所にハンターハンター落ちてんなって言われて恥ずかしかった https://imgur.com/CmmAMgv.jpg _____________________________________ 手塚賞選考コメント【new】 https://i.imgur.com/xMKQqH3.jpg | 1 |
| 2 | 『うずまき』（伊藤潤二）盗作問題 https://imgur.com/0QeROau.jpg 盗作された伊藤先生のうずまき https://imgur.com/Tira5e3.jpg 0巻うずまき（初出:ジャンプGIGA 2017 vol.4 2017/7/28発売） https://imgur.com/SQuSGxI.jpg ジャンプ2021年5,6合併号のうずまき https://imgur.com/wMaoK5P.jpg 呪術廻戦コミック16巻のうずまきおよび反転比較 https://imgur.com/0SHpjIi.jpg 芥見下々の謝罪してない謝罪文「ありがとうございました!!」（コミック16巻） https://imgur.com/ZdEFyZA.jpg 劇場版呪術廻戦0黒塗りのうずまき https://i.imgur.com/Ax3dP8i.jpg | 1|
| 3 | ●呪術廻戦9巻第75話における『バキ』構図パクリ疑惑 バキに出てくる鎖鎌の鎌は2つ付いており、片方だけならそういう動きにならない もっと言うと手首で回して速度上げる武器であり、手描けないの誤魔化そうとして腕ブンブン振っているのがモロバレ 原作ほとんど知らないのに表面だけ盗んだのが分かってパクリの芸術点高い ・ 両手武器じゃないんかい！！ 片手なんのために高速移動してるんだろw ・ 鎖鎌って鎌の反対側に分銅とかついてるもんだからパクリと断定するのは難しいかと思ったけど 画像見たらただの鎖に鎌くっつけてるだけだから反対側何もついてないんだな じゃあもうパクリ確定だわそうじゃなかったらなにもついてない鎖ぶるんぶるんしてるだけのアホになるし ・ 武器1本の鎖鎌なのに2本の鎖鎌の動き盗んだせいで刃牙読んでないのがバレるっていう https://imgur.com/xx7QPM9.jpg https://imgur.com/VfLZLSC.jpg https://imgur.com/hBhbUah.jpg https://imgur.com/bnMMoq4.jpg https://imgur.com/wP2T292.jpg https://imgur.com/z2nqSCo.jpg __________________________________ 不安の種からも https://imgur.com/9ATaE6i.jpg _________________________________ 充実海鮮 https://i.imgur.com/uMH2E5b.jpg | 1 |
| 4 | ●呪術のパクり元、元ネタ、既視感あると言われた作品リスト(随時追加） 残穢、魔性の子、HUNTER×HUNTER、幽遊白書、BLEACH、ゾンビパウダー NARUTO（原作/アニメ）、サムライ8、D.Gray-man、るろうに剣心、武装錬金 地獄先生ぬーべー、シャーマンキング､銀魂、忍空、DRAGON BALL SLAM DUNK、バガボンド、ジョジョの奇妙な冒険シリーズ、ぬらりひょんの孫 キャプテン翼、進撃の巨人、東京喰種、バキシリーズ、青の祓魔師、鋼の錬金術師 烈火の炎、うしおととら、結界師、ゲットバッカーズ、天上天下 うずまき、長い夢（伊藤潤二）、エヴァンゲリオン、シン・ゴジラ 喧嘩稼業、Fateシリーズ、月姫シリーズ、バトゥーキ、魍魎戦記MADARA、多重人格探偵サイコ ジブリ作品、新世界よりシリーズ、帝都物語、魔界都市、メガテンシリーズ X（CLAMP）、弱虫ペダル、みえるひと、名探偵コナン、カルラ舞う! ハイキュー!!、犬神家の一族（市川崑監督）、東京レイヴンズ、寄生獣、彼岸島 鬼滅の刃、蝿庭のジグザグ、ONE PIECE、無限の住人、僕のヒーローアカデミア チェンソーマン、魔人探偵脳噛ネウロ、GANTZ、SKET DANCE ウルトラシリーズ、笑う犬の冒険よりセンターマン、実写版クマのプーさん 白暮のクロニクル、ペット（三宅乱丈）、サタニックスイート、不呪姫と檻の塔 ギレルモ・デル・トロ作品、キルビル、エイリアンシリーズ、See No Evil2 火ノ丸相撲、餓狼伝 | 4 |
| 5 | クラウドシンキングの説明 0463 名無しさんの次レスにご期待下さい 2021/07/05 01:39:50 愚痴スレ見てたらクラウドシンキングって言葉が出ていてたけど言い得て妙すぎて爆笑した 0464 名無しさんの次レスにご期待下さい 2021/07/05 02:20:02 確かにクラウドの同期で説明可能で超ウケる 創作家としてはやはり素人同然なわけだが 0327 マロン名無しさん 2021/07/03(土) 08:57:15.06 仲間の事を心配しないのは「作者が仲間を無事だって決めたから」だよ この漫画は作者が設定を決めた瞬間にキャラクター全員にその設定が共有されるクラウドシンキングシステムを採用してるから 無事だってわかってる人を心配しないだろ？ 全く同じ理由で「作者が虎杖は二度と暴走しないって決めたから」乙骨と平気で別行動するし 「作者が呪力0は強いって決めたから」真依は突然姉の呪力を奪いに行ったんだよ キャラクターの心情でおかしいなって思ったことの8割くらいはこれで説明がつく この漫画に個人の思考なんてものは存在しない https://medaka.5ch.net/test/read.cgi/csaloon/1624856793/327 | 1 |
</div></details>

問題なくテキストに対してパターンを割り振る事が出来ました。
なので、これをさっき作ったWordcloudに放り込みます。

``` python:呼び出し
keys = []
for key, group in df.groupby('グループ名'):
  keys.append(key)

df_5ch_group = {}
for key in keys:
  print(key)
  create_wordcloud(df[df['グループ名'] == key], "テキスト")
```

そして作成された画像はこんな感じです。

![呪術廻戦アンチスレ267_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631551/62f577ca-f72b-9bf6-008b-1e59e5082005.png)
![呪術廻戦アンチスレ267_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631551/c99449c1-0ca3-2b1e-f609-0edddc368cc6.png)
![呪術廻戦アンチスレ267_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631551/0f9e4223-18f9-cc7c-fefb-574f0665fd77.png)
![呪術廻戦アンチスレ267_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631551/533b9157-2a60-9d84-af14-412aa6bf9af9.png)
![呪術廻戦アンチスレ267_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631551/db77d78f-4f36-25ed-34eb-9184bb9f9b74.png)

「鬼滅」に関連するワードとして「売り上げ」が挙げられており、
「笑」も「売り上げ」との関連が強いと見えます。

そして最初に挙げていた予想「パクリ」のワードが出ていない事に驚きました。

トレンドの可視化をした後にスレッドの内容をサラッと見たところ、
前の書き込みと次の書き込みに関連性が無い書き込みが多く、
トレンドを作成した際に埋もれてしまうのもスレッドの特徴みたいでした。

# 最後に

行動ログに足跡を残さない幽霊のようなユーザと5chのトレンドを照らし合わせることで継続率を上げるための改善点が見えました。

また、今回は5chの文章からトレンドの可視化でしたがTwitterだったりアンケートだったりYouTubeのコメントだったりデータの差し替えでトレンド分析が出来るのは応用も出来て便利でした。

Pythonの知識が浅い自分でも簡単に使えるように先人の方々がライブラリとして提供されている事に感謝しかありません。

そして、今年の[CYBIRD Advent Calendar 2023](https://qiita.com/advent-calendar/2023/cybird)は以上になります。
新しい年もHAPPYでいっぱいの年になりますように。来年もよろしくお願い致します。