相互推薦アルゴリズム

https://note.com/kuriyama_data/n/n0eb0f982916c

https://developers.cyberagent.co.jp/blog/archives/35119/

https://note.com/shintaro_shimizu/n/n2dc02a392b2e

https://speakerdeck.com/cyberagentdevelopers/matutinguapuriniokerutui-jian-sisutemu
```python
# Program Name: reciprocal_recommendation_simulation.py
# Creation Date: 20250603
# Overview: Simulate reciprocal recommendation using dummy data in a dating app context
# Usage: Run in Python environment (e.g., Jupyter, Google Colab)

# -------------------- Install Required Libraries --------------------
!pip install pandas numpy matplotlib scikit-learn

# -------------------- Import Libraries --------------------
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics.pairwise import cosine_similarity

# -------------------- Parameter Settings --------------------
np.random.seed(42)  # 再現性のための乱数シード / Random seed for reproducibility
n_users = 10        # ユーザー数 / Number of users
n_features = 5      # 特徴量数（年齢、学歴、性格など）/ Number of user profile features

# -------------------- Generate Dummy User Data --------------------
# ランダムにユーザー属性を生成 / Generate user features randomly
user_features = np.random.rand(n_users, n_features)
user_df = pd.DataFrame(user_features, columns=[f"Feature_{i+1}" for i in range(n_features)])
user_df["User_ID"] = [f"User_{i+1}" for i in range(n_users)]

# -------------------- Simulate User Preferences --------------------
# 各ユーザーが「いいね」した過去の相手（ランダムに3人）を記録 / Each user likes 3 others randomly
like_history = {}
for i in range(n_users):
    others = list(set(range(n_users)) - {i})
    liked = np.random.choice(others, 3, replace=False)
    like_history[i] = liked

# ユーザーごとの嗜好ベクトルを作成（過去にいいねした相手の平均ベクトル） / Compute preference vector from like history
preference_vectors = np.zeros((n_users, n_features))
for i in range(n_users):
    liked_indices = like_history[i]
    preference_vectors[i] = user_features[liked_indices].mean(axis=0)

# -------------------- Compute Reciprocal Scores --------------------
# 各ユーザーの嗜好ベクトルと他ユーザーの特徴ベクトルの類似度（cos類似度）を使う / Use cosine similarity
similarity_matrix = cosine_similarity(preference_vectors, user_features)

# マッチ確率行列：調和平均を使って相互性を考慮 / Use harmonic mean of both directions
match_prob_matrix = np.zeros((n_users, n_users))
for i in range(n_users):
    for j in range(n_users):
        if i == j:
            continue
        p_ij = similarity_matrix[i, j]
        p_ji = similarity_matrix[j, i]
        match_prob_matrix[i, j] = 2 * p_ij * p_ji / (p_ij + p_ji) if (p_ij + p_ji) > 0 else 0

# -------------------- Visualize Matching Probability --------------------
plt.figure(figsize=(8, 6))
plt.imshow(match_prob_matrix, cmap="Blues", interpolation="nearest")
plt.title("Reciprocal Match Probability Matrix")
plt.xlabel("Target User")
plt.ylabel("Source User")
plt.colorbar(label="Matching Probability")
plt.xticks(ticks=np.arange(n_users), labels=[f"U{i+1}" for i in range(n_users)], rotation=45)
plt.yticks(ticks=np.arange(n_users), labels=[f"U{i+1}" for i in range(n_users)])
plt.tight_layout()
plt.show()

# -------------------- Top Recommendations --------------------
# 各ユーザーに対して最もマッチ確率の高い相手を推薦 / Recommend top match for each user
recommendations = {}
for i in range(n_users):
    match_probs = match_prob_matrix[i].copy()
    match_probs[i] = -1  # 自分自身を除外 / Exclude self
    best_match = np.argmax(match_probs)
    recommendations[f"User_{i+1}"] = f"User_{best_match+1}"

# 推薦結果を表示 / Display recommendations
recommendation_df = pd.DataFrame.from_dict(recommendations, orient="index", columns=["Recommended Match"])
display(recommendation_df)
```
```python
# Program Name: tappuru_recommendation_simulation.py
# Creation Date: 20250603
# Overview: Simulate Tapple-style mutual recommendation using collaborative filtering and interest scores
# Usage: Run in Python environment (e.g., Jupyter, Google Colab)

# -------------------- Install Required Libraries --------------------
!pip install numpy pandas matplotlib scikit-learn

# -------------------- Import Libraries --------------------
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics.pairwise import cosine_similarity

# -------------------- Parameter Settings --------------------
np.random.seed(42)     # 乱数のシードを固定 / Random seed
n_men = 10             # 男性ユーザー数 / Number of male users
n_women = 10           # 女性ユーザー数 / Number of female users
n_features = 5         # ユーザーの特徴量数 / Number of profile features

# -------------------- Generate Dummy User Data --------------------
# 男性と女性の属性ベクトルを生成 / Generate profile features
men_features = np.random.rand(n_men, n_features)
women_features = np.random.rand(n_women, n_features)

# 各ユーザーID / User IDs
men_ids = [f"Man_{i}" for i in range(n_men)]
women_ids = [f"Woman_{i}" for i in range(n_women)]

# -------------------- Simulate Interaction History --------------------
# 「いいかも！」履歴（確率的に生成） / Simulate like-history
like_prob_matrix = cosine_similarity(men_features, women_features)
like_matrix = (like_prob_matrix > np.quantile(like_prob_matrix, 0.7)).astype(int)  # 上位30%を1とする

# 「ありがとう」履歴（逆方向） / Simulate return likes ("Thank you")
thank_matrix = (like_prob_matrix.T > np.quantile(like_prob_matrix, 0.7)).astype(int)

# -------------------- Calculate Mutual Interest Scores --------------------
# 双方向の興味スコア（調和平均）/ Harmonic mean of bidirectional interest
mutual_interest = np.zeros((n_men, n_women))
for i in range(n_men):
    for j in range(n_women):
        p_ij = like_prob_matrix[i, j]
        p_ji = like_prob_matrix.T[j, i]
        mutual_interest[i, j] = 2 * p_ij * p_ji / (p_ij + p_ji) if (p_ij + p_ji) > 0 else 0

# -------------------- Recommend Top-K Matches --------------------
top_k = 3  # 推薦数 / Number of recommendations
recommendations = {}
for i, man in enumerate(men_ids):
    top_indices = mutual_interest[i].argsort()[::-1][:top_k]
    recommendations[man] = [women_ids[j] for j in top_indices]

# -------------------- Display Recommendations --------------------
recommendation_df = pd.DataFrame.from_dict(recommendations, orient='index')
recommendation_df.columns = [f"Recommendation_{i+1}" for i in range(top_k)]
display(recommendation_df)

# -------------------- Visualize Mutual Interest --------------------
plt.figure(figsize=(10, 6))
plt.imshow(mutual_interest, cmap='YlGnBu')
plt.title("Mutual Interest Score (Man → Woman)")
plt.xlabel("Woman ID")
plt.ylabel("Man ID")
plt.colorbar(label="Mutual Interest Score")
plt.xticks(ticks=np.arange(n_women), labels=women_ids, rotation=45)
plt.yticks(ticks=np.arange(n_men), labels=men_ids)
plt.tight_layout()
plt.show()

```

```python
# Program Name: recommendation_type_simulation.py
# Creation Date: 20250603
# Overview: Compare item-to-user vs reciprocal recommendation logic using Python simulation
# Usage: Run in Python environment to visualize recommendation outcomes

# -------------------- Install Required Libraries --------------------
!pip install pandas numpy matplotlib seaborn

# -------------------- Import Libraries --------------------
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# -------------------- Parameter Settings --------------------
np.random.seed(42)
n_users = 10
n_items = 5

# -------------------- Item-to-User Recommendation --------------------
# 各ユーザーのアイテムに対するスコアをランダム生成 / Generate satisfaction scores
item_scores = np.random.rand(n_users, n_items)
item_df = pd.DataFrame(item_scores, columns=[f"Item_{i+1}" for i in range(n_items)])
item_df["User"] = [f"User_{i+1}" for i in range(n_users)]

# 各ユーザーごとに最高スコアのアイテムを推薦 / Recommend top-1 item per user
item_df["Recommended_Item"] = item_df[[f"Item_{i+1}" for i in range(n_items)]].idxmax(axis=1)
item_df["Max_Score"] = item_df[[f"Item_{i+1}" for i in range(n_items)]].max(axis=1)

# -------------------- Reciprocal Recommendation --------------------
# 相互推薦ではユーザー同士の関係性スコアをランダム生成 / Mutual affinity matrix
mutual_scores = np.random.rand(n_users, n_users)
np.fill_diagonal(mutual_scores, 0)  # 自分とのマッチは除外

rec_match = []
for i in range(n_users):
    for j in range(i+1, n_users):
        score_i_j = mutual_scores[i, j]
        score_j_i = mutual_scores[j, i]
        harmonic = 2 * score_i_j * score_j_i / (score_i_j + score_j_i) if (score_i_j + score_j_i) > 0 else 0
        rec_match.append({"User_1": f"User_{i+1}", "User_2": f"User_{j+1}", "Mutual_Score": harmonic})

rec_df = pd.DataFrame(rec_match).sort_values(by="Mutual_Score", ascending=False).head(10)

# -------------------- Visualize --------------------
plt.figure(figsize=(8, 6))
sns.heatmap(mutual_scores, xticklabels=[f"U{i+1}" for i in range(n_users)],
            yticklabels=[f"U{i+1}" for i in range(n_users)], cmap="coolwarm", annot=True, fmt=".2f")
plt.title("Mutual Affinity Matrix (Reciprocal Recommendation)")
plt.xlabel("User j")
plt.ylabel("User i")
plt.tight_layout()
plt.show()

# -------------------- Display Results --------------------
print("▼ item-to-user推薦結果 (Top item per user)")
display(item_df[["User", "Recommended_Item", "Max_Score"]])

print("▼ 相互推薦のスコア上位10組 (Harmonic Mean based)")
display(rec_df)

```