# Build Up My Own Recommend Playlist from Scratch

Collaborative Filtering is usually the first type of method for recommender system. It has two approachs, the first one is user-user based model, which use the similiarity between user to recommend new items, another one is item-item based model. Instead of using the similarity between users, it uses that between items to recommend new items.

Here, we are going to go beyond collaborative filtering and introduce latent factor model in the application of recommender system. In this article, we are going to use [Million Song Dataset](https://labrosa.ee.columbia.edu/millionsong/). It contains users and song data. The main motivation behind is that when we using music streaming service like Spotify, kkbox, and youtube, the recommended songs often catch my eye. Take Spotify for example, there is a feature called *Discover Weekly*, which automatically generate a recommended playlist weekly. Very often, I enjoyed listening to the recommended songs. Therefore, I think it will be a great idea if I can build up a recommend playlist or songs using different methods, and to see what the result will be.

Here are the steps that I take for this experiment:
* Take [Million Song Dataset](https://labrosa.ee.columbia.edu/millionsong/)
* Use user-user based collaborative filtering to build up a recommended playlist
* Use item-item based collaborative filtering to build up a recommended playlist
* Use Latent Factor Model to build up a recommended playlist
* Measure the performance using Root Mean Square Error(RMSE)
* Compare the result of different approachs

For collaborative filtering, we follow the same step as the [previous notebook for recommending movies](https://github.com/johnnychiuchiu/Machine-Learning/blob/master/RecommenderSystem/collaborative_filtering.ipynb).
Firstly, in order to calculate the similarity, we need to get a utility matrix using the song dataframe. For illustration purpose, I also manually append three rows into the utility matrix. Each row represent a person with some specific music taste.

We use two method to compare the measure the result of different approachs. The first approach is calculate the Mean Square Error. Since both collaborative filtering and latent factor model need all the dataset to calcualte the predicted result. The way we generate train and test different from the way we usually use, that is randomly select some row to be test.

In the song data, we randomly take 3 listen_count of each user out and place it in the test dataset. Then we use only train dataset to predict the recommended playlist. After have the predicted score for all the songs, we then compare the nonzero values in test data set with the corresponding value in the train dataset and calcualte the MSE of it. Also, I have make sure each user has at least listened to 5 different songs in the song data.

---

## Implementing Collaborative Filtering to build up Recommeded Playlist

```python
%matplotlib inline

import pandas as pd
from sklearn.cross_validation import train_test_split
import numpy as np
import os
from sklearn.metrics import mean_squared_error
```

    /Users/johnnychiu/anaconda3/lib/python3.6/site-packages/sklearn/cross_validation.py:41: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
      "This module will be removed in 0.20.", DeprecationWarning)

```python
def compute_mse(y_true, y_pred):
    """ignore zero terms prior to comparing the mse"""
    mask = np.nonzero(y_true)
    mse = mean_squared_error(y_true[mask], y_pred[mask])
    return mse

def create_train_test(ratings):
    """
    split into training and test sets,
    remove 3 ratings from each user
    and assign them to the test set
    """
    test = np.zeros(ratings.shape)
    train = ratings.copy()
    for user in range(ratings.shape[0]):
        test_index = np.random.choice(
            np.flatnonzero(ratings[user]), size=3, replace=False)

        train[user, test_index] = 0.0
        test[user, test_index] = ratings[user, test_index]

    # assert that training and testing set are truly disjoint
    assert np.all(train * test == 0)
    return (train, test)
```

```python
class collaborativeFiltering():
    def __init__(self):
        pass

    def readSongData(self, top):
        """
        Read song data from targeted url
        """
        if 'song.pkl' in os.listdir('../../data/'):
            song_df = pd.read_pickle('../../data/song.pkl')
        else:
            # Read userid-songid-listen_count triplets
            # This step might take time to download data from external sources
            triplets_file = 'https://static.turi.com/datasets/millionsong/10000.txt'
            songs_metadata_file = 'https://static.turi.com/datasets/millionsong/song_data.csv'

            song_df_1 = pd.read_table(triplets_file, header=None)
            song_df_1.columns = ['user_id', 'song_id', 'listen_count']

            # Read song  metadata
            song_df_2 = pd.read_csv(songs_metadata_file)

            # Merge the two dataframes above to create input dataframe for recommender systems
            song_df = pd.merge(song_df_1, song_df_2.drop_duplicates(['song_id']), on="song_id", how="left")

            # Merge song title and artist_name columns to make a merged column
            song_df['song'] = song_df['title'].map(str) + " - " + song_df['artist_name']

            n_users = song_df.user_id.unique().shape[0]
            n_items = song_df.song_id.unique().shape[0]
            print(str(n_users) + ' users')
            print(str(n_items) + ' items')

            song_df.to_pickle('../data/processed/song.pkl')

        # keep top_n rows of the data
        song_df = song_df.head(top)

        song_df = self.drop_freq_low(song_df)

        return(song_df)

    def drop_freq_low(self, song_df):
        freq_df = song_df.groupby(['user_id']).agg({'song_id': 'count'}).reset_index(level=['user_id'])
        below_userid = freq_df[freq_df.song_id <= 5]['user_id']
        new_song_df = song_df[~song_df.user_id.isin(below_userid)]

        return(new_song_df)

    def utilityMatrix(self, song_df):
        """
        Transform dataframe into utility matrix, return both dataframe and matrix format
        :param song_df: a dataframe that contains user_id, song_id, and listen_count
        :return: dataframe, matrix
        """
        song_reshape = song_df.pivot(index='user_id', columns='song_id', values='listen_count')
        song_reshape = song_reshape.fillna(0)
        ratings = song_reshape.as_matrix()
        return(song_reshape, ratings)

    def fast_similarity(self, ratings, kind='user', epsilon=1e-9):
        """
        Calculate the similarity of the rating matrix
        :param ratings: utility matrix
        :param kind: user-user sim or item-item sim
        :param epsilon: small number for handling dived-by-zero errors
        :return: correlation matrix
        """

        if kind == 'user':
            sim = ratings.dot(ratings.T) + epsilon
        elif kind == 'item':
            sim = ratings.T.dot(ratings) + epsilon
        norms = np.array([np.sqrt(np.diagonal(sim))])
        return (sim / norms / norms.T)

    def predict_fast_simple(self, ratings, kind='user'):
        """
        Calculate the predicted score of every song for every user.
        :param ratings: utility matrix
        :param kind: user-user sim or item-item sim
        :return: matrix contains the predicted scores
        """

        similarity = self.fast_similarity(ratings, kind)

        if kind == 'user':
            return similarity.dot(ratings) / np.array([np.abs(similarity).sum(axis=1)]).T
        elif kind == 'item':
            return ratings.dot(similarity) / np.array([np.abs(similarity).sum(axis=1)])

    def get_overall_recommend(self, ratings, song_reshape, user_prediction, top_n=10):
        """
        get the top_n predicted result of every user. Notice that the recommended item should be the song that the user
         haven't listened before.
        :param ratings: utility matrix
        :param song_reshape: utility matrix in dataframe format
        :param user_prediction: matrix with predicted score
        :param top_n: the number of recommended song
        :return: a dict contains recommended songs for every user_id
        """
        result = dict({})
        for i, row in enumerate(ratings):
            user_id = song_reshape.index[i]
            result[user_id] = {}
            zero_item_list = np.where(row == 0)[0]
            prob_list = user_prediction[i][np.where(row == 0)[0]]
            song_id_list = np.array(song_reshape.columns)[zero_item_list]
            result[user_id]['recommend'] = sorted(zip(song_id_list, prob_list), key=lambda item: item[1], reverse=True)[
                                           0:top_n]

        return (result)

    def get_user_recommend(self, user_id, overall_recommend, song_df):
        """
        Get the recommended songs for a particular user using the song information from the song_df
        :param user_id:
        :param overall_recommend:
        :return:
        """
        user_score = pd.DataFrame(overall_recommend[user_id]['recommend']).rename(columns={0: 'song_id', 1: 'score'})
        user_recommend = pd.merge(user_score,
                                  song_df[['song_id', 'title', 'release', 'artist_name', 'song']].drop_duplicates(),
                                  on='song_id', how='left')
        return (user_recommend)

    def createNewObs(self, artistName, song_reshape, index_name):
        """
        Append a new row with userId 0 that is interested in some specific artists
        :param artistName: a list of artist names
        :return: dataframe, matrix
        """
        interest = []
        for i in song_reshape.columns:
            if i in song_df[song_df.artist_name.isin(artistName)]['song_id'].unique():
                interest.append(10)
            else:
                interest.append(0)

        print(pd.Series(interest).value_counts())

        newobs = pd.DataFrame([interest],
                              columns=song_reshape.columns)
        newobs.index = [index_name]

        new_song_reshape = pd.concat([song_reshape, newobs])
        new_ratings = new_song_reshape.as_matrix()
        return (new_song_reshape, new_ratings)
```

## Take Million Song Dataset

We only keep the first 50000 rows for this notebook. Otherwise it will take too long to execute it. As following, we can see that there are around **17k** users and **93k** different songs out of the first 50k rows.

```python
cf = collaborativeFiltering()
song_df = cf.readSongData(100000)
```

    76353 users
    10000 items

```python
song_df.head()
```

      user_id
      song_id
      listen_count
      title
      release
      artist_name
      year
      song

      0
      b80344d063b5ccb3212f76538f3d9e43d87dca9e
      SOAKIMP12A8C130995
      1
      The Cove
      Thicker Than Water
      Jack Johnson
      0
      The Cove - Jack Johnson

      1
      b80344d063b5ccb3212f76538f3d9e43d87dca9e
      SOBBMDR12A8C13253B
      2
      Entre Dos Aguas
      Flamenco Para Niños
      Paco De Lucia
      1976
      Entre Dos Aguas - Paco De Lucia

      2
      b80344d063b5ccb3212f76538f3d9e43d87dca9e
      SOBXHDL12A81C204C0
      1
      Stronger
      Graduation
      Kanye West
      2007
      Stronger - Kanye West

      3
      b80344d063b5ccb3212f76538f3d9e43d87dca9e
      SOBYHAJ12A6701BF1D
      1
      Constellations
      In Between Dreams
      Jack Johnson
      2005
      Constellations - Jack Johnson

      4
      b80344d063b5ccb3212f76538f3d9e43d87dca9e
      SODACBL12A8C13C273
      1
      Learn To Fly
      There Is Nothing Left To Lose
      Foo Fighters
      1999
      Learn To Fly - Foo Fighters

```python
artist_df= song_df.groupby(['artist_name']).agg({'song_id':'count'}).reset_index(level=['artist_name']).sort_values(by='song_id',ascending=False).head(100)
```

```python
n_users = song_df.user_id.unique().shape[0]
n_items = song_df.song_id.unique().shape[0]
print(str(n_users) + ' users')
print(str(n_items) + ' songs')
```

    3464 users
    9930 songs

• **Get the utility matrix**

```python
song_reshape, ratings = cf.utilityMatrix(song_df)
```

• **Append new rows to simulate a users who love different kinds of musicians**

```python
song_reshape, ratings = cf.createNewObs(['Beyoncé', 'Katy Perry', 'Alicia Keys'], song_reshape, 'GirlFan')
song_reshape, ratings = cf.createNewObs(['Metallica', 'Guns N\' Roses', 'Linkin Park', 'Red Hot Chili Peppers'],
                                        song_reshape, 'HeavyFan')
song_reshape, ratings = cf.createNewObs(['Daft Punk','John Mayer','Hot Chip','Coldplay'],
                                        song_reshape, 'Johnny')
```

    0     9876
    10      54
    dtype: int64
    0     9801
    10     129
    dtype: int64
    0     9747
    10     183
    dtype: int64

• **Create train test dataset**

```python
train, test = create_train_test(ratings)
```

```python
song_reshape.shape
```

    (3467, 9930)

## Calculate user-user collaborative filtering

```python
user_prediction = cf.predict_fast_simple(train, kind='user')
user_overall_recommend = cf.get_overall_recommend(train, song_reshape, user_prediction, top_n=10)
user_recommend_girl = cf.get_user_recommend('GirlFan', user_overall_recommend, song_df)
user_recommend_heavy = cf.get_user_recommend('HeavyFan', user_overall_recommend, song_df)
user_recommend_johnny = cf.get_user_recommend('Johnny', user_overall_recommend, song_df)
```

## Calculate item-item collaborative filtering

```python
item_prediction = cf.predict_fast_simple(train, kind='item')
item_overall_recommend = cf.get_overall_recommend(train, song_reshape, item_prediction, top_n=10)
item_recommend_girl = cf.get_user_recommend('GirlFan', item_overall_recommend, song_df)
item_recommend_heavy = cf.get_user_recommend('HeavyFan', item_overall_recommend, song_df)
item_recommend_johnny = cf.get_user_recommend('Johnny', item_overall_recommend, song_df)
```

---

The main idea behind Latent Factor Model is that we can transform our utility matrix into the multiple of two lower rank matrix. For example, if we have 5 users and 10 songs, then our utility matrix is 5 * 10. We can transform the matrix in to two matrixs, say 5 x 3 (say Q) and 3 x 10 (say P). Each user can be represented by a vector in 3 dimension, and each song can als obe represented by a vector in 3 dimension. The meaning of each dimension for Q can be, for example, do the user like jazz related music; each dimension for P can be, for example, is it a jazz song. The picture copied from google search result visualize it more clearly:

In order to get all the values in the Q and P, we need some optimization method to help us. The optimization method suggested by the winner of Netflix is called **Alternating Least Squares with Weighted Regularization (ALS-WR)**.

Our cost function is as follows:

$$ \begin{align} L &= \sum\limits_{u,i \in S}( r_{ui} - \textbf{x}_{u} \textbf{y}_{i}^{T} )^{2} + \lambda \big( \sum\limits_{u} \left\Vert \textbf{x}_{u} \right\Vert^{2} + \sum\limits_{i} \left\Vert \textbf{y}_{i} \right\Vert^{2} \big) \end{align} $$

We will try to minimize the loss function to get our optimal $x_u$ and $y_i$ vectors. The main idea behind ALS-WR method is that we try to get the optimal Q and P matrix by holding one vector to be fixed at a time. We alternate back and forth until the value of Q and P converges. The reason why we don't optimize both vector at the same time is that it is hard to get optimal vectors at the same time. By holding one vector to be fixed and optimize another vector alternately, we can find the optimal Q and P more efficiently.

For a detailed explaination on how to
please check [Ethen's Alternating Least Squares with Weighted Regularization (ALS-WR) from scratch](http://nbviewer.jupyter.org/github/ethen8181/machine-learning/blob/master/recsys/1_ALSWR.ipynb).

## Recommend using Latent Factor Model

```python
class ExplicitMF:
    """
    This function is directly taken from Ethen's github (http://nbviewer.jupyter.org/github/ethen8181/machine-learning/blob/master/recsys/1_ALSWR.ipynb)
    Train a matrix factorization model using Alternating Least Squares
    to predict empty entries in a matrix

    Parameters
    ----------
    n_iters : int
        number of iterations to train the algorithm

    n_factors : int
        number of latent factors to use in matrix
        factorization model, some machine-learning libraries
        denote this as rank

    reg : float
        regularization term for item/user latent factors,
        since lambda is a keyword in python we use reg instead
    """

    def __init__(self, n_iters, n_factors, reg):
        self.reg = reg
        self.n_iters = n_iters
        self.n_factors = n_factors

    def fit(self, train):#, test
        """
        pass in training and testing at the same time to record
        model convergence, assuming both dataset is in the form
        of User x Item matrix with cells as ratings
        """
        self.n_user, self.n_item = train.shape
        self.user_factors = np.random.random((self.n_user, self.n_factors))
        self.item_factors = np.random.random((self.n_item, self.n_factors))

        # record the training and testing mse for every iteration
        # to show convergence later (usually, not worth it for production)
        # self.test_mse_record = []
        # self.train_mse_record = []
        for _ in range(self.n_iters):
            self.user_factors = self._als_step(train, self.user_factors, self.item_factors)
            self.item_factors = self._als_step(train.T, self.item_factors, self.user_factors)
            predictions = self.predict()
            # test_mse = self.compute_mse(test, predictions)
            # train_mse = self.compute_mse(train, predictions)
            # self.test_mse_record.append(test_mse)
            # self.train_mse_record.append(train_mse)

        return self

    def _als_step(self, ratings, solve_vecs, fixed_vecs):
        """
        when updating the user matrix,
        the item matrix is the fixed vector and vice versa
        """
        A = fixed_vecs.T.dot(fixed_vecs) + np.eye(self.n_factors) * self.reg
        b = ratings.dot(fixed_vecs)
        A_inv = np.linalg.inv(A)
        solve_vecs = b.dot(A_inv)
        return solve_vecs

    def predict(self):
        """predict ratings for every user and item"""
        pred = self.user_factors.dot(self.item_factors.T)
        return pred
```

• **Fit using Alternating Least Square Method**

```python
als = ExplicitMF(n_iters=200, n_factors=10, reg=0.01)
als.fit(train)
```

    <__main__.ExplicitMF at 0x1a3061be48>

```python
latent_prediction = als.predict()
latent_overall_recommend = cf.get_overall_recommend(train, song_reshape, latent_prediction, top_n=10)
latent_recommend_girl = cf.get_user_recommend('GirlFan', latent_overall_recommend, song_df)
latent_recommend_heavy = cf.get_user_recommend('HeavyFan', latent_overall_recommend, song_df)
latent_recommend_johnny = cf.get_user_recommend('Johnny', latent_overall_recommend, song_df)
```

## Measure the performance using Root Mean Square Error(RMSE)

```python
user_mse = compute_mse(test, user_prediction)
item_mse = compute_mse(test, item_prediction)
latent_mse = compute_mse(test, latent_prediction)

print("MSE for user-user approach: "+str(user_mse))
print("MSE for item-item approach: "+str(item_mse))
print("MSE for latent factor model: "+str(latent_mse))
```

    MSE for user-user approach: 57.7771858363
    MSE for item-item approach: 58.6375454429
    MSE for latent factor model: 58.2479015207

We can see that even though latent factor model is somewhat a more advanced model, the MSE not the lowerest for some reason. It is something that I should keep in mind.

## Compare the result of different approachs

### > Recommend Playlist for someone who is a big fan of *Beyoncé*, *Katy Perry* and *Alicia Keys*

• **User-user approach**

```python
user_recommend_girl
```

      song_id
      score
      title
      release
      artist_name
      song

      0
      SOFRQTD12A81C233C0
      1.220800
      Sehr kosmisch
      Musik von Harmonia
      Harmonia
      Sehr kosmisch - Harmonia

      1
      SOAWJSH12A8C13AE09
      0.864679
      Diary
      The Diary Of Alicia Keys
      Alicia Keys featuring Tony! Toni! Toné! and Je...
      Diary - Alicia Keys featuring Tony! Toni! Toné...

      2
      SONYKOW12AB01849C9
      0.591618
      Secrets
      Waking Up
      OneRepublic
      Secrets - OneRepublic

      3
      SOBONKR12A58A7A7E0
      0.568278
      You're The One
      If There Was A Way
      Dwight Yoakam
      You're The One - Dwight Yoakam

      4
      SOPTLQL12AB018D56F
      0.529204
      Billionaire [feat. Bruno Mars]  (Explicit Albu...
      Billionaire [feat. Bruno Mars]
      Travie McCoy
      Billionaire [feat. Bruno Mars]  (Explicit Albu...

      5
      SODCNJX12A6D4F93CB
      0.487053
      Jamaica Roots II(Agora E Sempre)
      Nova Bis-Natiruts
      Natiruts
      Jamaica Roots II(Agora E Sempre) - Natiruts

      6
      SOAXGDH12A8C13F8A1
      0.484940
      Dog Days Are Over (Radio Edit)
      Now That's What I Call Music! 75
      Florence + The Machine
      Dog Days Are Over (Radio Edit) - Florence + Th...

      7
      SODJWHY12A8C142CCE
      0.462038
      Hey_ Soul Sister
      Save Me_ San Francisco
      Train
      Hey_ Soul Sister - Train

      8
      SOTWSXL12A8C143349
      0.456135
      Love Story
      Het Beste Uit De Top 40 - 2009
      Taylor Swift
      Love Story - Taylor Swift

      9
      SOXFPND12AB017C9D1
      0.441003
      I Gotta Feeling
      Todo Éxitos 2009
      Black Eyed Peas
      I Gotta Feeling - Black Eyed Peas

• **Item-item approach**

```python
item_recommend_girl
```

      song_id
      score
      title
      release
      artist_name
      song

      0
      SOUVXMC12A8C13FBD3
      2.014231
      The Storm Is Over Now
      Kirk Franklin Presents: Songs For The Storm_ V...
      Gods Property
      The Storm Is Over Now - Gods Property

      1
      SOYINGU12AAF3B3314
      1.823236
      Now Behold The Lamb
      Christmas
      Kirk Franklin & The Family
      Now Behold The Lamb - Kirk Franklin & The Family

      2
      SOUWBLM12A8C1353D7
      1.729083
      EMOTIONS
      The Remixes
      Mariah Carey
      EMOTIONS - Mariah Carey

      3
      SOHAIXS12A8C1432FF
      1.673589
      Tattoo
      Jordin Sparks
      Jordin Sparks
      Tattoo - Jordin Sparks

      4
      SOEVGOY12AB0181053
      1.477932
      Be With You
      Freedom
      Akon
      Be With You - Akon

      5
      SOPZFDD12A8C13AE12
      1.425781
      A Prayer
      Red Balloon
      East Blues Experience
      A Prayer - East Blues Experience

      6
      SOOXYLM12AB018472B
      1.366272
      Mr. Man
      Songs In A Minor
      Alicia Keys;Jimmy Cozier
      Mr. Man - Alicia Keys;Jimmy Cozier

      7
      SONLMAQ12A58A7C17E
      1.314909
      It Kills Me
      The Bridge
      Melanie Fiona
      It Kills Me - Melanie Fiona

      8
      SOAWJSH12A8C13AE09
      1.310774
      Diary
      The Diary Of Alicia Keys
      Alicia Keys featuring Tony! Toni! Toné! and Je...
      Diary - Alicia Keys featuring Tony! Toni! Toné...

      9
      SOBVFLL12AF72A4EE8
      1.235398
      Intuition
      In A Perfect World...
      Keri Hilson
      Intuition - Keri Hilson

• **Latent Factor Model**

```python
latent_recommend_girl
```

      song_id
      score
      title
      release
      artist_name
      song

      0
      SOHTKMO12AB01843B0
      0.295730
      Catch You Baby (Steve Pitron & Max Sanna Radio...
      Catch You Baby
      Lonnie Gordon
      Catch You Baby (Steve Pitron & Max Sanna Radio...

      1
      SOSXLTC12AF72A7F54
      0.282809
      Revelry
      Only By The Night
      Kings Of Leon
      Revelry - Kings Of Leon

      2
      SOBONKR12A58A7A7E0
      0.250950
      You're The One
      If There Was A Way
      Dwight Yoakam
      You're The One - Dwight Yoakam

      3
      SOAUWYT12A81C206F1
      0.234038
      Undo
      Vespertine Live
      Björk
      Undo - Björk

      4
      SOXLOQG12AF72A2D55
      0.201449
      Unite (2009 Digital Remaster)
      Hello Nasty (Remastered Edition)
      Beastie Boys
      Unite (2009 Digital Remaster) - Beastie Boys

      5
      SOEGIYH12A6D4FC0E3
      0.099974
      Horn Concerto No. 4 in E flat K495: II. Romanc...
      Mozart - Eine kleine Nachtmusik
      Barry Tuckwell/Academy of St Martin-in-the-Fie...
      Horn Concerto No. 4 in E flat K495: II. Romanc...

      6
      SOQXBZN12AB018610A
      0.090470
      Waiting For A Dream
      Want
      Rufus Wainwright
      Waiting For A Dream - Rufus Wainwright

      7
      SOCHWPT12AB0184F15
      0.064614
      Girl Money
      Kix
      Kix
      Girl Money - Kix

      8
      SOWMDQL12A8C13FB54
      0.063458
      What I Want
      Daughtry
      Daughtry featuring Slash
      What I Want - Daughtry featuring Slash

      9
      SOUFTBI12AB0183F65
      0.053377
      Invalid
      Fermi Paradox
      Tub Ring
      Invalid - Tub Ring

### > Recommend Playlist for someone who is a big fan of  *Metallica*, *Guns N' Roses*, *Linkin Park*  and *Red Hot Chili Peppers*

```python
user_recommend_heavy
```

      song_id
      score
      title
      release
      artist_name
      song

      0
      SOHNRJO12A8AE44A2B
      0.753657
      Duality (Album Version)
      Vol. 3 The Subliminal Verses
      Slipknot
      Duality (Album Version) - Slipknot

      1
      SOFRQTD12A81C233C0
      0.410551
      Sehr kosmisch
      Musik von Harmonia
      Harmonia
      Sehr kosmisch - Harmonia

      2
      SOEGIYH12A6D4FC0E3
      0.397378
      Horn Concerto No. 4 in E flat K495: II. Romanc...
      Mozart - Eine kleine Nachtmusik
      Barry Tuckwell/Academy of St Martin-in-the-Fie...
      Horn Concerto No. 4 in E flat K495: II. Romanc...

      3
      SOAUWYT12A81C206F1
      0.391494
      Undo
      Vespertine Live
      Björk
      Undo - Björk

      4
      SOLLNTU12A6701CFDC
      0.356573
      Kryptonite
      Total 90s
      3 Doors Down
      Kryptonite - 3 Doors Down

      5
      SOLRGNF12AB0187CF4
      0.344345
      Sample Track 2
      Dance & Hip Hop Breaks
      Simon Harris
      Sample Track 2 - Simon Harris

      6
      SOBONKR12A58A7A7E0
      0.333048
      You're The One
      If There Was A Way
      Dwight Yoakam
      You're The One - Dwight Yoakam

      7
      SOSXLTC12AF72A7F54
      0.295502
      Revelry
      Only By The Night
      Kings Of Leon
      Revelry - Kings Of Leon

      8
      SONYKOW12AB01849C9
      0.280297
      Secrets
      Waking Up
      OneRepublic
      Secrets - OneRepublic

      9
      SODJWHY12A8C142CCE
      0.272850
      Hey_ Soul Sister
      Save Me_ San Francisco
      Train
      Hey_ Soul Sister - Train

```python
item_recommend_heavy
```

      song_id
      score
      title
      release
      artist_name
      song

      0
      SOKNDKQ12A58A795CC
      5.024717
      Boom (2006 Remastered Album Version)
      Greatest Hits [The Atlantic Years]
      P.O.D.
      Boom (2006 Remastered Album Version) - P.O.D.

      1
      SOMRAUN12A6D4F5224
      3.214688
      Departure (Album Version)
      Ascendancy
      Trivium
      Departure (Album Version) - Trivium

      2
      SOEXZPN12A6701FBC9
      2.999622
      The Curse
      Out of Exile
      Audioslave
      The Curse - Audioslave

      3
      SONYBWB12A8C137FB7
      2.443226
      The Robots (2009 Digital Remaster)
      The Mix (2009 Digital Remaster)
      Kraftwerk
      The Robots (2009 Digital Remaster) - Kraftwerk

      4
      SOSLSLS12A8C135B5F
      2.425797
      Sleep Now In The Fire
      The Battle Of Los Angeles
      Rage Against The Machine
      Sleep Now In The Fire - Rage Against The Machine

      5
      SOEKZAZ12A8C134536
      2.368279
      No Government
      No Government
      Nicolette
      No Government - Nicolette

      6
      SOCRIYW12A8C143467
      2.241282
      Ella Elle L A
      Free
      Kate Ryan
      Ella Elle L A - Kate Ryan

      7
      SOHNRJO12A8AE44A2B
      2.221037
      Duality (Album Version)
      Vol. 3 The Subliminal Verses
      Slipknot
      Duality (Album Version) - Slipknot

      8
      SOXQBCW12AB018704A
      2.107345
      Own Little World
      ROUNDERS
      Celldweller
      Own Little World - Celldweller

      9
      SOXBRKW12A8C142084
      2.100702
      'Til We Die (Album Version)
      All Hope Is Gone
      Slipknot
      'Til We Die (Album Version) - Slipknot

```python
latent_recommend_heavy
```

      song_id
      score
      title
      release
      artist_name
      song

      0
      SOSXLTC12AF72A7F54
      0.565791
      Revelry
      Only By The Night
      Kings Of Leon
      Revelry - Kings Of Leon

      1
      SOAUWYT12A81C206F1
      0.441504
      Undo
      Vespertine Live
      Björk
      Undo - Björk

      2
      SOBONKR12A58A7A7E0
      0.376160
      You're The One
      If There Was A Way
      Dwight Yoakam
      You're The One - Dwight Yoakam

      3
      SOHTKMO12AB01843B0
      0.375985
      Catch You Baby (Steve Pitron & Max Sanna Radio...
      Catch You Baby
      Lonnie Gordon
      Catch You Baby (Steve Pitron & Max Sanna Radio...

      4
      SOXLOQG12AF72A2D55
      0.246720
      Unite (2009 Digital Remaster)
      Hello Nasty (Remastered Edition)
      Beastie Boys
      Unite (2009 Digital Remaster) - Beastie Boys

      5
      SOEGIYH12A6D4FC0E3
      0.193375
      Horn Concerto No. 4 in E flat K495: II. Romanc...
      Mozart - Eine kleine Nachtmusik
      Barry Tuckwell/Academy of St Martin-in-the-Fie...
      Horn Concerto No. 4 in E flat K495: II. Romanc...

      6
      SOQXBZN12AB018610A
      0.189135
      Waiting For A Dream
      Want
      Rufus Wainwright
      Waiting For A Dream - Rufus Wainwright

      7
      SOUFTBI12AB0183F65
      0.143973
      Invalid
      Fermi Paradox
      Tub Ring
      Invalid - Tub Ring

      8
      SOCHWPT12AB0184F15
      0.140022
      Girl Money
      Kix
      Kix
      Girl Money - Kix

      9
      SOHKZSM12A8C13E5D5
      0.114459
      (They Long To Be) Close To You
      The Essential Collection (1965-1997)
      Carpenters
      (They Long To Be) Close To You - Carpenters

### > Recommend Playlist for myself, I like *Daft Punk*, *John Mayer*, *Hot Chip* and *Coldplay*

```python
user_recommend_johnny
```

      song_id
      score
      title
      release
      artist_name
      song

      0
      SOFRQTD12A81C233C0
      0.624175
      Sehr kosmisch
      Musik von Harmonia
      Harmonia
      Sehr kosmisch - Harmonia

      1
      SOAXGDH12A8C13F8A1
      0.523781
      Dog Days Are Over (Radio Edit)
      Now That's What I Call Music! 75
      Florence + The Machine
      Dog Days Are Over (Radio Edit) - Florence + Th...

      2
      SONYKOW12AB01849C9
      0.468903
      Secrets
      Waking Up
      OneRepublic
      Secrets - OneRepublic

      3
      SOTWNDJ12A8C143984
      0.445995
      Marry Me
      Save Me_ San Francisco
      Train
      Marry Me - Train

      4
      SOBONKR12A58A7A7E0
      0.419571
      You're The One
      If There Was A Way
      Dwight Yoakam
      You're The One - Dwight Yoakam

      5
      SOSXLTC12AF72A7F54
      0.386520
      Revelry
      Only By The Night
      Kings Of Leon
      Revelry - Kings Of Leon

      6
      SOAUWYT12A81C206F1
      0.367355
      Undo
      Vespertine Live
      Björk
      Undo - Björk

      7
      SODJWHY12A8C142CCE
      0.358878
      Hey_ Soul Sister
      Save Me_ San Francisco
      Train
      Hey_ Soul Sister - Train

      8
      SOWCKVR12A8C142411
      0.345714
      Use Somebody
      Use Somebody
      Kings Of Leon
      Use Somebody - Kings Of Leon

      9
      SOLFXKT12AB017E3E0
      0.328672
      Fireflies
      Karaoke Monthly Vol. 2 (January 2010)
      Charttraxx Karaoke
      Fireflies - Charttraxx Karaoke

```python
item_recommend_johnny
```

      song_id
      score
      title
      release
      artist_name
      song

      0
      SOACMJJ12A6D4FC66A
      2.865445
      Legacy Of Kings
      Steel Meets Steel - 10 Years Of Glory
      HAMMERFALL
      Legacy Of Kings - HAMMERFALL

      1
      SOJZVDN12A8C133C0B
      2.658009
      With Oden On Our Side
      With Oden On Our Side
      Amon Amarth
      With Oden On Our Side - Amon Amarth

      2
      SOJLYEB12A6D4F9750
      2.573096
      Angel
      Beneath These Fireworks
      Matt Nathanson
      Angel - Matt Nathanson

      3
      SOAWXHP12AB01840AC
      2.309754
      Lemonade
      Grey Oceans
      Cocorosie
      Lemonade - Cocorosie

      4
      SOFESLM12AB017ED43
      2.251314
      Play On
      Play On
      Carrie Underwood
      Play On - Carrie Underwood

      5
      SOMFPCO12AF72ABFC2
      2.046729
      Falling Or Flying
      Grey's Anatomy Volume 3 Original Soundtrack
      Grace Potter and the Nocturnals
      Falling Or Flying - Grace Potter and the Noctu...

      6
      SOKIYKH12AB0186B3C
      2.033221
      Please Read The Letter
      2009 GRAMMY Nominees
      Robert Plant & Alison Krauss
      Please Read The Letter - Robert Plant & Alison...

      7
      SOBCLWO12A6D4F83AD
      1.849505
      Forever My Friend
      Trouble
      Ray LaMontagne
      Forever My Friend - Ray LaMontagne

      8
      SOLUKGT12A67ADF6B0
      1.819389
      Just Like Honey
      21 Singles
      The Jesus And Mary Chain
      Just Like Honey - The Jesus And Mary Chain

      9
      SOZVZSP12A6D4F6A99
      1.736477
      Rosemary
      Scott 3
      Scott Walker
      Rosemary - Scott Walker

```python
latent_recommend_johnny
```

      song_id
      score
      title
      release
      artist_name
      song

      0
      SOBONKR12A58A7A7E0
      1.098167
      You're The One
      If There Was A Way
      Dwight Yoakam
      You're The One - Dwight Yoakam

      1
      SOUFTBI12AB0183F65
      0.846242
      Invalid
      Fermi Paradox
      Tub Ring
      Invalid - Tub Ring

      2
      SOSXLTC12AF72A7F54
      0.805501
      Revelry
      Only By The Night
      Kings Of Leon
      Revelry - Kings Of Leon

      3
      SOHKZSM12A8C13E5D5
      0.749307
      (They Long To Be) Close To You
      The Essential Collection (1965-1997)
      Carpenters
      (They Long To Be) Close To You - Carpenters

      4
      SOAUWYT12A81C206F1
      0.712063
      Undo
      Vespertine Live
      Björk
      Undo - Björk

      5
      SOHTKMO12AB01843B0
      0.522571
      Catch You Baby (Steve Pitron & Max Sanna Radio...
      Catch You Baby
      Lonnie Gordon
      Catch You Baby (Steve Pitron & Max Sanna Radio...

      6
      SOQXBZN12AB018610A
      0.362042
      Waiting For A Dream
      Want
      Rufus Wainwright
      Waiting For A Dream - Rufus Wainwright

      7
      SOXLOQG12AF72A2D55
      0.335933
      Unite (2009 Digital Remaster)
      Hello Nasty (Remastered Edition)
      Beastie Boys
      Unite (2009 Digital Remaster) - Beastie Boys

      8
      SOEGIYH12A6D4FC0E3
      0.314326
      Horn Concerto No. 4 in E flat K495: II. Romanc...
      Mozart - Eine kleine Nachtmusik
      Barry Tuckwell/Academy of St Martin-in-the-Fie...
      Horn Concerto No. 4 in E flat K495: II. Romanc...

      9
      SOSJLSI12A8C13FB69
      0.246786
      Your Rocky Spine
      Penny Candy_ Vol. 2
      Great Lake Swimmers
      Your Rocky Spine - Great Lake Swimmers

We see that the all the recommended playlist are actually kind of make sense. In the following notebook, I will continue to try some other methods to build up custom recommended playlists.

### Reference

* http://nbviewer.jupyter.org/github/ethen8181/machine-learning/blob/master/recsys/1_ALSWR.ipynb
* https://github.com/dvysardana/RecommenderSystems_PyData_2016/blob/master/Song%20Recommender_Python.ipynb