はじめに
それぞれの人が好きな映画は違います。
好きなジャンルや、この監督の映画は好きだなとかで好きな映画の範囲を線引きしている人が多いのではないでしょうか。
ただ、それだと知れる映画は限られます。
今回は、実は知らなかった隠れた自分にとっての名作映画を見つける試みの第一弾として、Word2Vecとk-meansを使用した映画のクラスタリングを試みました。
「自分にとって」ということろがミソです。
これは、映画の出会いを増やす試みです。
結論
先に結論から書きます。
「うまく分類できたように見える」というのが今回の結論です。
なんかぼんやりした結論ですが、それでも読んでみたいという方、読み進めていただければと思います。
Word2Vecとk-means
まず、今回のクラスタリングで使用するWord2Vecとk-meansについて説明します。
Word2Vecは単語をベクトルで表現する手法です。
k-meansは近いデータ同士は同じクラスタであるという考えに基づいたデータ群をk個に分類するという手法です。
つまり、Word2Vecによってベクトル化し、空間上にプロットされた点の近いもの同士をk-meansでクラスタリングできないかと考えたわけです。
使用するデータ
使用するデータは以下のkaggleのデータです。
pythonコード
元々のデータに入っている概要は普通の文章のデータですが、これを以下のように単語ごとに分解します。
[In, the, 22nd, century, a, paraplegic, Marine...]
これは、ある一つの映画に対しての概要の単語リストで、他の映画の概要も同様に単語リストとして用意しています。
この単語リストをWordVecにぶち込みます。
WordVecとk-meansのコードは以下のようになっています。
movie_df[‘overview_sentence_list’]に上記の単語リストのデータが入っています。
from gensim.models import Word2Vec
from sklearn.cluster import KMeans
# 文章のリスト
# リストの中身が空でない要素を持つ行のインデックスを取得
is_not_empty = movie_df['overview_sentence_list'].apply(lambda x: any(x))
movie_word2vec_df = movie_df[is_not_empty]
sentences = movie_word2vec_df['overview_sentence_list']
# Word2Vecモデルの学習
model = Word2Vec(sentences, min_count=1)
# 文章ベクトルの取得
sentence_vectors = []
for sentence in sentences:
if len(sentence) > 0:
vector = sum(model.wv[word] for word in sentence) / len(sentence)
sentence_vectors.append(vector)
# k-meansクラスタリングの適用
num_clusters = 20
kmeans = KMeans(n_clusters=num_clusters)
kmeans.fit(sentence_vectors)
20個のクラスに分類しています。
これで分類ができました。
結果を見ていきましょう。
結果
以下のtarget_labelに抽出したいラベルを設定すると、そのラベルの映画のデータのみ出力されるようになります。
movie_word2vec_df['cluster_label'] = labels
target_label = 19 # 表示させたいクラスタのラベル
filtered_df = movie_word2vec_df[movie_word2vec_df['cluster_label'] == target_label]
filtered_df
試しに映画「アバター」と同じ分類をされた作品を10作品をもとめてみました。
①「ローン・レンジャー」(The Lone Ranger)
②「アベンジャーズ」(The Avengers)
③「ホビット 決戦のゆくえ」(The Hobbit: The Battle of the Five Armies)
④「バトルシップ」(Battleship)
⑤「アイアンマン3」(Iron Man 3)
⑥「オズ はじまりの戦い」(Oz: The Great and Powerful)
⑦「トロン: レガシー」(TRON: Legacy)
⑧「グリーン・ランタン」(Green Lantern)
⑨「トランスフォーマー/ダークサイド・ムーン」(Transformers: Dark of the Moon)
⑩「ウォーターワールド」(Waterworld)
僕は⑧と⑩以外はすべて見ていますが、どうですかね。
一応すべてアクション系の映画ですね。
「アバター」は他の惑星の宇宙人と一緒に闘う話ですが、一緒に闘う系の映画が揃っていそうですね。
なんか近いようにも見えますし、近くないようにも見えますね(笑)
ただ、「アバター」が好きな人におススメする映画かと言われると、「うーん、どうだろうか…」ってのが感想です。
もうちょっと深堀して分類してみる事にします。
3つの結果をクラスタリング
次にさらに深堀して、3つのカラムをそれぞれクラスタリングして、それを1つにクラスタリングするということを試みます。
使うのは以下3つ
- overveiw(概要)
- keywords(キーワード)
- genres(ジャンル)
例えばある映画のクラスタリング結果が以下に3つの要素に関して分類できたら
[1, 19 ,5]
3次元ベクトルになります。
これをさらにk-meansでクラスタリングします。
pythonコード
以下がジャンルでクラスタリングするコードになります。(キーワードも同様のコードになります。)
以下のコードはジャンルでクラスタリングを行っていますが、ハイライトの部分をキーワードに変えてもらえばよいです。
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
from sklearn.preprocessing import MultiLabelBinarizer
is_not_empty = movie_df['overview_sentence_list'].apply(lambda x: any(x)) ## overview_sentence_listと同じデータにするため
movie_genre_clustering_df = movie_df[is_not_empty]
movie_genre_clustering_df['genre_text'] = movie_genre_clustering_df['genre_list'].apply(lambda x: ' '.join(x))
# テキストデータを数値特徴に変換するためにTF-IDFを使用
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(movie_genre_clustering_df['genre_text'])
# k-meansでクラスタリングを実行
num_clusters = 20
kmeans_genre_clustering = KMeans(n_clusters=num_clusters)
kmeans_genre_clustering.fit(X)
# クラスタリング結果を保存
genre_clustering_labels = kmeans_genre_clustering.labels_
概要とジャンルとキーワードをそれぞれクラスタリングできたら、それぞれのラベルを以下のように一つにまとめて、そのまとめたものを20個のクラスに分類します。
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from sklearn.preprocessing import OneHotEncoder
# エンコーディング結果を結合
combined_data = list(zip(labels, genre_clustering_labels, keyword_clustering_labels))
# 再度クラスタリングを実行
num_clusters = 20
consensus_labels = KMeans(n_clusters=num_clusters).fit_predict(combined_data)
# 最終的なクラスタリング結果を表示
movie_word2vec_df['all_cluster_label'] = consensus_labels
movie_word2vec_df
結果
再度「アバター」と同じ分類をされた作品を10作品見てみます。
①「ジョン・カーター」(John Carter)
②「アベンジャーズ/エイジ・オブ・ウルトロン」(Avengers: Age of Ultron)
③「マン・オブ・スティール」(Man of Steel)
④「アベンジャーズ」(The Avengers)
⑤「バトルシップ」(Battleship)
⑥「アイアンマン3」(Iron Man 3)
⑦「トランスフォーマー/リベンジ」(Transformers: Revenge of the Fallen)
⑧「トランスフォーマー/ロストエイジ」(Transformers: Age of Extinction)
⑨「トロン: レガシー」(TRON: Legacy)
⑩「グリーン・ランタン」(Green Lantern)
上記の分類にも入っていた映画もありますね。
一緒に闘う系の映画がまた揃いました。
そして、ロボットが出てきて戦う系の作品が多いです。
ファンタジーチックでありながらリアリズムも含んでいるような映画です。
そして近未来に起きそうな映画とも言えます。SFアクションですね。
似ている映画がクラスタリングできた…とも言えそうです…。
ただ、これらも映画「アバター」が好きな人におススメする映画かと言われると、ちょっとまだ「うーん、どうでしょう…」って感じです。
でも概要だけのクラスタリングよりは精度が上がっているように見えますね。
一旦、今回はこれまででまとめに入ります。
まとめ
今回は20個の分類に分けました。
データ数は約4800なので、一つの分類には240個ほどの映画があることになります。
分類をもっと細かくした方が良かったのかもしれないです。
似ている映画ようにも見えますに、似ていない映画のようにも見えると言えるなんともあやふやな結果になりました。
全く違う映画ではない映画はなかったので、感覚として分類できているのかもしれないですが、お勧めできる映画かと言われると微妙なところです。
歯切れが悪くなりましたが、今回はここまで。ではまた。👋👋👋