楽曲レコメンドアプリ作ってみた！

# はじめに


Streamlitで楽曲レコメンドアプリを作成しました。[データセット](https://www.kaggle.com/competitions/kkbox-music-recommendation-challenge/data)はKaggleで公開されているものを利用しました。
[Streamlit Cloud](https://recomusic.streamlit.app/)で公開しています。


## データセットの加工

データセットにはKaggleで公開されているものを利用しました。KKBOXという音楽レコメンドサービスのデータセットでいくつかのcsvファイルに分割されて提供されています。今回はすべてのデータセットを結合した後にレコメンドに使いたいカラムを抽出して加工しました。また、データセットの`language`カラムを日本語に指定して、日本の楽曲に限定しています。
```python:data_process.py
import pandas as pd

train = pd.read_csv('/train.csv')
songs = pd.read_csv('/songs.csv')
members = pd.read_csv('/members.csv')
song_ex = pd.read_csv('/song_extra_info.csv')

merge1 = pd.merge(train, songs, on = 'song_id', how = 'left')
merge2 = pd.merge(merge1, members, on = 'msno', how = 'left')
origin_data = pd.merge(merge2, song_ex, on = 'song_id', how = 'left')
del train, songs, members, song_ex, merge1, merge2

origin_data.isnull().sum()
features = ['msno', 'name', 'language', 'artist_name', 'composer', 'lyricist']

origin_data['language'].unique()

data = origin_data[features].dropna()

# language = 17.0 が日本語
j_song = data[data['language'] == 17.0]
jp_song = j_song.copy()

jp_data = jp_song.drop('language', axis=1)
jp_data = jp_data.rename(columns={'msno': 'user_id', 'name': 'song_name'})

# '\u3000'(全角スペースの文字コード)を半角スペースで置換
jp_data['song_name'] = jp_data['song_name'].str.replace('\u3000', ' ')
jp_data['song_name'] = jp_data['song_name'].str.replace('\|', '')
jp_data['artist_name'] = jp_data['artist_name'].str.replace('\u3000', ' ')
jp_data['composer'] = jp_data['composer'].str.replace('\u3000', ' ')
jp_data['lyricist'] = jp_data['lyricist'].str.replace('\u3000', ' ')


music_data = jp_data.drop('user_id', axis=1)
music_data = music_data.drop_duplicates().sort_values('song_name').reset_index(drop=True)

# ファイル出力
# jp_data.to_csv('data.csv', index=False)

# アプリで4種類から選択できるようにする
song_name = sorted(list(set(jp_data['song_name'].tolist())))
artist = sorted(list(set(jp_data['artist_name'].tolist())))
composer = sorted(list(set(jp_data['composer'].tolist())))
lyricist = sorted(list(set(jp_data['lyricist'].tolist())))

# userが聞いた曲
unique = jp_data.groupby('user_id').agg({'song_name': list})
listened_list = unique['song_name'].tolist()

result = []
for i in range(len(listened_list)):
  if song_name[0] in listened_list[i]:
    if len(listened_list[i]) >=  2:
      result += listened_list[i]
print(result)

import collections
c = collections.Counter(result)
values, counts = zip(*c.most_common(3))
print(values, counts)

recommend_df = pd.DataFrame()
for j in range(len(values)):
  recommend_info = music_data[music_data['song_name'].isin([values[j]])]
  df_new = pd.DataFrame(recommend_info)
  recommend_df = pd.concat([recommend_df, df_new])
```

## 実装

私自身が初心者だったのではじめから目標物を完成させることは意識せずに、とりあえずアプリの大枠を作成し、随時機能を追加していくという方針で進めていきました。
レコメンド方法は概要レコメンドで自分が聞いた曲を聞いた他のユーザーはどんな曲を聞いているか推薦する仕組みです。
![スクリーンショット 2023-11-08 20.33.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559951/19b9a61e-5045-d7f3-5ea9-acec088a8b24.png)
実装部分を載せると記事が見にくくなると思ったので気になる方は[Streamlit Cloud](https://recomusic.streamlit.app/)のGitHubアイコンからご覧ください。
## 頑張ったこと

今回が初めてのWebアプリ作成でAPIも使ってみたいと思い、[Youtube Data API](https://developers.google.com/youtube/v3?hl=jaz)を使用しました。
レコメンドされた楽曲のYoutube上で個々に割り振られている`video ID`をAPIから取得し、その`video ID`をURLに結合して楽曲に関連した動画にアクセスできるようにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559951/893e4ebb-7e16-b2a1-e189-08b02efca55a.png)

## 良くない点
データセットが海外のもので日本の楽曲に絞り込んでも中国語表記だったり、半角スペースの有無で楽曲がダブったり、曲名がローマ字表記だったり、など楽曲を選択するところ場面でUXが悪いと感じています。

## 最後に
初心者にしては実際に動くものを作れてこれがプログラミングの醍醐味かと感銘しています。知識のインプットばかりするのではなく、なにか作ることを目的に設定して、インプットしていけばアウトプットにもなるし、と改めて学習方法を考え直すきっかけになりました。