diff --git a/solutions.ipynb b/solutions.ipynb new file mode 100644 index 0000000..f714237 --- /dev/null +++ b/solutions.ipynb @@ -0,0 +1,437 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instructions\n", + "\n", + "To move forward with the project, you need to create a collection of songs with their audio features - as large as possible!\n", + "\n", + "These are the songs that we will cluster. And, later, when the user inputs a song, we will find the cluster to which the song belongs and recommend a song from the same cluster. The more songs you have, the more accurate and diverse recommendations you'll be able to give. Although... you might want to make sure the collected songs are \"curated\" in a certain way. Try to find playlists of songs that are diverse, but also that meet certain standards.\n", + "\n", + "The process of sending hundreds or thousands of requests can take some time - it's normal if you have to wait a few minutes (or, if you're ambitious, even hours) to get all the data you need.\n", + "\n", + "An idea for collecting as many songs as possible is to start with all the songs of a big, diverse playlist and then go to every artist present in the playlist and grab every song of every album of that artist. The amount of songs you'll be collecting per playlist will grow exponentially!" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# import libraries\n", + "import spotipy\n", + "from spotipy.oauth2 import SpotifyClientCredentials\n", + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials(client_id=\"da55f67d57504befa94a4c8a982c7f77\",\n", + " client_secret=\"3b08e6c5c38744eeb726342990f814bc\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "# found this function on the internet and changed it so it can return more than 100 results at a time\n", + "\n", + "def playlist_df(playlist_id):\n", + " \n", + " # Create empty dataframe\n", + " playlist_features_list = [\"artist\",\"album\",\"track_name\", \"track_id\",\"danceability\",\"energy\",\"key\",\"loudness\",\"mode\", \"speechiness\",\"instrumentalness\",\"liveness\",\"valence\",\"tempo\", \"duration_ms\",\"time_signature\"]\n", + " \n", + " playlist_df = pd.DataFrame(columns = playlist_features_list)\n", + " \n", + " # Loop through every track in the playlist, extract features and append the features to the playlist df\n", + "\n", + " results = sp.user_playlist_tracks(\"spotify\", playlist_id)\n", + " tracks = results['items']\n", + "\n", + " for oset in range(100,results['total'],100):\n", + " results = sp.user_playlist_tracks(\"spotify\", playlist_id, offset=oset)\n", + " tracks += results['items']\n", + "\n", + " \n", + " for track in tracks:\n", + " # Create empty dict\n", + " playlist_features = {}\n", + " # Get metadata\n", + " playlist_features[\"artist\"] = track[\"track\"][\"album\"][\"artists\"][0][\"name\"]\n", + " playlist_features[\"album\"] = track[\"track\"][\"album\"][\"name\"]\n", + " playlist_features[\"track_name\"] = track[\"track\"][\"name\"]\n", + " playlist_features[\"track_id\"] = track[\"track\"][\"id\"]\n", + " \n", + " # Get audio features\n", + " audio_features = sp.audio_features(playlist_features[\"track_id\"])[0]\n", + " for feature in playlist_features_list[4:]:\n", + " playlist_features[feature] = audio_features[feature]\n", + " \n", + " # Concat the dfs\n", + " track_df = pd.DataFrame(playlist_features, index = [0])\n", + " playlist_df = pd.concat([playlist_df, track_df], ignore_index = True)\n", + " \n", + " return playlist_df" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
artistalbumtrack_nametrack_iddanceabilityenergykeyloudnessmodespeechinessinstrumentalnesslivenessvalencetempoduration_mstime_signature
0HozierHozier (Deluxe)Take Me To Church7dS5EaCoMnN7DzlpT6aRn20.5660.6644-5.30300.046400.1160.437128.9452416884
1Mike Posner31 Minutes to TakeoffCooler Than Me - Single Mix2V4bv1fNWfTcyRJKmej6Sj0.7680.8207-4.63000.047400.6890.625129.9652132934
2Tyler, The CreatorFlower BoySee You Again (feat. Kali Uchis)7KA4W4McWYRpgf0fWsJZWB0.5580.5596-9.22210.09590.0000070.1090.62078.5581803874
3BastilleBad BloodPompeii3gbBpTdY8lnQwqxNCcf7950.6790.7159-6.38310.040700.2710.571127.4352141484
4ShakiraOral Fixation, Vol. 2 (Expanded Edition)Hips Don't Lie (feat. Wyclef Jean)3ZFTkvIE7kyPt6Nu3PEa7V0.7780.82410-5.89200.070700.4050.758100.0242180934
...................................................
5290MARINAThe Family JewelsHermit the Frog4Zcz6saEkOII3PlXd9gN3o0.6090.6790-4.54510.031200.1990.487122.0342159604
5291Olivia Rodrigodeja vudeja vu61KpQadow081I2AsbeLcsb0.4390.6109-7.23610.11600.0000110.3410.172181.0882155084
5292BIAFOR CERTAINWHOLE LOTTA MONEY5yorXJWdBan1Vlh116ZtQ70.8970.3711-5.01910.368000.3250.44181.0081560054
5293AshnikkoDEMIDEVILSlumber Party (feat. Princess Nokia)11ZulcYY4lowvcQm4oe3VJ0.9640.39811-8.98100.07950.0000390.1010.563105.0121784054
5294Kali UchisSin Miedo (del Amor y Otros Demonios) ∞telepatía6tDDoYIxWvMLTdKpjFkc1B0.6530.52411-9.01600.050200.2030.55383.9701601914
\n", + "

5295 rows × 16 columns

\n", + "
" + ], + "text/plain": [ + " artist album \\\n", + "0 Hozier Hozier (Deluxe) \n", + "1 Mike Posner 31 Minutes to Takeoff \n", + "2 Tyler, The Creator Flower Boy \n", + "3 Bastille Bad Blood \n", + "4 Shakira Oral Fixation, Vol. 2 (Expanded Edition) \n", + "... ... ... \n", + "5290 MARINA The Family Jewels \n", + "5291 Olivia Rodrigo deja vu \n", + "5292 BIA FOR CERTAIN \n", + "5293 Ashnikko DEMIDEVIL \n", + "5294 Kali Uchis Sin Miedo (del Amor y Otros Demonios) ∞ \n", + "\n", + " track_name track_id \\\n", + "0 Take Me To Church 7dS5EaCoMnN7DzlpT6aRn2 \n", + "1 Cooler Than Me - Single Mix 2V4bv1fNWfTcyRJKmej6Sj \n", + "2 See You Again (feat. Kali Uchis) 7KA4W4McWYRpgf0fWsJZWB \n", + "3 Pompeii 3gbBpTdY8lnQwqxNCcf795 \n", + "4 Hips Don't Lie (feat. Wyclef Jean) 3ZFTkvIE7kyPt6Nu3PEa7V \n", + "... ... ... \n", + "5290 Hermit the Frog 4Zcz6saEkOII3PlXd9gN3o \n", + "5291 deja vu 61KpQadow081I2AsbeLcsb \n", + "5292 WHOLE LOTTA MONEY 5yorXJWdBan1Vlh116ZtQ7 \n", + "5293 Slumber Party (feat. Princess Nokia) 11ZulcYY4lowvcQm4oe3VJ \n", + "5294 telepatía 6tDDoYIxWvMLTdKpjFkc1B \n", + "\n", + " danceability energy key loudness mode speechiness instrumentalness \\\n", + "0 0.566 0.664 4 -5.303 0 0.0464 0 \n", + "1 0.768 0.820 7 -4.630 0 0.0474 0 \n", + "2 0.558 0.559 6 -9.222 1 0.0959 0.000007 \n", + "3 0.679 0.715 9 -6.383 1 0.0407 0 \n", + "4 0.778 0.824 10 -5.892 0 0.0707 0 \n", + "... ... ... .. ... ... ... ... \n", + "5290 0.609 0.679 0 -4.545 1 0.0312 0 \n", + "5291 0.439 0.610 9 -7.236 1 0.1160 0.000011 \n", + "5292 0.897 0.371 1 -5.019 1 0.3680 0 \n", + "5293 0.964 0.398 11 -8.981 0 0.0795 0.000039 \n", + "5294 0.653 0.524 11 -9.016 0 0.0502 0 \n", + "\n", + " liveness valence tempo duration_ms time_signature \n", + "0 0.116 0.437 128.945 241688 4 \n", + "1 0.689 0.625 129.965 213293 4 \n", + "2 0.109 0.620 78.558 180387 4 \n", + "3 0.271 0.571 127.435 214148 4 \n", + "4 0.405 0.758 100.024 218093 4 \n", + "... ... ... ... ... ... \n", + "5290 0.199 0.487 122.034 215960 4 \n", + "5291 0.341 0.172 181.088 215508 4 \n", + "5292 0.325 0.441 81.008 156005 4 \n", + "5293 0.101 0.563 105.012 178405 4 \n", + "5294 0.203 0.553 83.970 160191 4 \n", + "\n", + "[5295 rows x 16 columns]" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# this is a playlist with 5000 songs\n", + "\n", + "playlist_df(\"4rnleEAOdmFAbRcNCgZMpY\") " + ] + } + ], + "metadata": { + "interpreter": { + "hash": "576841b4f7799d251ae57aad53f0bddb5c298a2c04b91f5151e4f2b208165af8" + }, + "kernelspec": { + "display_name": "Python 3.8.8 64-bit ('base': conda)", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.8" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +}