Clustify

Music is a driving force for me. I listen to it in the morning while making breakfast, during my commute to work and before I go to bed. Since Im usually to busy to make my own playlist, Spotify's "Daily Mixes" are perfect for me. They take my favorite songs, group similar ones together and create cohesive playlists for me.

I wanted to see if I could create my own system to do something similar. Thus, Clustify was born.

Clustify takes your top 100 most played tracks and creates four unique playlist using the K-Means clustering algorithm. This notebook will walk you step by step through the process.

In [4]:
%matplotlib inline

import os
import json
import pickle
import spotipy
import numpy as np
import pandas as pd
import spotipy.util as util
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from sklearn.cluster import KMeans

Create your Spotify App

The first thing you have to do is create your Spotify app through the Spotify for Developers site . Once created you will have access to your Client ID, Client Secret and redirect URI.

Now that we have those we will create a pkl file to hold our sensitive information. They will be empty but you can add your Client ID and Secert. Then we can setup a token that will allow us to login.

The scope atribute tells the Spotify API what premissions we need. You can read more about them here. For now all we need to do is read the users most played songs.

In [7]:
if not os.path.exists('secret_spotify_credentials.pkl'):
    Spotify = {}
    Spotify['Client ID'] = ''
    Spotify['Client Secret'] = ''
    Spotify['Redirect_URI'] = ''
    with open('secret_spotify_credentials.pkl', 'wb') as f:
        pickle.dump(Spotify, f)
else:
    Spotify = pickle.load(open('secret_spotify_credentials.pkl', 'rb'))
    
SPOTIPY_CLIENT_ID = Spotify['Client ID']
SPOTIPY_CLIENT_SECRET = Spotify['Client Secret']
SPOTIPY_REDIRECT_URI = Spotify['Redirect_URI']

username = 'DevTheWrightOne'
scope = 'user-top-read'

# Prompt for user premissions
token = util.prompt_for_user_token(username, scope, client_id = SPOTIPY_CLIENT_ID,
                           client_secret = SPOTIPY_CLIENT_SECRET,redirect_uri=SPOTIPY_REDIRECT_URI)

Gathering Data

Now that we have sucessfully logged in we can create a Spotify object using the Spotipy Python library.

The Spotify API only allows you to retrieve 50 songs at a time. You can also specify what time span you want to collect the songs from with the 'time_range' parameter. We are going to use 'short_term' which will give us the most played song from the past month.

In [4]:
# Create a spotify object
spotify = spotipy.Spotify(auth=token)

# Get currents user's top 50 songs.
results = spotify.current_user_top_tracks(offset=0, time_range='short_term', limit=50)

The results are returned to us in JSON format. Lets go ahead and display the top 50 songs along with the artist in a more readable format.

In [5]:
print('Top 50 Songs')
for i, item in enumerate(results['items']):
    print(i, item['name'], 'by', item['artists'][0]['name'])
Top 50 Songs
0 Smoke Session by Mozzy
1 Passionfruit by Drake
2 Jesus Is The One (I Got Depression) by Zack Fox
3 Death Row (feat. 03 Greedo) by Freddie Gibbs
4 Ojuelegba by WizKid
5 GRoCERIES by Chance the Rapper
6 Come Closer (feat. Drake) by WizKid
7 Devil in California by Burna Boy
8 Mi Unruly by Popcaan
9 Madiba Riddim by Drake
10 Countin' Up by Rico Nasty
11 Kontrol by Maleek Berry
12 Just My Luck (feat. Sada Baby) by Mozzy
13 Bacc At It Again by Yella Beezy
14 Blitz by ALLBLACK
15 Down Bad (feat. JID, Bas, J. Cole, EARTHGANG & Young Nudy) by Dreamville
16 Feel the Same (feat. Lamii) by Toyin Ores
17 The London (feat. J. Cole & Travis Scott) by Young Thug
18 Suge by DaBaby
19 Corners Of My Mind by Emotional Oranges
20 Boshe Nlo by Burna Boy
21 F What The Opp Said by Chief Keef
22 London by Jeremih
23 Foot Fungus by Ski Mask The Slump God
24 Money In The Grave (Drake ft. Rick Ross) by Drake
25 Not Nice by PARTYNEXTDOOR
26 Hallelujah by Burna Boy
27 Permanent Scar (feat. Young Thug and Quando Rondo) by YoungBoy Never Broke Again
28 Sound of Rain by Solange
29 IGOR'S THEME by Tyler, The Creator
30 New Person, Same Old Mistakes by Tame Impala
31 EARFQUAKE by Tyler, The Creator
32 The Less I Know The Better by Tame Impala
33 Tweakin' by Vince Staples
34 Trust Issues by Rico Nasty
35 Broke Leg (with Quavo & Tyga) by Tory Lanez
36 Mad World by Jordan Rakei
37 Run Me Dry by Bryson Tiller
38 LOVE. FEAT. ZACARI. by Kendrick Lamar
39 My Love (feat. Major Lazer, WizKid, Dua Lipa) by Wale
40 Envy Me by Calboy
41 Ransom by Lil Tecca
42 Winning (feat. Lil Poppa) by Mozzy
43 Cold by Rico Nasty
44 Cristal Occasions by Jim Jones
45 Hope by Blood Orange
46 XanaX Damage by Future
47 Jermaine's Interlude (feat. J. Cole) by DJ Khaled
48 Rock Your Body by Burna Boy
49 Heroes by Flying Lotus

Data Analytics

Now that we have the top 50 songs we can analysis them and create some cohesive playlists, but we can't do that with just song names. We need some type of features that provide us with information about the songs. Luckily, Spotify's 'get-audio-features' API request will give us that information.

To get these features we have to use the song IDs which were provided to use in the last request. Lets go ahead and store them in there own list along with the song names and artist names.

In [6]:
# List containing song names
top_song_names = [item['name'] for item in results['items']]

# List containing artist names
top_song_artists = [item['artists'][0]['name'] for item in results['items']]

# List containing song IDs
top_song_ids = [item['uri'] for item in results['items']]

Now we can pass the song IDs to the audio_features method and retrieve the song feature for all 50 songs. They will come in JSON format, but to make things simpler we'll store them in a Pandas Dataframe and take a look at the features names.

In [7]:
# Using song ids get song features for all the songs
tracks_features = spotify.audio_features(top_song_ids)

# Create a dataframe containing all the songs and their features
top_50_songs = pd.read_json(json.dumps(tracks_features))

# View the features present in the DataFrame
print(top_50_songs.columns)
Index(['acousticness', 'analysis_url', 'danceability', 'duration_ms', 'energy',
       'id', 'instrumentalness', 'key', 'liveness', 'loudness', 'mode',
       'speechiness', 'tempo', 'time_signature', 'track_href', 'type', 'uri',
       'valence'],
      dtype='object')

For the purposes of this notebook we will be using the energy and valence features.

Energy is a measure from 0.0 to 1.0 and represents a perceptual measure of intensity and activity. Typically, energetic tracks feel fast, loud, and noisy. For example, death metal has high energy, while a Bach prelude scores low on the scale.

Valence is a measure from 0.0 to 1.0 describing the musical positiveness conveyed by a track. Tracks with high valence sound more positive (e.g. happy, cheerful, euphoric), while tracks with low valence sound more negative (e.g. sad, depressed, angry).

We can use a combination of the features to gauge a persons most common mood. If someone is listening to music with high Energy and high Valence we can consider that person to be Happy or Cheerful. On the other hand if someone listens to music with low Energy and Valence we can consider them to be sad or depressed. We'll get a better idea of this when we visualize our data.

For now lets get rid of the columns in the Dataframe we dont need and add the song names and artist names to the Dataframe.

In [8]:
# Get the features that we need (Energy and Valence)
columns = ['energy', 'valence', 'id']
top_50_songs = top_50_songs[columns]

# Add the song name and artist name to the DataFrame
top_50_songs['title'] = top_song_names
top_50_songs['artist'] = top_song_artists

# Rearrange columns
columns = ['title', 'artist', 'valence', 'energy', 'id']
top_50_songs = top_50_songs[columns]

# Veiw the Dataframe
top_50_songs
Out[8]:
title artist valence energy id
0 Smoke Session Mozzy 0.1120 0.496 2sycbIpVfHRQrGMxEHvadq
1 Passionfruit Drake 0.3720 0.459 5mCPDVBb16L4XQwDdbRUpz
2 Jesus Is The One (I Got Depression) Zack Fox 0.3270 0.446 1YR9iNGXtsbrd8deR9ULDD
3 Death Row (feat. 03 Greedo) Freddie Gibbs 0.4400 0.660 3YZ5NiutSg7KraH87r4fgm
4 Ojuelegba WizKid 0.9010 0.748 6cTLhp8a39TClL2iqGpPVc
5 GRoCERIES Chance the Rapper 0.7010 0.596 0yFvWTLs3iIwDbc91noXGT
6 Come Closer (feat. Drake) WizKid 0.4960 0.453 2zYs4BonN2ydkbrRk333SN
7 Devil in California Burna Boy 0.5460 0.538 39GdQUHeQwpwyvmyXwv5Dq
8 Mi Unruly Popcaan 0.8890 0.692 49Ctz83Vrh2qTbi7wh4qwR
9 Madiba Riddim Drake 0.3190 0.527 76gUmNLXGQVOsGhfcshkFP
10 Countin' Up Rico Nasty 0.7570 0.851 6UFG7GbMAeeMijEyrp6f1D
11 Kontrol Maleek Berry 0.8860 0.521 1090OWoP6JTpYAaSSEBvGy
12 Just My Luck (feat. Sada Baby) Mozzy 0.5060 0.749 1EURKUjkZ1Vr9Jv47kZlNG
13 Bacc At It Again Yella Beezy 0.8560 0.623 2biNa12dMbHJrHVFRt8JyO
14 Blitz ALLBLACK 0.4210 0.573 32a1If7CywlxP0owXOgJOR
15 Down Bad (feat. JID, Bas, J. Cole, EARTHGANG &... Dreamville 0.6940 0.583 4eqrNsKy9Mvg1fvfsTVIAE
16 Feel the Same (feat. Lamii) Toyin Ores 0.3040 0.411 7gxb3ZzvyJYdibG2XNtPzj
17 The London (feat. J. Cole & Travis Scott) Young Thug 0.1790 0.586 7DcvwMAiqKJQD1rrdfxSDx
18 Suge DaBaby 0.8440 0.662 2gwkD6igEhQbDQegRCcdoB
19 Corners Of My Mind Emotional Oranges 0.2120 0.594 0wdMcK7ejJRdi2AiY2wLGk
20 Boshe Nlo Burna Boy 0.8860 0.574 1GxEPihVSvLveAUjUw0Dct
21 F What The Opp Said Chief Keef 0.2060 0.506 1WyBMYx2Ff3WwLjTuM8lH6
22 London Jeremih 0.5360 0.625 30VqGu6DoFagQgHiB1hGQt
23 Foot Fungus Ski Mask The Slump God 0.7450 0.623 3EikYy40GMSp8l5mDV6IQo
24 Money In The Grave (Drake ft. Rick Ross) Drake 0.1010 0.502 5ry2OE6R2zPQFDO85XkgRb
25 Not Nice PARTYNEXTDOOR 0.7250 0.496 4STaHtfguDMkWbPEo6Fwcx
26 Hallelujah Burna Boy 0.7630 0.575 37Kn41E9SYrzjphkjlkTH1
27 Permanent Scar (feat. Young Thug and Quando Ro... YoungBoy Never Broke Again 0.7320 0.698 56y48l3RslFer22WytV6KU
28 Sound of Rain Solange 0.4540 0.526 4o8Rk1YzdkTxsSEXd3YhAK
29 IGOR'S THEME Tyler, The Creator 0.0648 0.672 51RN0kzWd7xeR4th5HsEtW
30 New Person, Same Old Mistakes Tame Impala 0.4900 0.809 52ojopYMUzeNcudsoz7O9D
31 EARFQUAKE Tyler, The Creator 0.4130 0.498 5hVghJ4KaYES3BFUATCYn0
32 The Less I Know The Better Tame Impala 0.7850 0.740 6K4t31amVTZDgR3sKmwUJJ
33 Tweakin' Vince Staples 0.2580 0.620 6b6liLOZhXdOfFBFVN5KNK
34 Trust Issues Rico Nasty 0.1650 0.621 3U1er6n2pSve0xcNVn9eUu
35 Broke Leg (with Quavo & Tyga) Tory Lanez 0.6420 0.850 5WJdUrZ4ND1TCZ2AsjYK3P
36 Mad World Jordan Rakei 0.1550 0.620 1l2GLXAiyeYfHCUKbj55c2
37 Run Me Dry Bryson Tiller 0.5960 0.756 5GG3knKdxKWrNboRijxeKF
38 LOVE. FEAT. ZACARI. Kendrick Lamar 0.7790 0.585 6PGoSes0D9eUDeeAafB2As
39 My Love (feat. Major Lazer, WizKid, Dua Lipa) Wale 0.7050 0.811 7rfiXyFb5M9BqdkvKvVEiB
40 Envy Me Calboy 0.5840 0.488 7rvyVWja33WG9R97oeJAjx
41 Ransom Lil Tecca 0.2260 0.642 1xbtojAZsQjOgiGdGX6ChU
42 Winning (feat. Lil Poppa) Mozzy 0.1940 0.584 7suwdHe9b0B2ahALSt5uZP
43 Cold Rico Nasty 0.7820 0.906 4Onanh2sbZQKTGH8KvWzxS
44 Cristal Occasions Jim Jones 0.3580 0.823 1bD7QOKDKrKixoZkTgcvOF
45 Hope Blood Orange 0.3540 0.227 2QLNDKL7hZyh2OZ8UL9WrV
46 XanaX Damage Future 0.3240 0.609 3tZ4zv4UuenjJGSNUMfBNG
47 Jermaine's Interlude (feat. J. Cole) DJ Khaled 0.6100 0.678 4LAp0EFUdBeVCkusdw8i77
48 Rock Your Body Burna Boy 0.8010 0.623 4LbEUmACVAFj8e0WrMUdlN
49 Heroes Flying Lotus 0.0908 0.721 4d9B8XK0EZ4KVlFg6ULY8l

Graphing Our Data

Lets graph our data on a scatter plot to get an idea of how dispersed the songs are from each other. A songs valence will be measured along the x-axis and its energy will be measured along the y-axis. We'll also be able to see what mood the songs fall under.

In [34]:
#Plot the songs
x = top_50_songs['valence']
y = top_50_songs['energy']

fig, ax = plt.subplots(figsize=(8, 8))
ax.scatter(x, y)
ax.set_xlabel('Valence')
ax.set_ylabel('Energy')
ax.xaxis.set_major_locator(ticker.FixedLocator(np.arange(0,1.1, step=0.1)))
ax.yaxis.set_major_locator(ticker.FixedLocator(np.arange(0,1.1, step=0.1)))
ax.set_xlim(left=0, right=1.0)
ax.set_ylim(bottom=0, top=1.0)
plt.grid(b=True, which='major')
plt.minorticks_on()
plt.grid(b=True, which='minor', alpha=0.25)
plt.axhline(0.5, color='black')
plt.axvline(0.5, color='black')
plt.text(0.78, 0.94, s="Happy / Cheerful")
plt.text(0.8, 0.04, s="Chill / Relaxed")
plt.text(0.04, 0.94, s="Angry / Irate")
plt.text(0.04, 0.04, s="Sad / Depressed")
plt.show()

We can see that alot of the music I listen to has high energy and falls under the Angry to Happy spectrum. I assume this is due to the large amount of Rap and Hip Hop music I listen too. Where songs have fast paced beats that result in a high Energy value, but the songs convey a wide range of messages. Some my discuss the struggles of being raised in a bad enviorment while others discuss to the feeling of being happy with a lot of money, this would explain the wide range of Valence feature values.

Lets count the number of songs in each quadrants and determine my most frequently ocurring mood.

In [51]:
# Filters for each quadrant.
angry_filter = (top_50_songs['valence'] < 0.5) & (top_50_songs['energy'] > 0.5)
happy_filter = (top_50_songs['valence'] > 0.5) & (top_50_songs['energy'] > 0.5)
sad_filter = (top_50_songs['valence'] < 0.5) & (top_50_songs['energy'] < 0.5)
chill_filter = (top_50_songs['valence'] > 0.5) & (top_50_songs['energy'] < 0.5)

angry_songs = len(top_50_songs[angry_filter])
happy_songs = len(top_50_songs[happy_filter])
sad_songs = len(top_50_songs[sad_filter])
chill_songs = len(top_50_songs[chill_filter])

print("Angry/Irate songs:", angry_songs, "or", angry_songs/len(top_50_songs) * 100, "%")
print("Happy/Cheerful songs:", happy_songs, "or", happy_songs/len(top_50_songs) * 100, "%")
print("Sad/Depressed songs:", sad_songs, "or", sad_songs/len(top_50_songs) * 100, "%")
print("Chill/Relaxed songs:", chill_songs, "or", chill_songs/len(top_50_songs) * 100, "%")
Angry/Irate songs: 18 or 36.0 %
Happy/Cheerful songs: 23 or 46.0 %
Sad/Depressed songs: 7 or 14.000000000000002 %
Chill/Relaxed songs: 2 or 4.0 %

We can see that based on the music I listen to my most frequently occuring mood is Happy/Cheerful with 46% of the songs I listen to fall under that category.

Modeling Our Data

We are going to use the K-Means clustering algorithm from the Scikit-learn library to model are data. We will be group our songs into 4 clusters based on their energy and valence features. Each one of these clusters will represent a playlist.

Before we being we need to prepare our data by moving it into a numpy array so that we can feed it into the model.

In [35]:
# Prepare data for K-Means clustering algorithm by putting data in a numpy array
data = np.array([[i,j] for i,j in zip(x,y)])

Lets go ahead and check that we have all 50 data points.

In [36]:
# Check that there is 50 pairs of data points.
print(data.shape)
(50, 2)

Now that the data is prepared lets go head and create our model, fit our data and plot the clusters.

In [37]:
# Now we can use KMeans to cluster the songs togther using 4 centroids.
kmeans = KMeans(n_clusters=4)
kmeans.fit(data)

# Plot the clusters
fig, ax = plt.subplots(figsize=(8, 8))
ax.scatter(data[:,0],data[:,1], c=kmeans.labels_, cmap='rainbow')
ax.scatter(kmeans.cluster_centers_[:,0] ,kmeans.cluster_centers_[:,1], color='black')  

ax.set_xlabel('Valence')
ax.set_ylabel('Energy')
ax.xaxis.set_major_locator(ticker.FixedLocator(np.arange(0,1.1, step=0.1)))
ax.yaxis.set_major_locator(ticker.FixedLocator(np.arange(0,1.1, step=0.1)))
ax.set_xlim(left=0, right=1.0)
ax.set_ylim(bottom=0, top=1.0)
plt.grid(b=True, which='major')
plt.minorticks_on()
plt.grid(b=True, which='minor', alpha=0.25)
plt.axhline(0.5, color='black') # x = 0
plt.axvline(0.5, color='black') # y = 0
plt.text(0.78, 0.94, s="Happy / Cheerful")
plt.text(0.8, 0.04, s="Chill / Relaxed")
plt.text(0.04, 0.94, s="Angry / Irate")
plt.text(0.04, 0.04, s="Sad / Depressed")
plt.show()

We have successfuly grouped and labeled our top 50 songs into 4 unique playlist/clusters. Lets create a list containing the labels because we will need them later.

In [14]:
# Lets save the labels in a list.
playlist_labels = kmeans.labels_

Predicting the next 50 songs

Now that we have a model of the data we can use it to predict which playlist a song belongs to. We will do this with the next 50 songs for the users top play tracks.

Lets collect the next 50 songs and store them with the rest for a total of 100 songs.

In [15]:
# Create new token and spotify object
token = util.prompt_for_user_token(username, scope, client_id = SPOTIPY_CLIENT_ID,
                           client_secret = SPOTIPY_CLIENT_SECRET,redirect_uri=SPOTIPY_REDIRECT_URI)

spotify = spotipy.Spotify(auth=token)

results = spotify.current_user_top_tracks(offset=49, time_range='short_term', limit=50)
    
top_song_names.extend([item['name'] for item in results['items']])
top_song_artists.extend([item['artists'][0]['name'] for item in results['items']])
top_song_ids.extend([item['uri'] for item in results['items']])

# Check that there are 100 songs in total.
print(len(top_song_names))
100

Now that we have the next 50 songs and their IDs we can get their features. We will then create a DataFrame containing all the information and feature for all 100 songs.

In [16]:
# Get song features for all 100 songs.
tracks_features = spotify.audio_features(top_song_ids)

# Create a new DataFrame containing all 100 songs.
top_100_songs = pd.read_json(json.dumps(tracks_features))

# Get the features that we need (Energy and Valence)
columns = ['energy', 'valence', 'id']
top_100_songs = top_100_songs[columns]

# Add the song name and artist name to the DataFrame
top_100_songs['title'] = top_song_names
top_100_songs['artist'] = top_song_artists

# Rearrange columns
columns = ['title', 'artist', 'valence', 'energy', 'id']
top_100_songs = top_100_songs[columns]
top_100_songs
Out[16]:
title artist valence energy id
0 Smoke Session Mozzy 0.1120 0.496 2sycbIpVfHRQrGMxEHvadq
1 IGOR'S THEME Tyler, The Creator 0.0648 0.672 51RN0kzWd7xeR4th5HsEtW
2 Passionfruit Drake 0.3720 0.459 5mCPDVBb16L4XQwDdbRUpz
3 GRoCERIES Chance the Rapper 0.7010 0.596 0yFvWTLs3iIwDbc91noXGT
4 I THINK Tyler, The Creator 0.4310 0.579 4f8Mh5wuWHOsfXtzjrJB3t
5 EARFQUAKE Tyler, The Creator 0.4130 0.498 5hVghJ4KaYES3BFUATCYn0
6 Madiba Riddim Drake 0.3190 0.527 76gUmNLXGQVOsGhfcshkFP
7 Jesus Is The One (I Got Depression) Zack Fox 0.3270 0.446 1YR9iNGXtsbrd8deR9ULDD
8 Ojuelegba WizKid 0.9010 0.748 6cTLhp8a39TClL2iqGpPVc
9 The London (feat. J. Cole & Travis Scott) Young Thug 0.1790 0.586 7DcvwMAiqKJQD1rrdfxSDx
10 Corners Of My Mind Emotional Oranges 0.2120 0.594 0wdMcK7ejJRdi2AiY2wLGk
11 F What The Opp Said Chief Keef 0.2060 0.506 1WyBMYx2Ff3WwLjTuM8lH6
12 Come Closer (feat. Drake) WizKid 0.4960 0.453 2zYs4BonN2ydkbrRk333SN
13 Devil in California Burna Boy 0.5460 0.538 39GdQUHeQwpwyvmyXwv5Dq
14 Mi Unruly Popcaan 0.8890 0.692 49Ctz83Vrh2qTbi7wh4qwR
15 New Person, Same Old Mistakes Tame Impala 0.4900 0.809 52ojopYMUzeNcudsoz7O9D
16 RUNNING OUT OF TIME Tyler, The Creator 0.1620 0.391 5QvBXUm5MglLJ3iBfTX2Wo
17 Kontrol Maleek Berry 0.8860 0.521 1090OWoP6JTpYAaSSEBvGy
18 Drais Moneybagg Yo 0.7760 0.923 1P8EwM4FD6O5quWD4z244A
19 NEW MAGIC WAND Tyler, The Creator 0.4640 0.730 0fv2KH6hac06J86hBUTcSf
20 Boshe Nlo Burna Boy 0.8860 0.574 1GxEPihVSvLveAUjUw0Dct
21 London Jeremih 0.5360 0.625 30VqGu6DoFagQgHiB1hGQt
22 Sound of Rain Solange 0.4540 0.526 4o8Rk1YzdkTxsSEXd3YhAK
23 Not Nice PARTYNEXTDOOR 0.7250 0.496 4STaHtfguDMkWbPEo6Fwcx
24 5200 ScHoolboy Q 0.3200 0.545 1e3GEwsaXtBNtPfooQimDn
25 Hallelujah Burna Boy 0.7630 0.575 37Kn41E9SYrzjphkjlkTH1
26 Just My Luck (feat. Sada Baby) Mozzy 0.5060 0.749 1EURKUjkZ1Vr9Jv47kZlNG
27 A BOY IS A GUN* Tyler, The Creator 0.5050 0.689 1nXZnTALNXiPlvXotqHm66
28 Feel the Same (feat. Lamii) Toyin Ores 0.3040 0.411 7gxb3ZzvyJYdibG2XNtPzj
29 Bottle Service YG 0.3590 0.860 0MRhKGA87dwWtoit9pQ4xY
... ... ... ... ... ...
70 Ain't Gonna Happen Chief Keef 0.5740 0.552 0X0GwBMrG53Gmm3HyRIscj
71 Roll Some Mo Lucky Daye 0.3630 0.507 1sQBPGypjSgEgJZvD8u8ty
72 Shoota (feat. Lil Uzi Vert) Playboi Carti 0.4800 0.649 2BJSMvOGABRxokHKB0OI8i
73 Die For It (feat. Sage The Gemini) Mozzy 0.4810 0.718 2UnuZfQdrhATHxT4EQeeoC
74 Floating (feat. 21 Savage) ScHoolboy Q 0.5430 0.545 4NN6N5TxBO5k9uqu0W4gfQ
75 Real Games Lucky Daye 0.5630 0.374 4c3d0xt7rUFDV7EnnRYi4i
76 I Was On The Block (feat. Valee, Boogie) YG 0.1120 0.266 5Eg7NBrJKmyn22nPVaft0E
77 Post Requisite Flying Lotus 0.7940 0.718 5l25WurqQFTmdBqCLqLZ4Z
78 Dior (feat. Gunna) Moneybagg Yo 0.6290 0.525 683tYxiTlWzupDpaZ2mCv4
79 WHAT'S GOOD Tyler, The Creator 0.4490 0.909 6bOkaEXc5CopinGazSLokx
80 Make No Issues of It Jim Jones 0.4110 0.884 6eMLO4plJenbdJXtHY9bjB
81 In The Dark YG 0.0635 0.261 6l26j7uCiDstBiYTuiaInV
82 Misunderstood Lucky Daye 0.1460 0.358 6zsT60ALu2xeljCWRp3rEs
83 Karma Lucky Daye 0.8120 0.676 0xB7i2AhQZT7nnor7rb15L
84 Chill Phillipe Mozzy 0.3480 0.599 2JIGKEAehtBWKgYsbjBKD8
85 Empty Juice WRLD 0.4490 0.561 41MCdlvXOl62B7Kv86Bb1v
86 Weather the Storm (feat. Meek Mill & Lil Baby) DJ Khaled 0.2790 0.802 6xVhqLT40s5sVhepe9Mckc
87 Jealous (feat. Chris Brown, Lil Wayne & Big Sean) DJ Khaled 0.6100 0.685 6Dq8FZrvx9S28iyaKSwn9x
88 Do Not Disturb (feat. Lil Yachty & Offset) Smokepurpp 0.2120 0.647 08zAFXhfyIxq9359NHksdP
89 Burning Down The House Flying Lotus 0.5110 0.623 0FoVmWBwMGEJZWmHvvBtCT
90 Adam & Eve Calboy 0.6920 0.696 0J6UvGEMuJvzPKvlDbBvLz
91 Twerk (feat. Cardi B) City Girls 0.4810 0.842 0RRm4OS5ymfZryXBuj0G2m
92 Headstrong (feat. Kevin Gates) Moneybagg Yo 0.5290 0.671 0Tuxvc11PSg4SyImVQYO4J
93 R.I.C.O. (feat. Drake) Meek Mill 0.3860 0.599 0Y0TOsE1q11qgbi7c5WZsG
94 Wat3va I’m Wit Moneybagg Yo 0.1790 0.635 0Ys4jRPeQWfe4mMmoTgK9r
95 Walker Texas Ranger DaBaby 0.7990 0.682 0eBOVXdnrVQ0rITgKXBAA7
96 False Prophets J. Cole 0.7510 0.747 0eneujAc4PxkdjP25Gsue1
97 The Climb Flying Lotus 0.9430 0.667 0et8cwwawoxWTwozJiFJl3
98 Chosen OG 0.5870 0.633 0jJVBuOXjPQgBuVbxFFe73
99 Dangote - Instrumental Burna Boy 0.6660 0.368 12v4H7dQEMxgSfO1yt5kPu

100 rows × 5 columns

We already have a labels for the first 50 songs, now we can use the model to predict the labels for the next 50 songs. We will add the labels to the 'playlist_labels' list.

In [17]:
data = np.array([[i,j] for i,j in zip(top_100_songs['valence'], top_100_songs['energy'])])

predictions = kmeans.predict(data[50:100])
playlist_labels = np.append(playlist_labels, predictions)

# Check that there are 100 label in total.
print(len(playlist_labels))
100

Now we can add the labels to the DataFrame.

In [18]:
top_100_songs['playlist'] = playlist_labels

top_100_songs
Out[18]:
title artist valence energy id playlist
0 Smoke Session Mozzy 0.1120 0.496 2sycbIpVfHRQrGMxEHvadq 2
1 IGOR'S THEME Tyler, The Creator 0.0648 0.672 51RN0kzWd7xeR4th5HsEtW 2
2 Passionfruit Drake 0.3720 0.459 5mCPDVBb16L4XQwDdbRUpz 0
3 GRoCERIES Chance the Rapper 0.7010 0.596 0yFvWTLs3iIwDbc91noXGT 1
4 I THINK Tyler, The Creator 0.4310 0.579 4f8Mh5wuWHOsfXtzjrJB3t 0
5 EARFQUAKE Tyler, The Creator 0.4130 0.498 5hVghJ4KaYES3BFUATCYn0 0
6 Madiba Riddim Drake 0.3190 0.527 76gUmNLXGQVOsGhfcshkFP 0
7 Jesus Is The One (I Got Depression) Zack Fox 0.3270 0.446 1YR9iNGXtsbrd8deR9ULDD 0
8 Ojuelegba WizKid 0.9010 0.748 6cTLhp8a39TClL2iqGpPVc 1
9 The London (feat. J. Cole & Travis Scott) Young Thug 0.1790 0.586 7DcvwMAiqKJQD1rrdfxSDx 2
10 Corners Of My Mind Emotional Oranges 0.2120 0.594 0wdMcK7ejJRdi2AiY2wLGk 2
11 F What The Opp Said Chief Keef 0.2060 0.506 1WyBMYx2Ff3WwLjTuM8lH6 2
12 Come Closer (feat. Drake) WizKid 0.4960 0.453 2zYs4BonN2ydkbrRk333SN 0
13 Devil in California Burna Boy 0.5460 0.538 39GdQUHeQwpwyvmyXwv5Dq 0
14 Mi Unruly Popcaan 0.8890 0.692 49Ctz83Vrh2qTbi7wh4qwR 1
15 New Person, Same Old Mistakes Tame Impala 0.4900 0.809 52ojopYMUzeNcudsoz7O9D 3
16 RUNNING OUT OF TIME Tyler, The Creator 0.1620 0.391 5QvBXUm5MglLJ3iBfTX2Wo 2
17 Kontrol Maleek Berry 0.8860 0.521 1090OWoP6JTpYAaSSEBvGy 1
18 Drais Moneybagg Yo 0.7760 0.923 1P8EwM4FD6O5quWD4z244A 1
19 NEW MAGIC WAND Tyler, The Creator 0.4640 0.730 0fv2KH6hac06J86hBUTcSf 3
20 Boshe Nlo Burna Boy 0.8860 0.574 1GxEPihVSvLveAUjUw0Dct 1
21 London Jeremih 0.5360 0.625 30VqGu6DoFagQgHiB1hGQt 3
22 Sound of Rain Solange 0.4540 0.526 4o8Rk1YzdkTxsSEXd3YhAK 0
23 Not Nice PARTYNEXTDOOR 0.7250 0.496 4STaHtfguDMkWbPEo6Fwcx 1
24 5200 ScHoolboy Q 0.3200 0.545 1e3GEwsaXtBNtPfooQimDn 0
25 Hallelujah Burna Boy 0.7630 0.575 37Kn41E9SYrzjphkjlkTH1 1
26 Just My Luck (feat. Sada Baby) Mozzy 0.5060 0.749 1EURKUjkZ1Vr9Jv47kZlNG 3
27 A BOY IS A GUN* Tyler, The Creator 0.5050 0.689 1nXZnTALNXiPlvXotqHm66 3
28 Feel the Same (feat. Lamii) Toyin Ores 0.3040 0.411 7gxb3ZzvyJYdibG2XNtPzj 0
29 Bottle Service YG 0.3590 0.860 0MRhKGA87dwWtoit9pQ4xY 3
... ... ... ... ... ... ...
70 Ain't Gonna Happen Chief Keef 0.5740 0.552 0X0GwBMrG53Gmm3HyRIscj 0
71 Roll Some Mo Lucky Daye 0.3630 0.507 1sQBPGypjSgEgJZvD8u8ty 0
72 Shoota (feat. Lil Uzi Vert) Playboi Carti 0.4800 0.649 2BJSMvOGABRxokHKB0OI8i 3
73 Die For It (feat. Sage The Gemini) Mozzy 0.4810 0.718 2UnuZfQdrhATHxT4EQeeoC 3
74 Floating (feat. 21 Savage) ScHoolboy Q 0.5430 0.545 4NN6N5TxBO5k9uqu0W4gfQ 0
75 Real Games Lucky Daye 0.5630 0.374 4c3d0xt7rUFDV7EnnRYi4i 0
76 I Was On The Block (feat. Valee, Boogie) YG 0.1120 0.266 5Eg7NBrJKmyn22nPVaft0E 2
77 Post Requisite Flying Lotus 0.7940 0.718 5l25WurqQFTmdBqCLqLZ4Z 1
78 Dior (feat. Gunna) Moneybagg Yo 0.6290 0.525 683tYxiTlWzupDpaZ2mCv4 1
79 WHAT'S GOOD Tyler, The Creator 0.4490 0.909 6bOkaEXc5CopinGazSLokx 3
80 Make No Issues of It Jim Jones 0.4110 0.884 6eMLO4plJenbdJXtHY9bjB 3
81 In The Dark YG 0.0635 0.261 6l26j7uCiDstBiYTuiaInV 2
82 Misunderstood Lucky Daye 0.1460 0.358 6zsT60ALu2xeljCWRp3rEs 2
83 Karma Lucky Daye 0.8120 0.676 0xB7i2AhQZT7nnor7rb15L 1
84 Chill Phillipe Mozzy 0.3480 0.599 2JIGKEAehtBWKgYsbjBKD8 0
85 Empty Juice WRLD 0.4490 0.561 41MCdlvXOl62B7Kv86Bb1v 0
86 Weather the Storm (feat. Meek Mill & Lil Baby) DJ Khaled 0.2790 0.802 6xVhqLT40s5sVhepe9Mckc 3
87 Jealous (feat. Chris Brown, Lil Wayne & Big Sean) DJ Khaled 0.6100 0.685 6Dq8FZrvx9S28iyaKSwn9x 3
88 Do Not Disturb (feat. Lil Yachty & Offset) Smokepurpp 0.2120 0.647 08zAFXhfyIxq9359NHksdP 2
89 Burning Down The House Flying Lotus 0.5110 0.623 0FoVmWBwMGEJZWmHvvBtCT 3
90 Adam & Eve Calboy 0.6920 0.696 0J6UvGEMuJvzPKvlDbBvLz 1
91 Twerk (feat. Cardi B) City Girls 0.4810 0.842 0RRm4OS5ymfZryXBuj0G2m 3
92 Headstrong (feat. Kevin Gates) Moneybagg Yo 0.5290 0.671 0Tuxvc11PSg4SyImVQYO4J 3
93 R.I.C.O. (feat. Drake) Meek Mill 0.3860 0.599 0Y0TOsE1q11qgbi7c5WZsG 0
94 Wat3va I’m Wit Moneybagg Yo 0.1790 0.635 0Ys4jRPeQWfe4mMmoTgK9r 2
95 Walker Texas Ranger DaBaby 0.7990 0.682 0eBOVXdnrVQ0rITgKXBAA7 1
96 False Prophets J. Cole 0.7510 0.747 0eneujAc4PxkdjP25Gsue1 1
97 The Climb Flying Lotus 0.9430 0.667 0et8cwwawoxWTwozJiFJl3 1
98 Chosen OG 0.5870 0.633 0jJVBuOXjPQgBuVbxFFe73 3
99 Dangote - Instrumental Burna Boy 0.6660 0.368 12v4H7dQEMxgSfO1yt5kPu 0

100 rows × 6 columns

Creating playlists and adding songs

Great we successfully labeled our top 100 songs in 4 unique playlist. Now all we need to do is create the playlist and add the songs in the out Spotify library.

In [19]:
# Scope needed to create playlists and add songs to them.
scope = 'playlist-modify-public'

# Create a new token and spotify object.
token = util.prompt_for_user_token(username, scope, client_id = SPOTIPY_CLIENT_ID,
                           client_secret = SPOTIPY_CLIENT_SECRET,redirect_uri=SPOTIPY_REDIRECT_URI)

spotify = spotipy.Spotify(auth=token)

# Create the playlist and add the songs.
for i in range(1,5):
    # Get the songs the belong in playlist 'i'
    filter = top_100_songs['playlist'] == i-1
    stage = top_100_songs[filter]
    track_ids = stage['id']
    
    # Create the playlist
    name = "Clustify Daily Mix {}".format(i)
    playlist = spotify.user_playlist_create(user=username, name=name, public=True)
    playlist_id = playlist['id']
    
    # Add songs to the playlist
    results = spotify.user_playlist_add_tracks(user=username, playlist_id=playlist_id, tracks=track_ids)

            User authentication requires interaction with your
            web browser. Once you enter your credentials and
            give authorization, you will be redirected to
            a url.  Paste that url you were directed to to
            complete the authorization.

        
Opened https://accounts.spotify.com/authorize?client_id=65aff1cf84fb4067a58a2c6c6a601e98&response_type=code&redirect_uri=https%3A%2F%2Fwww.google.com%2F&scope=playlist-modify-public in your browser


Enter the URL you were redirected to: https://www.google.com/?code=AQBV39VSAfQYvqhx-Cf9J83c0RBbsVH8M4F2FNG_0SH80FjnCmovxO0AZKcIsCpybs3NrIYiHl9v0EY8B1iUhDHfr9i01-8rMlMJejp_sBFyzADGM-DiK4uKgf_H6FEtL_JExIhKH3xeWjtVztZzPZ88z-t2Z9EKTVP7SYUeC6aO9Mlfa2XC3OC0D4VkUunVllCgMDrFyunPbNGkMfeJA3p0z-CSkVA


Done!!

We have successfully created our own Spotify Daily Mixes