質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

833閲覧

コサイン類似度が正しく算出されない

handake

総合スコア1

Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/12/10 08:46

前提・実現したいこと

プログラミング初心者で、初投稿です。
わかりづらいとは思いますがご容赦ください。
https://qiita.com/hik0107/items/96c483afd6fb2f077985
@hik0107様のブログのデータセットからコサイン類似度を算出して比較をしようと、拙いながらも様々なブログなどを閲覧して自力でコサイン類似度の算出を試みたのですが、最終的に算出される値が1になってしまって(コサイン類似度は-1~1の間の値をとる)どうすれば正しい値が算出されるか悩んでいます。
datasetは先のブログのデータを利用しています。

発生している問題・エラーメッセージ

1.0

該当のソースコード

python

1import numpy as np 2import pandas as pd 3def cos_sim(person1, person2): 4 5 both_rated = {} # 双方に共通のアイテムを取得 6 7 for item in dataset[person1]: 8 if item in dataset[person2]: 9 both_rated[item] = 1 10 11 # 共通のアイテムを持っていなければ 0 を返す 12 if len(both_rated) == 0: 13 return 0 14 15 16 #コサイン類似度の計算 17 cos_similarity = [] 18 19 dot12 = np.dot(dataset[person1][item] , dataset[person2][item]) 20 norm1 = np.linalg.norm(dataset[person1][item]) 21 norm2 = np.linalg.norm(dataset[person2][item]) 22 23 for item in both_rated: 24 25 #内積の計算 26 cos_similarity = dot12 / (norm1 * norm2) 27 28 return cos_similarity 29 30 print(cos_simimilarity(person1,person2)) 31cos_sim('Lisa Rose','Jack Matthews')

試したこと

内積の計算のnorm1などに直接入れて算出した。

補足情報(FW/ツールのバージョンなど)

google colaboratoryを用いています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2021/12/10 11:03 編集

cos 類似度 = 2つのベクトルのなす角のことなので、cos 類似度を計算する前に、なんらかの方法で比較対象の2つの入力を数値ベクトルに変換する必要があるのではないでしょうか。 文章の類似度だと簡単な方法では Bag-of-words などありますが、今回のケースでどのような方法で変換するかは質問者さんが考える必要がある部分です
jbpb0

2021/12/10 11:34

tiitoiさん 質問者さんがやろうとしてるのは、各映画に付けた点数から計算することで、「文章」(映画の題名)から計算するのではありませんよ
jbpb0

2021/12/10 11:44

質問者さん コードの「for item in dataset[person1]:」のループが終わった段階で、「item」はどれか一つの映画の題名が入った状態になってるので、 dot12 = np.dot(dataset[person1][item] , dataset[person2][item]) norm1 = np.linalg.norm(dataset[person1][item]) norm2 = np.linalg.norm(dataset[person2][item]) は、その一つの映画だけに付いて計算されます その後の「for item in both_rated:」のループの中では「item」は使われず、上記3行で計算された値で cos_similarity = dot12 / (norm1 * norm2) が計算されるので、結局一つの映画に対する点数しか使われません 二人の人が共通して評価した映画全部の点数を使って計算したいのですよね?
handake

2021/12/10 15:01 編集

tiitoiさんjbpb0さん質問ありがとうございます。そして遅くなってしまい申し訳ないです。 まずtiitoiさんjbpb0さんが言うように人ごとのコサイン類似度を求めようとしてました。説明不足で申し訳ないです。
handake

2021/12/10 15:05

それとjbpb0さんの仰る通りで2人が共通して評価した映画全体の点数を使ってその2人がつけた点数から2人のコサイン類似度を求めようとしています。 そうなると今のプログラムだと映画ひとつの評価だけで計算されているという認識で合っていますでしょうか? 今自分がやりたいことはそれぞれ2人の評価した点数からコサイン類似度を求めたいのですがどうすればいいでしょうか?
jbpb0

2021/12/10 21:55 編集

> 今のプログラムだと映画ひとつの評価だけで計算されている #コサイン類似度の計算 cos_similarity = [] のすぐ下に print(item) をインデントを合わせて追加して、実行してみてください 映画の題名は一つだけしか表示されませんよね そこよりも下のコードを見たら、上記で表示される映画の点数だけが計算に使われることは、明らかですよね
handake

2021/12/10 22:54

なるほど!そうですね、print(item)を実行してみたらjbpb0さんの言う通り題名は1個しか表示されませんでした。そうなると演算の処理はその1個にしか行ってないですね。 自分がやりたい処理をさせるにはユーザの評価スコアをベクトルにしてそれらのベクトルのなす角を求めるという形で進めるのがよいのでしょうか?
guest

回答1

0

ベストアンサー

すいません。質問内容を勘違いしてました。
共通のタイトルの点数からベクトルを作成し、そのcos類似度を計算するのであれば、以下のようにすればよいです。

2つの dict 型の変数 dict1, dict2 があるとき、dict1.keys() & dict2.keys() で共通のキーが取得できます。

import numpy as np dataset = { "Lisa Rose": { "Lady in the Water": 2.5, "Snakes on a Plane": 3.5, "Just My Luck": 3.0, "Superman Returns": 3.5, "You, Me and Dupree": 2.5, "The Night Listener": 3.0, }, "Gene Seymour": { "Lady in the Water": 3.0, "Snakes on a Plane": 3.5, "Just My Luck": 1.5, "Superman Returns": 5.0, "The Night Listener": 3.0, "You, Me and Dupree": 3.5, }, "Michael Phillips": { "Lady in the Water": 2.5, "Snakes on a Plane": 3.0, "Superman Returns": 3.5, "The Night Listener": 4.0, }, "Claudia Puig": { "Snakes on a Plane": 3.5, "Just My Luck": 3.0, "The Night Listener": 4.5, "Superman Returns": 4.0, "You, Me and Dupree": 2.5, }, "Mick LaSalle": { "Lady in the Water": 3.0, "Snakes on a Plane": 4.0, "Just My Luck": 2.0, "Superman Returns": 3.0, "The Night Listener": 3.0, "You, Me and Dupree": 2.0, }, "Jack Matthews": { "Lady in the Water": 3.0, "Snakes on a Plane": 4.0, "The Night Listener": 3.0, "Superman Returns": 5.0, "You, Me and Dupree": 3.5, }, "Toby": {"Snakes on a Plane": 4.5, "You, Me and Dupree": 1.0, "Superman Returns": 4.0}, } def cos_similarity(person1, person2): person1_reviews = dataset[person1] person2_reviews = dataset[person2] # 共通のタイトルを取得する。 common_titles = person1_reviews.keys() & person2_reviews.keys() if not common_titles: return 0 # 共通のタイトルが存在しない場合 # 共通のタイトルの点数をそれぞれ取得する。 scores1 = [person1_reviews[title] for title in common_titles] scores2 = [person2_reviews[title] for title in common_titles] for title, score1, score2 in zip(common_titles, scores1, scores2): print(f"title: {title} {person1}: {score1}点, {person2}: {score2}点") # コサイン類似度 cosΘ = <a, b>/(|a| |b|) cos_similarity = np.dot(scores1, scores2) / (np.linalg.norm(scores1) * np.linalg.norm(scores2)) return cos_similarity print(cos_similarity("Lisa Rose", "Jack Matthews"))

投稿2021/12/11 06:48

編集2021/12/11 06:52
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

handake

2021/12/14 07:55

回答ありがとうございます! なるほどです。tiitoiさんの回答のようにすれば共通したタイトルだけを取ってコサイン類似度をもとめられるんですね! 今回の場合だと共通していないタイトルは完全に無視している形ですが、共通していないタイトルを類似度に影響させる場合はそれぞれのユーザの評価をベクトルにすれば可能でしょうか?
tiitoi

2021/12/16 09:09

> 共通していないタイトルを類似度に影響させる場合はそれぞれのユーザの評価をベクトルにすれば可能でしょうか? 共通してないタイトルは、レビューしていない人のそのタイトルの点数を0にして計算すればいいと思います。
handake

2021/12/16 09:12

そうですね! 色々試しましたがtiitoiさんのおっしゃってるように未記入は0にしてみたら正しく動きました! 最後まで非常に丁寧にありがとうございます。助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問