Python で作る協調フィルタリング入門：カレー推薦システム

## はじめに
カレー好きの皆さん、こんにちは！「もっと自分好みのカレーに出会いたい」「友達にぴったりのカレーを提案したい」と思ったことはありませんか？今回は、そんな夢を叶える魔法のような AI 技術、「協調フィルタリング」を使って、カレー推薦システムを作ってみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/f005a4c4-dd5f-d5ec-4c3e-effd421499ec.png)

## この記事で学べること

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/bce95d9f-a829-e671-0e28-216652e7d403.png)

カレー好きの皆さん、協調フィルタリングを学ぶことで、こんな素敵な体験ができるんです：

1. **AIの実践的な使い方を知る**: 
   NetflixやAmazonなど、普段使っているサービスの裏側で動いているAI技術を、カレーという身近な題材で理解できます。難しそうなAIも、こうして実践的に学べば、とても親しみやすいものだとわかりますよ。

2. **個人の好みに合わせる技を習得**: 
   「この人にはこのカレーがぴったり！」というマッチングの裏側にある技術を学べます。これは、カレーショップのオーナーさんや、友達にぴったりのプレゼントを選びたい人にとって、とても役立つスキルになりますね。

3. **幅広い分野に応用できるアイデアが浮かぶ**: 
   カレーで学んだことを、音楽、本、旅行先の推薦など、様々な分野に応用するヒントが得られます。あなたの興味のある分野で、どんな風に活用できるか、想像が膨らむはずです。

この記事を読み進めるうちに、「へぇ、こんなことができるんだ！」「これ、〇〇にも使えそう！」というワクワク感が溢れてくると思います。AIを味方につけて、もっと楽しい毎日を過ごすためのヒントが、ここにはたくさん詰まっているんです。一緒に、AIの魔法で新しい発見の旅に出かけましょう！

## 実装手順

### 1. 準備：必要なライブラリのインポート

```python
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
```

これらのライブラリは、データ処理、数値計算、類似度計算、データの正規化、そしてグラフ描画に使用します。

### 2. データの用意：カレー評価データの作成

```python
data = {
    'User': ['User1', 'User2', 'User3', 'User4', 'User5'],
    'Butter Chicken': [4, 3, 5, 4, 2],
    'Green Curry': [5, 4, 2, 3, 1],
    'Beef Curry': [3, 5, 4, 3, 5],
    'Vegetable Curry': [2, 2, 1, 5, 4],
    'Keema Curry': [4, 3, 5, 2, 3]
}

ratings = pd.DataFrame(data).set_index('User')
print("Original ratings data:")
print(ratings)
```

ここでは、5人のユーザーと5種類のカレーに対する評価データを作成しています。実際のアプリケーションでは、このデータはユーザーからの実際の評価を集めて作成します。

### 3. 新しいユーザーの追加

```python
new_user_ratings = pd.Series({'Butter Chicken': 4, 'Green Curry': 0, 'Beef Curry': 5, 'Vegetable Curry': 0, 'Keema Curry': 3})
ratings.loc['NewUser'] = new_user_ratings
```

ここでは、推薦を受けたい新しいユーザー（NewUser）を追加しています。0の値は、そのカレーをまだ評価していないことを示します。

### 4. データの正規化

```python
scaler = StandardScaler()
normalized_ratings = pd.DataFrame(scaler.fit_transform(ratings), 
                                  columns=ratings.columns, 
                                  index=ratings.index)
print("\nNormalized ratings data:")
print(normalized_ratings)
```

データを正規化することで、評価のスケールを統一し、ユーザー間の比較を公平に行えるようにします。

### 5. 協調フィルタリング関数の実装

```python
def recommend_curry(user_ratings, target_user):
    # ユーザー間の類似度を計算
    user_similarity = cosine_similarity(user_ratings)
    user_similarity_df = pd.DataFrame(user_similarity, 
                                      index=user_ratings.index, 
                                      columns=user_ratings.index)
    
    # ターゲットユーザーの類似ユーザーを取得
    similar_users = user_similarity_df[target_user].sort_values(ascending=False)[1:]
    
    # 推薦スコアを計算
    recommendations = pd.Series(dtype=float)
    for curry in user_ratings.columns:
        if ratings.loc[target_user, curry] == 0:  # 評価していないカレー
            similar_users_ratings = ratings.loc[similar_users.index, curry]
            recommendation_score = np.average(similar_users_ratings, weights=similar_users)
            recommendations[curry] = recommendation_score
    
    return recommendations.sort_values(ascending=False)
```

この関数が協調フィルタリングの核心部分です。ユーザー間の類似度を計算し、類似したユーザーの評価を基に、まだ評価していないカレーの推薦スコアを算出します。

### 6. 推薦の実行と結果の表示

```python
recommendations = recommend_curry(normalized_ratings, 'NewUser')
print("\nRecommendations for NewUser:")
print(recommendations)
```

新しいユーザー（NewUser）に対する推薦を実行し、結果を表示します。

### 7. 結果の可視化

```python
if not recommendations.empty:
    plt.figure(figsize=(10, 6))
    recommendations.plot(kind='bar')
    plt.title('Curry Recommendation Scores for NewUser')
    plt.xlabel('Curry Types')
    plt.ylabel('Recommendation Score')
    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.show()
else:
    print("No recommendations to display.")
```

推薦結果をグラフで視覚化します。これにより、どのカレーがより強く推薦されているかが一目でわかります。

google colabでの実行例:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/6bf3ace8-62ce-573e-14f3-7e4abaa9e31a.png)


## 結果の解釈

実行結果を見ると、NewUserにはまだ評価していないGreen CurryとVegetable Curryが推薦されていることがわかります。推薦スコアが高いほど、そのカレーがNewUserの好みに合っている可能性が高いと言えます。

## 実用的な応用例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/b3abfdd3-87eb-ff72-ac7c-812d16c7e717.png)

1. **カレー店のメニュー開発**: お客様の好みを分析して、新メニューの方向性を決める。
2. **パーソナライズドメニュー**: スマホアプリで、各ユーザーにカスタマイズされたメニューを提案。
3. **マーケティング戦略**: 似た好みのユーザーグループにターゲットを絞った広告配信。

## 発展的な課題

1. **特徴量の追加**: カレーの辛さや具材などの特徴を考慮した推薦システムに拡張してみましょう。
2. **ハイブリッドアプローチ**: コンテンツベースのフィルタリングと組み合わせて、より精度の高い推薦システムを作ってみましょう。
3. **大規模データへの対応**: 実際のビジネスでは大量のユーザーとアイテムがあります。スケーラビリティを考慮したシステムに改良してみましょう。

## まとめ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/0bac7e1d-a33c-ef66-5a34-ae856ebe8b85.png)

協調フィルタリングを使えば、このように簡単に個人化された推薦システムが作れます。カレーだけでなく、様々な分野で活用できるこの技術を、ぜひ自分なりにアレンジしてみてください。AI 技術を味方につけて、あなただけの究極のカレーライフを楽しんでくださいね。Happy Coding & Curry Time!


# 参考情報と更なる学習のために

この章では、本記事の内容に関連する参考資料や、協調フィルタリングについてさらに学ぶためのリソースを紹介します。

## 学術論文

1. Sarwar, B., Karypis, G., Konstan, J., & Riedl, J. (2001). Item-based collaborative filtering recommendation algorithms. In Proceedings of the 10th international conference on World Wide Web (pp. 285-295).
   - 項目ベースの協調フィルタリングアルゴリズムの基礎となる重要な論文です。

2. Koren, Y., Bell, R., & Volinsky, C. (2009). Matrix factorization techniques for recommender systems. Computer, 42(8), 30-37.
   - 推薦システムにおける行列分解技術について詳しく解説しています。

## 書籍

1. Aggarwal, C. C. (2016). Recommender Systems: The Textbook. Springer.
   - 推薦システムに関する包括的な教科書で、協調フィルタリングについても詳しく解説しています。

2. Ricci, F., Rokach, L., & Shapira, B. (Eds.). (2015). Recommender Systems Handbook (2nd ed.). Springer.
   - 推薦システムの様々な側面を網羅した専門家向けのハンドブックです。

## ビジネス事例

1. Netflix: 映画・ドラマ推薦システム
   - [Netflix Technology Blog: Netflix Recommendations: Beyond the 5 stars (Part 1)](https://netflixtechblog.com/netflix-recommendations-beyond-the-5-stars-part-1-55838468f429)

2. Amazon: 商品推薦システム
   - Linden, G., Smith, B., & York, J. (2003). Amazon.com recommendations: Item-to-item collaborative filtering. IEEE Internet computing, 7(1), 76-80.
   - [Google Scholar で検索](https://scholar.google.com/scholar?q=Amazon.com+recommendations:+Item-to-item+collaborative+filtering)

## 関連するPythonライブラリ

1. Surprise: 推薦システム用のPythonライブラリ
   [http://surpriselib.com/](http://surpriselib.com/)

2. LightFM: ハイブリッド推薦システムのためのPythonライブラリ
   [https://making.lyst.com/lightfm/docs/home.html](https://making.lyst.com/lightfm/docs/home.html)

これらの参考資料を活用することで、協調フィルタリングやカレー推薦システムについてより深く学ぶことができます。また、実際のビジネス事例を参考にすることで、この技術の実用的な応用方法についても理解を深めることができるでしょう。

## 実装(まとめ)

```python
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
import matplotlib.pyplot as plt

# Curry rating data
data = {
    'User': ['User1', 'User2', 'User3', 'User4', 'User5'],
    'Butter Chicken Curry': [4, 3, 5, 4, 2],
    'Green Curry': [5, 4, 2, 3, 1],
    'Beef Curry': [3, 5, 4, 3, 5],
    'Vegetable Curry': [2, 2, 1, 5, 4],
    'Keema Curry': [4, 3, 5, 2, 3]
}

ratings = pd.DataFrame(data).set_index('User')
print(ratings)

def recommend_curry(user_ratings, target_user):
    user_similarity = cosine_similarity(user_ratings)
    user_similarity_df = pd.DataFrame(user_similarity, index=user_ratings.index, columns=user_ratings.index)

    similar_users = user_similarity_df[target_user].sort_values(ascending=False)[1:]

    recommendations = pd.Series()
    for curry in user_ratings.columns:
        if user_ratings.loc[target_user, curry] == 0:
            similar_users_ratings = user_ratings.loc[similar_users.index, curry]
            recommendation_score = np.average(similar_users_ratings, weights=similar_users)
            recommendations[curry] = recommendation_score

    return recommendations.sort_values(ascending=False)

new_user_ratings = pd.Series({'Butter Chicken Curry': 4, 'Green Curry': 0, 'Beef Curry': 5, 'Vegetable Curry': 0, 'Keema Curry': 3})
ratings.loc['NewUser'] = new_user_ratings

recommendations = recommend_curry(ratings, 'NewUser')
print("Curry recommendations for NewUser:")
print(recommendations)

# Plot the recommendations
plt.figure(figsize=(10, 6))
recommendations.plot(kind='bar')
plt.title('Curry Recommendation Scores for NewUser')
plt.xlabel('Curry Types')
plt.ylabel('Recommendation Score')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
```