- ์ถ์ฒ์์คํ ์ ๊ฐ๋ ๊ณผ ๋ชฉ์ ์ ์ดํดํ๋ค.
- Implicit ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํ์ฌ Matrix Factorization(์ดํ MF) ๊ธฐ๋ฐ์ ์ถ์ฒ ๋ชจ๋ธ์ ๋ง๋ค์ด ๋ณธ๋ค.
- ์์ ๊ฐ์ ๊ธฐ๋ก์ ํ์ฉํ์ฌ ๋น์ทํ ์ํฐ์คํธ๋ฅผ ์ฐพ๊ณ ์ํฐ์คํธ๋ฅผ ์ถ์ฒํด ๋ณธ๋ค.
- ์ถ์ฒ ์์คํ ์์ ์์ฃผ ์ฌ์ฉ๋๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ธ CSR Matrix์ ์ตํ๋ค
- ์ ์ ์ ํ์ ๋ฐ์ดํฐ ์ค Explicit data์ Implicit data์ ์ฐจ์ด์ ์ ์ตํ๋ค.
- ์๋ก์ด ๋ฐ์ดํฐ์ ์ผ๋ก ์ง์ ์ถ์ฒ ๋ชจ๋ธ์ ๋ง๋ค์ด ๋ณธ๋ค.
์ถ์ฒ์์คํ ์ด๋, ๋ฐ์ดํฐ๋ฅผ ๋ฐํ์ผ๋ก ์ ์ ๊ฐ ์ข์ํ ๋งํ ์ฝํ ์ธ ๋ฅผ ์ฐพ์์ ์๋์ผ๋ก ๋ณด์ฌ์ฃผ๊ฑฐ๋ ์ถ์ฒํด์ฃผ๋ ๊ธฐ๋ฅ์ด๋ค. ์ถ์ฒ์์คํ ์ ์๋ฆฌ๋ ๊ฐ๋จํ๊ฒ ์ค๋ช ํ๋ฉด ๋์ ๋น์ทํ ๋ค๋ฅธ ์ฌ์ฉ์๋ค์ด ์ข์ํ๋ ๊ฒ๊ณผ ๋น์ทํ ๊ฒ์ ๋ด๊ฒ ์ถ์ฒํด์ค๋ค๋ ๊ฒ์ด๋ค. ์ด๋ฌํ ์ถ์ฒ์์คํ ์ ํฌ๊ฒ ๋ ๊ฐ์ง๋ก ๋๋๋ค.
http://www.kocca.kr/insight/vol05/vol05_04.pdf
ํ์ ํํฐ๋ง์ด๋ ๋๊ท๋ชจ์ ๊ธฐ์กด ์ฌ์ฉ์ ํ๋ ์ ๋ณด๋ฅผ ๋ถ์ํ์ฌ ํด๋น ์ฌ์ฉ์์ ๋น์ทํ ์ฑํฅ์ ์ฌ์ฉ์๋ค์ด ๊ธฐ์กด์ ์ข์ํ๋ ํญ๋ชฉ์ ์ถ์ฒํ๋ ๊ธฐ์ ์ด๋ค.
- ์ฅ์
- ๊ฒฐ๊ณผ๊ฐ ์ง๊ด์ ์ด๋ฉฐ ํญ๋ชฉ์ ๊ตฌ์ฒด์ ์ธ ๋ด์ฉ์ ๋ถ์ํ ํ์๊ฐ ์๋ค.
- ๋จ์
- ์ฝ๋ ์คํํธ(Cold Start)๋ฌธ์ ๊ฐ ์๋ค.
- ๊ณ์ฐ๋์ด ๋น๊ต์ ๋ง์ ์๊ณ ๋ฆฌ์ฆ์ด๋ฏ๋ก ์ฌ์ฉ์ ์๊ฐ ๋ง์ ๊ฒฝ์ฐ ํจ์จ์ ์ผ๋ก ์ถ์ฒํ ์ ์๋ค.
- ์์คํ ํญ๋ชฉ์ด ๋ง๋ค ํ๋๋ผ๋ ์ฌ์ฉ์๋ค์ ์์์ ์ธ๊ธฐ์๋ ํญ๋ชฉ์๋ง ๊ด์ฌ์ ๋ณด์ด๋ ๋กฑํ ์ผ(Long tail)๋ฌธ์ ๊ฐ ์๋ค.
- ํ๋ ฌ๋ถํด(Matrix Factorization), k-์ต๊ทผ์ ์ด์ ์๊ณ ๋ฆฌ์ฆ (k-Nearest Neighbor algorithm; kNN) ๋ฑ์ ๋ฐฉ๋ฒ์ด ๋ง์ด ์ฌ์ฉ๋๋ค.
์ฝํ ์ธ ๊ธฐ๋ฐ ํํฐ๋ง์ ํญ๋ชฉ ์์ฒด๋ฅผ ๋ถ์ํ์ฌ ์ถ์ฒ์ ๊ตฌํํ๋ค. ์๋ฅผ ๋ค์ด ์์ ์ ์ถ์ฒํ๊ธฐ ์ํด ์์ ์์ฒด๋ฅผ ๋ถ์ํ์ฌ ์ ์ฌํ ์์ ์ ์ถ์ฒํ๋ ๋ฐฉ์์ด๋ค.
์ฝํ ์ธ ๊ธฐ๋ฐ ํํฐ๋ง์ ์ํด์๋ ํญ๋ชฉ์ ๋ถ์ํ ํ๋กํ์ผ(item profile)๊ณผ ์ฌ์ฉ์์ ์ ํธ๋๋ฅผ ์ถ์ถํ ํ๋กํ์ผ(user profile)์ ์ถ์ถํ์ฌ ์ด์ ์ ์ฌ์ฑ์ ๊ณ์ฐํ๋ค. ์ ๋ช ํ ์์ ์ฌ์ดํธ์ธ ํ๋ ๋ผ(Pandora)์ ๊ฒฝ์ฐ, ์ ๊ณก์ด ์ถ์๋๋ฉด ์์ ์ ๋ถ์ํ์ฌ ์ฅ๋ฅด, ๋นํธ, ์์ ๋ฑ ์ฝ 400์ฌ ํญ๋ชฉ์ ํน ์ฑ์ ์ถ์ถํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์๋ก๋ถํฐ๋ โlikeโ๋ฅผ ๋ฐ์ ์์ ์ ํน์์ ๋ฐํ์ผ๋ก ํด๋น ์ฌ์ฉ์์ ํ๋ก ํ์ผ์ ์ค๋นํ๋ค. ์ด๋ฌํ ์์ ์ ํน์ฑ๊ณผ ์ฌ์ฉ์ ํ๋กํ์ผ์ ๋น๊ตํจ์ผ๋ก์จ ์ฌ์ฉ์๊ฐ ์ ํธํ ๋งํ ์์ ์ ์ ๊ณตํ๊ฒ ๋๋ค.
- ๊ตฐ์ง๋ถ์(Clustering analysis), ์ธ๊ณต์ ๊ฒฝ๋ง(Artificial neural network), tf-idf(term frequencyinverse document frequency) ๋ฑ์ ๊ธฐ์ ์ด ์ฌ์ฉ๋๋ค.
์ถ์ฒ์์คํ ์ ์์ดํ ์ ๋งค์ฐ ๋ง๊ณ , ์ ์ ์ ์ทจํฅ์ ๋ค์ํ ๋ ์ ์ ๊ฐ ์๋นํ ๋งํ ์์ดํ ์ ์์ธกํ๋ ๋ชจ๋ธ์ด๋ค.
- ์ ํ๋ธ : ๋์์์ด ๋งค์ผ ์์ฒญ๋๊ฒ ๋ง์ด ์ฌ๋ผ์ค๊ณ ์ ์ ์ ์ทจํฅ(๊ฒ์ ์ ํธ, ๋ทฐํฐ ์ ํธ, ์ง์ ์ ํธ, ๋ด์ค ์ ํธ)์ด ๋ค์
- ํ์ด์ค๋ถ : ํฌ์คํ ๋๋ ๊ธ์ด ์์ฒญ ๋ง๊ณ ์ ์ ๊ฐ ๊ด์ฌ ์๋ ํ์ด์ง, ์น๊ตฌ, ๊ทธ๋ฃน์ ์ ๋ถ ๋ค๋ฆ
- ์๋ง์กด : ์นดํ ๊ณ ๋ฆฌ๋ฅผ ํ์ ํด๋ ํ๋งค ํ๋ชฉ์ด ์์ฒญ ๋ง๊ณ ์ข์ํ๋ ๋ธ๋๋, ๊ตฌ๋งค ๊ธฐ์ค์ด ๋ค์
http://ocelma.net/MusicRecommendationDataset/lastfm-360K.html ๋ฐ์ดํฐ์ ํํ์ด์ง
# ํ์ผ ๋ถ๋ฌ์ค๊ธฐ
import pandas as pd
import os
fname = os.getenv('HOME') + '/aiffel/recommendata_iu/data/lastfm-dataset-360K/usersha1-artmbid-artname-plays.tsv'
col_names = ['user_id', 'artist_MBID', 'artist', 'play'] # ์์๋ก ์ง์ ํ ์ปฌ๋ผ๋ช
data = pd.read_csv(fname, sep='\t', names= col_names) # sep='\t'
data.head(10)
# ์ฌ์ฉํ๋ ์ปฌ๋ผ ์ฌ์ ์
using_cols = ['user_id', 'artist', 'play']
data = data[using_cols]
data.head(10)
data['artist'] = data['artist'].str.lower() # ๊ฒ์์ ์ฝ๊ฒํ๊ธฐ ์ํด ์ํฐ์คํธ ๋ฌธ์์ด์ ์๋ฌธ์๋ก ๋ณ๊ฒฝ
data.head(10)
# ์ฒซ ๋ฒ์งธ ์ ์ ๋ฐ์ดํฐ ํ์ธ
condition = (data['user_id']== data.loc[0, 'user_id'])
data.loc[condition]
ํ์ธ์ด ํ์ํ ์ ๋ณด
- ์ ์ ์, ์ํฐ์คํธ์, ์ธ๊ธฐ ๋ง์ ์ํฐ์คํธ
- ์ ์ ๋ค์ด ๋ช ๋ช ์ ์ํฐ์คํธ๋ฅผ ๋ฃ๊ณ ์๋์ง์ ๋ํ ํต๊ณ
- ์ ์ play ํ์ ์ค์๊ฐ์ ๋ํ ํต๊ณ
# ์ ์ ์
data['user_id'].nunique()
# ์ํฐ์คํธ ์
data['artist'].nunique()
# ์ธ๊ธฐ ๋ง์ ์ํฐ์คํธ
artist_count = data.groupby('artist')['user_id'].count()
artist_count.sort_values(ascending=False).head(30)
# ์ ์ ๋ณ ๋ช ๋ช
์ ์ํฐ์คํธ๋ฅผ ๋ฃ๊ณ ์๋์ง์ ๋ํ ํต๊ณ
user_count = data.groupby('user_id')['artist'].count()
user_count.describe()
# ์ ์ ๋ณ playํ์ ์ค์๊ฐ์ ๋ํ ํต๊ณ
user_median = data.groupby('user_id')['play'].median()
user_median.describe()
# ์ด๋ฆ์ ๊ผญ ๋ฐ์ดํฐ์
์ ์๋ ๊ฒ์ผ๋ก
my_favorite = ['black eyed peas' , 'maroon5' ,'jason mraz' ,'coldplay' ,'beyoncรฉ']
# 'zimin'์ด๋ผ๋ user_id๊ฐ ์ ์ํฐ์คํธ์ ๋
ธ๋๋ฅผ 30ํ์ฉ ๋ค์๋ค๊ณ ๊ฐ์
my_playlist = pd.DataFrame({'user_id': ['zimin']*5, 'artist': my_favorite, 'play':[30]*5})
if not data.isin({'user_id':['zimin']})['user_id'].any(): # user_id์ 'zimin'์ด๋ผ๋ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด
data = data.append(my_playlist) # ์์ ์์๋ก ๋ง๋ my_favorite ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐ
data.tail(10) # ์ ์ถ๊ฐ๋์๋์ง ํ์ธ
๋ฐ์ดํฐ์ ๊ด๋ฆฌ๋ฅผ ์ฝ๊ฒ ํ๊ธฐ ์ํด indexing ์์ ์ ํด์ค๋ค.
# ๊ณ ์ ํ ์ ์ , ์ํฐ์คํธ๋ฅผ ์ฐพ์๋ด๋ ์ฝ๋
user_unique = data['user_id'].unique()
artist_unique = data['artist'].unique()
# ์ ์ , ์ํฐ์คํธ indexing ํ๋ ์ฝ๋ idx๋ index์ ์ฝ์
user_to_idx = {v:k for k,v in enumerate(user_unique)}
artist_to_idx = {v:k for k,v in enumerate(artist_unique)}
# ์ธ๋ฑ์ฑ์ด ์ ๋์๋์ง ํ์ธํด ๋ด
๋๋ค.
print(user_to_idx['zimin']) # 358869๋ช
์ ์ ์ ์ค ๋ง์ง๋ง์ผ๋ก ์ถ๊ฐ๋ ์ ์ ์ด๋ 358868์ด ๋์์ผ ํฉ๋๋ค.
print(artist_to_idx['black eyed peas'])
# indexing์ ํตํด ๋ฐ์ดํฐ ์ปฌ๋ผ ๋ด ๊ฐ์ ๋ฐ๊พธ๋ ์ฝ๋
# dictionary ์๋ฃํ์ get ํจ์๋ https://wikidocs.net/16 ์ ์ฐธ๊ณ ํ์ธ์.
# user_to_idx.get์ ํตํด user_id ์ปฌ๋ผ์ ๋ชจ๋ ๊ฐ์ ์ธ๋ฑ์ฑํ Series๋ฅผ ๊ตฌํด ๋ด
์๋ค.
# ํน์ ์ ์์ ์ผ๋ก ์ธ๋ฑ์ฑ๋์ง ์์ row๊ฐ ์๋ค๋ฉด ์ธ๋ฑ์ค๊ฐ NaN์ด ๋ ํ
๋ dropna()๋ก ์ ๊ฑฐํฉ๋๋ค.
temp_user_data = data['user_id'].map(user_to_idx.get).dropna()
if len(temp_user_data) == len(data): # ๋ชจ๋ row๊ฐ ์ ์์ ์ผ๋ก ์ธ๋ฑ์ฑ๋์๋ค๋ฉด
print('user_id column indexing OK!!')
data['user_id'] = temp_user_data # data['user_id']์ ์ธ๋ฑ์ฑ๋ Series๋ก ๊ต์ฒดํด ์ค๋๋ค.
else:
print('user_id column indexing Fail!!')
# artist_to_idx์ ํตํด artist ์ปฌ๋ผ๋ ๋์ผํ ๋ฐฉ์์ผ๋ก ์ธ๋ฑ์ฑํด ์ค๋๋ค.
temp_artist_data = data['artist'].map(artist_to_idx.get).dropna()
if len(temp_artist_data) == len(data):
print('artist column indexing OK!!')
data['artist'] = temp_artist_data
else:
print('artist column indexing Fail!!')
data
- ๋ช ์์ ๋ฐ์ดํฐ(Explicit Data) : ์ข์์, ํ์ ๊ณผ ๊ฐ์ด ์ ์ ๊ฐ ์์ ์ ์ ํธ๋๋ฅผ ์ง์ (Explicit)ํํํ ๋ฐ์ดํฐ
- ์๋ฌต์ ๋ฐ์ดํฐ(Implicit Data) : ์ ์ ๊ฐ ๊ฐ์ ์ (Implicit)์ผ๋ก ์ ํธ, ์ทจํฅ์ ๋ํ๋ด๋ ๋ฐ์ดํฐ. ๊ฒ์๊ธฐ๋ก, ๋ฐฉ๋ฌธํ์ด์ง, ๊ตฌ๋งค๋ด์ญ, ๋ง์ฐ์ค ์์ง์ ๊ธฐ๋ก ๋ฑ์ด ์๋ค.
# 1ํ๋ง playํ ๋ฐ์ดํฐ์ ๋น์จ์ ๋ณด๋ ์ฝ๋
only_one = data[data['play']<2]
one, all_data = len(only_one), len(data)
print(f'{one},{all_data}')
print(f'Ratio of only_one over all data is {one/all_data:.2%}')
์ด๋ฒ์ ๋ง๋ค ๋ชจ๋ธ์์๋ ์๋ฌต์ ๋ฐ์ดํฐ์ ํด์์ ์ํด ๋ค์๊ณผ ๊ฐ์ ๊ท์น์ ์ ์ฉํ๋ค.
- ํ ๋ฒ์ด๋ผ๋ ๋ค์์ผ๋ฉด ์ ํธํ๋ค๊ณ ํ๋จํ๋ค.
- ๋ง์ด ์ฌ์ํ ์ํฐ์คํธ์ ๋ํด ๊ฐ์ค์น๋ฅผ ์ฃผ์ด์ ๋ ํ์คํ ์ข์ํ๋ค๊ณ ํ๋จํ๋ค.
์ถ์ฒ์์คํ ์ ๋ค์ํ ๋ชจ๋ธ ์ค Matrix Factorization(MF, ํ๋ ฌ๋ถํด) ๋ชจ๋ธ์ ์ฌ์ฉํ ๊ฒ์ด๋ค.
MF๋ ํ๊ฐํ๋ ฌ R์ P์ Q ๋ ๊ฐ์ Feature Matrix๋ก ๋ถํดํ๋ ๊ฒ์ด๋ค. ์๋ ๊ทธ๋ฆผ์์๋ P๊ฐ ์ฌ์ฉ์์ ํน์ฑ(Feature) ๋ฒกํฐ๊ณ , Q๋ ์ํ์ ํน์ฑ ๋ฒกํฐ๊ฐ ๋๋ค. ๋ ๋ฒกํฐ๋ฅผ ๋ด์ ํด์ ์ป์ด์ง๋ ๊ฐ์ด ์ํ ์ ํธ๋๋ก ๊ฐ์ฃผํ๋ ๊ฒ์ด๋ค.
๋ฒกํฐ๋ฅผ ์ ๋ง๋๋ ๊ธฐ์ค์ ์ ์ i์ ๋ฒกํฐ์ ์์ดํ j์ ๋ฒกํฐ๋ฅผ ๋ด์ ํ์ ๋ ์ ์ i๊ฐ ์์ดํ j์ ๋ํด ํ๊ฐํ ์์น์ ๋น์ทํ์ง ํ์ธํ๋ ๊ฒ์ด๋ค.
์ด๋ฒ์ ์ฌ์ฉํ ๋ชจ๋ธ์ Collaborative Filtering for Implicit Feedback Datasets ๋ ผ๋ฌธ์์ ์ ํํ ๋ชจ๋ธ์ ์ฌ์ฉํ๋ค.
์ ์ X ์์ดํ ํ๊ฐํ๋ ฌ์ ํ๋ ฌ๋ก ํํํ๋ค๊ณ ํ๋ฉด 36๋ง * 29๋ง * 1byte = ์ฝ 97GB๊ฐ ํ์ํ๋ค. ์ด๋ ๊ฒ ํฐ ์ฉ๋์ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ ค๋๊ณ ์์ ์ ํ๋ค๋ ๊ฒ์ ๊ฑฐ์ ๋ถ๊ฐ๋ฅ ํ๊ธฐ ๋๋ฌธ์ CSR์ ์ฌ์ฉํ๋ค.
CSR์ Sparseํ matrix์์ 0์ด ์๋ ์ ํจํ ๋ฐ์ดํฐ๋ก ์ฑ์์ง๋ ๋ฐ์ดํฐ์ ๊ฐ๊ณผ ์ขํ ์ ๋ณด๋ง์ผ๋ก ๊ตฌ์ฑํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์ต์ํ ํ๋ฉด์๋ Sparseํ matrix์ ๋์ผํ ํ๋ ฌ์ ํํํ ์ ์๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ด๋ค.
# ์ค์ต ์์ ์ค๋ช
๋ณด๊ณ ์ดํดํด์ ๋ง๋ค์ด๋ณด๊ธฐ
from scipy.sparse import csr_matrix
num_user = data['user_id'].nunique()
num_artist = data['artist'].nunique()
csr_data = csr_matrix((data.play, (data.user_id, data.artist)), shape= (num_user, num_artist))
csr_data
Matrix Factorization ๋ชจ๋ธ์ implicit ํจํค์ง๋ฅผ ์ฌ์ฉํ์ฌ ํ์ตํด๋ณด์.
- implicit ํจํค์ง๋ ์ด์ ์คํ ์์ ์ค๋ช ํ ์๋ฌต์ (implicit) dataset์ ์ฌ์ฉํ๋ ๋ค์ํ ๋ชจ๋ธ์ ๊ต์ฅํ ๋น ๋ฅด๊ฒ ํ์ตํ ์ ์๋ ํจํค์ง์ด๋ค.
- ์ด ํจํค์ง์ ๊ตฌํ๋ als(AlternatingLeastSquares) ๋ชจ๋ธ์ ์ฌ์ฉํ๋ค. Matrix Factorization์์ ์ชผ๊ฐ์ง ๋ Feature Matrix๋ฅผ ํ๊บผ๋ฒ์ ํ๋ จํ๋ ๊ฒ์ ์ ์๋ ดํ์ง ์๊ธฐ ๋๋ฌธ์, ํ์ชฝ์ ๊ณ ์ ์ํค๊ณ ๋ค๋ฅธ ์ชฝ์ ํ์ตํ๋ ๋ฐฉ์์ ๋ฒ๊ฐ์ ์ํํ๋ AlternatingLeastSquares ๋ฐฉ์์ด ํจ๊ณผ์ ์ธ ๊ฒ์ผ๋ก ์๋ ค์ ธ ์๋ค.
from implicit.als import AlternatingLeastSquares
import os
import numpy as np
# implicit ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๊ถ์ฅํ๊ณ ์๋ ๋ถ๋ถ
os.environ['OPENBLAS_NUM_THREADS']='1'
os.environ['KMP_DUPLICATE_LIB_OK']='True'
os.environ['MKL_NUM_THREADS']='1'
# Implicit AlternatingLeastSquares ๋ชจ๋ธ์ ์ ์ธ
als_model = AlternatingLeastSquares(factors=100, regularization=0.01, use_gpu=False, iterations=15, dtype=np.float32)
# als ๋ชจ๋ธ์ input์ผ๋ก (item X user ๊ผด์ matrix๋ฅผ ๋ฐ๊ธฐ ๋๋ฌธ์ Transposeํด์ค๋๋ค.)
csr_data_transpose = csr_data.T
csr_data_transpose
# ๋ชจ๋ธ ํ๋ จ
als_model.fit(csr_data_transpose)
# ๋ฒกํฐ๊ฐ ํ์ธ
zimin, black_eyed_peas = user_to_idx['zimin'], artist_to_idx['black eyed peas']
zimin_vector, black_eyed_peas_vector = als_model.user_factors[zimin], als_model.item_factors[black_eyed_peas]
zimin_vector
black_eyed_peas_vector
# zimin๊ณผ black_eyed_peas๋ฅผ ๋ด์ ํ๋ ์ฝ๋
np.dot(zimin_vector, black_eyed_peas_vector) # 0.5098079
# ๋ค๋ฅธ ์ํฐ์คํธ์ ๋ํ ์ ํธ๋
queen = artist_to_idx['queen']
queen_vector = als_model.item_factors[queen]
np.dot(zimin_vector, queen_vector) # 0.3044492
AlternatingLeastSquares
ํด๋์ค์ ๊ตฌํ๋์ด ์๋ similar_items
๋ฉ์๋๋ฅผ ํตํ์ฌ ๋น์ทํ ์ํฐ์คํธ๋ฅผ ์ฐพ๋๋ค.
# ๋น์ทํ ์ํฐ์คํธ ์ฐพ๊ธฐ
favorite_artist = 'coldplay'
artist_id = artist_to_idx[favorite_artist]
similar_artist = als_model.similar_items(artist_id, N=15)
similar_artist
# #artist_to_idx ๋ฅผ ๋ค์ง์ด, index๋ก๋ถํฐ artist ์ด๋ฆ์ ์ป๋ dict๋ฅผ ์์ฑํฉ๋๋ค.
idx_to_artist = {v:k for k,v in artist_to_idx.items()}
[idx_to_artist[i[0]] for i in similar_artist]
# ๋น์ทํ ์ํฐ์คํธ๋ฅผ ์ฐพ์์ฃผ๋ ํจ์
def get_similar_artist(artist_name: str):
artist_id = artist_to_idx[artist_name]
similar_artist = als_model.similar_items(artist_id)
similar_artist = [idx_to_artist[i[0]] for i in similar_artist]
return similar_artist
# ๋ค๋ฅธ ์ํฐ์คํธ ํ์ธ
get_similar_artist('2pac')
get_similar_artist('lady gaga')
ํน์ ์ฅ๋ฅด๋ฅผ ์ ํธํ๋ ์ฌ๋๋ค์ ์ ํธ๋๊ฐ ์ง์ค๋๊ธฐ ๋๋ฌธ์ ์ฅ๋ฅด๋ณ ํน์ฑ์ด ๋๋๋ฌ์ง๋ค.
AlternatingLeastSquares
ํด๋์ค์ ๊ตฌํ๋์ด ์๋ recommend ๋ฉ์๋๋ฅผ ํตํ์ฌ ์ข์ํ ๋งํ ์ํฐ์คํธ๋ฅผ ์ถ์ฒ๋ฐ๋๋ค. filter_already_liked_items
๋ ์ ์ ๊ฐ ์ด๋ฏธ ํ๊ฐํ ์์ดํ
์ ์ ์ธํ๋ Argument์ด๋ค.
user = user_to_idx['zimin']
# recommend์์๋ user*item CSR Matrix๋ฅผ ๋ฐ์ต๋๋ค.
artist_recommended = als_model.recommend(user, csr_data, N=20, filter_already_liked_items=True)
artist_recommended
# index to artist
[idx_to_artist[i[0]] for i in artist_recommended]
# ์ถ์ฒ ๊ธฐ์ฌ๋ ํ์ธ
rihanna = artist_to_idx['rihanna']
explain = als_model.explain(user, csr_data, itemid=rihanna)
[(idx_to_artist[i[0]], i[1]) for i in explain[1]]
์ถ์ฒ์์คํ ์์ Baseline์ผ๋ก ๋ง์ด ์ฌ์ฉ๋๋ MF๋ฅผ ํตํด ์ํฐ์คํธ๋ฅผ ์ถ์ฒํ๋ ๋ชจ๋ธ์ ๋ง๋ค์ด๋ณด์๋ค. ๊ทธ๋ฌ๋ ์ด ๋ชจ๋ธ์ ๋ช ๊ฐ์ง ์์ฌ์ด ์ ์ด ์๋ค.
- ์ ์ , ์ํฐ์คํธ์ ๋ํ Meta์ ๋ณด๋ฅผ ๋ฐ์ํ๊ธฐ ์ฝ์ง ์๋ค. ์๋ฅผ ๋ค์ด ์ฐ๋ น๋๋ณ๋ก ์์ ์ทจํฅ์ด ๋ค๋ฅผ ์ ์๋๋ฐ ์ด๋ฌํ ๋ถ๋ถ์ ๋ฐ์ํ๊ธฐ ์ด๋ ต๋ค.
- ์ ์ ๊ฐ ์ธ์ playํ๋์ง ๋ฐ์ํ๊ธฐ ์ด๋ ต๋ค. 10๋ ์ ์ ์ฌ์๋ ๋ ธ๋๋ ์ง๊ธ ์ฌ์๋๋ ๋ ธ๋๋ ๋น๊ตํด๋ณด์.
- csr_data๋ฅผ ๋ง๋๋๋ฐ ์์ธ์ง ๋ชจ๋ฅด๊ฒ ์ง๋ง unique๋ก ๋ฝ์ ๊ฐ์ shape์๋ค ๋ฃ์ด์คฌ๋๋ row index๊ฐ ๋์๋ค๊ณ ์๋ฌ๊ฐ ๋ด๋ค. ๊ทธ๋์ shape๋ฅผ ๋ฃ์ง ์๊ณ ๊ทธ๋ฅ ๋๋ ธ๋๋ ์์ฑ์ด ๋์๊ณ , ๋ง๋ค์ด์ง csr_data์ shape๋ฅผ ํ์ธํด๋ณด๋ unique๊ฐ๊ณผ ๋ฌ๋๋ค. ์ ๊ทธ๋ฐ์ง๋ ์ ๋ชจ๋ฅด๊ฒ ๋ค... NaN๊ฐ์ด ์๋..?
- ์ค๋ ํ ๊ณผ์ ๊ฐ ์ง๊ธ๊น์ง ํ ๊ณผ์ ์ค์์ ๊ฐ์ฅ ์ด๋ ค์ ๋ ๊ฒ ๊ฐ๋ค. ์์ง ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ์ ์ต์ํ์ง ์์์ ๊ทธ๋ด ์๋ ์์ง๋ง ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ๊ฐ ๊ฑฐ์ ์ ๋ถ์ธ ๊ฒ ๊ฐ๋ค.
- ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ๋ง ์ ํด๋ ๋ฐ์ ์ฑ๊ณตํ๋ค๋ ๋๋์ด๋ค. ์ ์ด์ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด ์์์กฐ์ฐจ ํ ์ ์์ผ๋ ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ๊ณผ pandas, numpy๋ฑ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋ํด ์ ์ตํ๋ฌ์ผ ๊ฒ ๋ค.
- ๋ชจ๋ธ์ ํ๋ จํ์ฌ ์ค์ ๋ก ์ถ์ฒ๋ฐ์ ๋ชฉ๋ก์ ๋ณด๋ ํ ์ด์คํ ๋ฆฌ๋ฅผ ๊ณจ๋์ ๋ ํ ์ด์คํ ๋ฆฌ2, ๋ฒ ์ค๋ผ์ดํ, ์๋ผ๋ ๋ฑ์ ์ถ์ฒํด์ฃผ๋ ๊ฑธ ๋ณด๋ฉด ๋งํ์ ๋๋ฉ์ด์ ์ฅ๋ฅด์ชฝ์ ์ถ์ฒํด์ฃผ๊ณ ์๋ค. ๋ฐ๋ผ์ ํ๋ จ์ด ์ ์ด๋ฃจ์ด์ก๋ค๊ณ ํ๊ฐํ ์ ์์ ๊ฒ ๊ฐ๋ค.
- csr_data๋ฅผ ๋ง๋ค ๋ shape ์์ Error๊ฐ ๋ฐ์ํ๋ ์ด์ ๋ฅผ ์์๋๋ค. ๊ทธ ์์ธ์ csr_data์ (row_ind, col_ind) parameter๊ฐ max(row_ind), max(col_ind)๋ก ์๋ํ์ฌ row_ind์ col_ind์ index์ ์ต๋๊ฐ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฌผ๋ก row์ col์ด index ์์ผ๋ก ์ ์ ๋ ฌ๋์ด ์๋ค๋ฉด ์ด๋ ๊ฒ ํด๋ ๋ฌธ์ ๊ฐ ์์ง๋ง, ์ค์ ๋ก๋ movie_id์ ์ค๊ฐ์ ๋น ์ง index๋ค์ด ์๊ธฐ ๋๋ฌธ์ movie_id์ ์ด ๊ฐฏ์์ธ 3628๊ฐ ๋ณด๋ค ํฐ max(row_ind)์ 3953๊ฐ๊ฐ parameter๋ก ์ฌ์ฉ๋๋ ๊ฒ์ด๋ค. user_id๋ ๋ง์ฐฌ๊ฐ์ง๋ก uniqueํ ๊ฐ์ 6040๊ฐ์ง๋ง, index๊ฐ 1๋ถํฐ ์์ํ์ฌ ๋๊ฐ์ 6041์ด๋ฏ๋ก ์ด 6042๊ฐ๋ฅผ col_ind๋ก ์ฌ์ฉํ๊ฒ ๋๋ค. ์ด ๋ถ๋ถ์ ์์ ํด๋ณด๋ ค๊ณ ํ์ผ๋, movie_id๋ง๋ค ์ด๋ฏธ ํ ๋น๋ title์ด ์๊ธฐ ๋๋ฌธ์ ratings DataFrame์ ๋ค์ movie_id์ ๋ง๋ title column์ ๋ํด์ฃผ๊ณ movie_id์์ผ๋ก ์ค๋ณต์ ์ ๊ฑฐํ๊ณ sortํ์ฌ title์ ๋ค์ movie_id๋ฅผ ํ ๋นํด ์ฃผ๋ ์์ ์ด ๋๋ฌด ๋ฒ๊ฑฐ๋ก์์ ๊ทธ๋ง๋๋ค.
https://orill.tistory.com/entry/Explicit-vs-Implicit-Feedback-Datasets?category=1066301 ๋ช ์์ /์๋ฌต์ ํ๊ฐ
https://lovit.github.io/nlp/machine learning/2018/04/09/sparse_mtarix_handling/#csr-matrix CSR
https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.html CSR์ ๋ง๋๋ ๋ฐฉ๋ฒ
https://danthetech.netlify.app/DataScience/evaluation-metrics-for-recommendation-system ์ถ์ฒ์์คํ ํ๊ฐ ๋ฐฉ๋ฒ