Data Science, даже в музыке.

Jan 23 2023
Тестируя Spotify API, я обнаружил множество функций, скрытых за песнями, которые мы слушаем каждый день. Вот проект, но я предпочитаю показать его вам в этой статье.

Тестируя Spotify API, я обнаружил множество функций, скрытых за песнями, которые мы слушаем каждый день.

Вот проект, но я предпочитаю показать его вам в этой статье.https://github.com/ivanurquiza/Spotify-Analysis

У меня возникла идея проанализировать самые прослушиваемые песни на данный момент.

Два основных вопроса, на которые нужно ответить:
1. Что характерно для трендовой музыки?
2. Чем она отличается от старомодной музыки?

# FILL IN THESE VALUES WITH YOUR OWN KEYS
client_id = ...

client_secret = ...

# Make sure to add this on "Edit Settings" in your Dashboard
redirect_uri = "http://localhost:9000"

import spotipy
from spotipy.oauth2 import SpotifyOAuth

# Connect with API Keys created earlier
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=client_id,
                                              client_secret=client_secret,
                                              redirect_uri=redirect_uri))

Я должен был сделать выбор. Для этого случая я использовал очень известный в Аргентине плейлист, созданный Spotify, который содержит Топ-50 самых прослушиваемых песен на данный момент:

#Playlist ID
TOP50_playlist = sp.playlist('37i9dQZEVXbMMy2roB9myp')

for track_data in TOP50_playlist['tracks']['items']:
    
    #Getting just the ID (last part of the url)
    track_id = track_data['track']['uri'].split(':')[-1]
    track_name = track_data['track']['name']
    track_popularity = track_data['track']['popularity']
    list_tracksids.append((track_name,track_id,track_popularity))

df_features = pd.DataFrame()

for idx, dict_trackfeatures in enumerate(sp.audio_features(tracks=[url[1] for url in list_tracksids])):
    dict_trackfeatures['track_name'] = list_tracksids[idx][0]
    dict_trackfeatures['popularity'] = list_tracksids[idx][2]
    df_features = pd.concat([df_features,pd.Series(dict_trackfeatures)], axis=1)

                      #Selects only useful features
df_features=df_features.transpose()[['track_name','popularity','danceability','energy','loudness','speechiness','acousticness','instrumentalness','liveness','tempo']]

#Display Top 5 songs
df_features.head()

Мы готовы. Давайте проанализируем данные!

Давайте построим несколько диаграмм, чтобы получить первые образцы самой популярной музыки.

На графике слева видно, что музыка, составляющая наш плейлист TOP 50, в основном расположена во второй половине (более 0,5 из 1), что, по-видимому, означает, что она очень танцевальная. Как мы можем узнать, верно ли это подозрение?

Давайте сравним среднюю танцевальность этих песен с классической музыкой. Здравствуй, Моцарт!

import seaborn as sns
import matplotlib.pyplot as plt

# Let's plot some charts for getting the first patterns about the most popular music

sns.set_theme(context='notebook',style="ticks")
fig, axes = plt.subplots(1, 2, figsize=(10,5))

# Left - Danceability's histogram with kde
sns.distplot(ax=axes[0], x=df_features["danceability"], bins=6, kde=True, color="#5B3BA0")

axes[0].set(xlabel='Danceability', ylabel='Frequency')
axes[0].set_title('TOP 50 Danceability freq.')

# Right - Comparation between the playlist avarage and Mozart's most popular song

                                              # Requiem, K. 626: Lacrimosa
mozart_danceability = sp.audio_features(tracks=['3oHSL6pt9LpNrQZuQGu9wL'])[0]['danceability']

avg_top50_danceability = df_features['danceability'].mean()

sns.barplot(ax= axes[1],
            x = 'who',
            y = 'Danceability',
            data = {'who':['TOP 50','MOZART'],
                   'Danceability':[avg_top50_danceability, mozart_danceability]},
            palette=['#5B3BA0','#A378FF']
            )

axes[1].set(ylabel='Danceability')
axes[1].set_title('Mozart vs TOP 50')

plt.show()

      
                

Как мы можем себе представить, Моцарт не входит в число 50 самых исполняемых песен. Судя по нашему краткому анализу, Моцарту может не хватить танцевальных способностей, чтобы попасть в плейлист.

  • Танцевальность Моцарта: 0,162
  • Средний балл танцевальности ТОП-50: 0,739

#Adding Mozart's song variables to our dataframe
mozart = pd.DataFrame({'track_name':['Mozart'], 'popularity':[0.0]})
for k,v in sp.audio_features(tracks=['3oHSL6pt9LpNrQZuQGu9wL'])[0].items():
    if k in df_features.keys():
        mozart[k]=v

df_features = pd.concat([df_features,mozart], axis=0)
df_features['playlist'] = ['TOP 50' if x != 'Mozart' else 'Mozart' for x in df_features['track_name']] 
                           
df_features.tail(1)

      
                
#Scatter plot plt.figure(dpi=80) sns.scatterplot( data=df_features, x='acousticness',y='loudness', hue="playlist", sizes=(20, 200), legend="full", palette=['#5B3BA0','#D00000'] ) plt.show()

Эта таблица отчасти помогает понять, почему Моцарт не в моде. Песни в топ-50 имеют близкие значения переменных «громкость» и «акустика» и сильно сконцентрированы в верхней левой части графика. Тенденция ясна: высокая громкость и низкий уровень акустики. С другой стороны, Моцарт идет против тренда!

Те же шаги, другой плейлист

А что, если вместо Моцарта и модных песен взять плейлист с лучшими песнями 80-х?

Сделаем то же самое, но немного иначе.

AllOut80s = sp.playlist('37i9dQZF1DX4UtSsGT1Sbe')
list_tracksids = list()

for track_data in AllOut80s['tracks']['items']:
    
    #Gets just the ID (last part of the url)
    track_id = track_data['track']['uri'].split(':')[-1]
    track_name = track_data['track']['name']
    track_popularity = track_data['track']['popularity']
    list_tracksids.append((track_name,track_id,track_popularity))

AllOut80s_features = pd.DataFrame()

for idx, dict_trackfeatures in enumerate(sp.audio_features(tracks=[url[1] for url in list_tracksids])):
    dict_trackfeatures['track_name'] = list_tracksids[idx][0]
    dict_trackfeatures['popularity'] = list_tracksids[idx][2]
    AllOut80s_features = pd.concat([AllOut80s_features,pd.Series(dict_trackfeatures)], axis=1)



                           #Selects only useful features
AllOut80s_features=AllOut80s_features.transpose()[['track_name','popularity','danceability','energy','loudness','speechiness','acousticness','instrumentalness','liveness','tempo']]
AllOut80s_features['playlist'] = 'AllOut80s'

#Handles data types
AllOut80s_features[['danceability','energy','loudness','speechiness','acousticness','instrumentalness','liveness','tempo']]=AllOut80s_features[['danceability','energy','loudness','speechiness','acousticness','instrumentalness','liveness','tempo']].astype(float)

Посмотрите результаты:

# Setting up concatenated df
df_allsongs = pd.concat([df_features, AllOut80s_features[:50]]).reset_index()

df_allsongs= df_allsongs.drop(df_allsongs.index[df_allsongs['playlist'] == 'Mozart'])

plt.figure(dpi=80)


sns.lmplot(
    data=df_allsongs, x='acousticness',y='loudness', hue="playlist",
    legend="full", palette=['#5B3BA0','#D00000']
)

plt.show()

      
                

Глядя на распределения и линии регрессии для каждого плейлиста, мы замечаем, что тенденции совершенно разные. Хотя взаимосвязь между переменными (наклон кривых) остается довольно похожей, кажется, что песни расположены по шаблону, причем плейлист Top 50 имеет более высокий уровень «громкости».

Просто проверив эти две особенности, мы можем увидеть, что музыка 80-х больше похожа на современные тенденции, чем Моцарт.

Давайте продвинем проект на шаг вперед!

Можем ли мы предсказать, учитывая все возможные переменные, к какому плейлисту принадлежит песня? Я не уверен, но ответ, вероятно, KNeighbors .

Я погуглил самую репрезентативную песню 80-х, чтобы использовать ее в качестве входных данных для нашего прогноза моделирования:

Features used for modeling
featlist=['danceability','energy','loudness','speechiness','acousticness','instrumentalness','liveness','tempo']

prince = {}
for k,v in sp.audio_features(tracks=['54X78diSLoUDI3joC2bjMz'])[0].items():
    if k in featlist:
        prince[k]=v

prince = pd.DataFrame(prince.items()).transpose()
prince.columns = prince.iloc[0]
prince=prince[1:]
prince[featlist] = prince[featlist].astype(float)
prince

      
                
from sklearn.neighbors import KNeighborsClassifier knn = KNeighborsClassifier(n_neighbors=3) X = df_allsongs[featlist] y = df_allsongs['playlist'] knn.fit(X,y) # Prediction prediction = knn.predict(prince) print('The song could be included in the playlist: ', prediction[0])

Спасибо за прочтение!

Контакты : www.linkedin.com/in/ivanroblesurquiza

Твиттер :https://twitter.com/urqivo