レコメンダー システムでのピアソン相関係数の使用について質問があります。
現在、データベースに 3 つのコレクションがあります。1 つはユーザー用、1 つはレストラン用、1 つはレビュー用です。
私は、2 人のユーザー ID と送信されたレビューのリストを受け取り、送信したレビューに基づく 2 人のユーザー間のピアソン相関係数である double を返す関数を作成しました。
したがって、関数が行うことは、ユーザーが送信したすべてのレビューの 2 つのリストを作成することです。次に、同じレストランに残されたレビューがあるかどうかを for ループがチェックし、これらのレビューをリストに配置します。このリストは、係数の計算に使用されます。
この係数を正しい方法で使用しているかどうかを知りたかっただけです。最初のユーザーにおすすめしたい。この係数を、別のユーザーに適合する人物の良い指標として使用できますか?
また、ユーザーを一致させる方法が適切でない場合、より良い方法は何でしょうか?
疑問に思われる方のために、係数を計算する関数を次に示します。
public static double CalculatePearsonCorrelation(Guid userId1, List<Review> user1Reviews,
Guid userId2, List<Review> user2Reviews)
{
//Resetting the dictionary
restaurantRecommendations = new Dictionary<Guid, List<Review>>();
//Matching the reviews with the corresponding user
restaurantRecommendations.Add(userId1, user1Reviews);
restaurantRecommendations.Add(userId2, user2Reviews);
//Check if users have enough reviews to get a correct correlation
if (restaurantRecommendations[userId1].Count < 4)
throw new NotEnoughReviewsException("UserId " + userId1 + " doesn't contain enough reviews for this correlation");
if (restaurantRecommendations[userId2].Count < 4)
throw new NotEnoughReviewsException("UserId " + userId2 + " doesn't contain enough reviews for this correlation");
//This will be the list of reviews that are the same per subject for the two users.
List<Review> shared_items = new List<Review>();
//Loops through the list of reviews of the selected user (userId1)
foreach (var item in restaurantRecommendations[userId1])
{
//Checks if they have any reviews on subjects in common
if (restaurantRecommendations[userId2].Where(x => x.subj.Id == item.subj.Id).Count() != 0)
{
//Adds these reviews to a list on which the correlation will be based
shared_items.Add(item);
}
}
//If they don't have anything in common, the correlation will be 0
if (shared_items.Count() == 0)
return 0;
//I decided users need at least 4 subjects in common, else there won't be an accurate correlation
if (shared_items.Count() < 4)
throw new NotEnoughReviewsException("UserId " + userId1 + " and UserId " + userId2 + " don't have enough reviews in common for a correlation");
////////////////////////// Calculating the pearson correlation //////////////////////////
double product1_review_sum = 0.00f;
double product2_review_sum = 0.00f;
double product1_rating = 0f;
double product2_rating = 0f;
double critics_sum = 0f;
foreach (Review item in shared_items)
{
product1_review_sum += restaurantRecommendations[userId1].Where(x => x.subj.Id == item.subj.Id).FirstOrDefault().rating;
product2_review_sum += restaurantRecommendations[userId2].Where(x => x.subj.Id == item.subj.Id).FirstOrDefault().rating;
product1_rating += Math.Pow(restaurantRecommendations[userId1].Where(x => x.subj.Id == item.subj.Id).FirstOrDefault().rating, 2);
product2_rating += Math.Pow(restaurantRecommendations[userId2].Where(x => x.subj.Id == item.subj.Id).FirstOrDefault().rating, 2);
critics_sum += restaurantRecommendations[userId1].Where(x => x.subj.Id == item.subj.Id).FirstOrDefault().rating *
restaurantRecommendations[userId2].Where(x => x.subj.Id == item.subj.Id).FirstOrDefault().rating;
}
//Calculate pearson correlation
double num = critics_sum - (product1_review_sum * product2_review_sum / shared_items.Count);
double density = Math.Sqrt((product1_rating - Math.Pow(product1_review_sum, 2) / shared_items.Count) *
((product2_rating - Math.Pow(product2_review_sum, 2) / shared_items.Count)));
if (density == 0)
return 0;
return num / density;
}
}