Spotify в Python, часть 1: предварительная обработка

Apr 24 2023
В этой статье мы начнем загружать ваши данные Spotify в Python. Это будет первая статья из серии статей о Spotify в Python.

В этой статье мы начнем загружать ваши данные Spotify в Python. Это будет первая статья из серии статей о Spotify в Python.

В этой статье я:

  • Покажите, как перенести данные Spotify в Python.
  • Загрузите список воспроизведения «Сохраненные песни» во фрейм данных.
  • Получите аудиофункции для всех ваших сохраненных песен.
  • Добавьте жанр (группу) к каждой песне.
  • Подведите небольшой итог и расскажите о следующих шагах.

Для начала необходимы учетные данные пользователя Spotify API.

Для этого вам необходимо выполнить следующие шаги:

  1. Перейдите на панель инструментов разработчика Spotify (https://developer.spotify.com/dashboard/applications) и войдите в свою учетную запись Spotify.
  2. Нажмите кнопку «Создать приложение», чтобы создать новое приложение Spotify.
  3. Заполните необходимую информацию для вашего приложения, такую ​​как название, описание и веб-сайт. Вы можете установить в поле «URI перенаправления» URL-адрес, который вы хотите использовать в качестве URL-адреса перенаправления.
  4. После создания приложения вам будут предоставлены значения «Идентификатор клиента» и «Секрет клиента».
  5. Не забудьте также установить «URI перенаправления» в вашем приложении Spotify в соответствии с предоставленным вами URL «ПЕРЕНАПРАВЛЕНИЕ» .

Я сохранил учетные данные следующим образом в файле «credentials»:

ПОЛЬЗОВАТЕЛЬ = '…'
CID = '...'
СЕКРЕТ = '...'
ПЕРЕНАПРАВЛЕНИЕ = '...'

В Jupiter Notebook можно запустить следующий код для создания токена пользователя с использованием учетных данных:

#importing libraries
import credentials
import spotipy
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# Retrieve user credentials from separate file
user = credentials.USER
cid = credentials.CID
secret = credentials.SECRET
redirect_uri = credentials.REDIRECT

# Define scope of access
scope = 'user-library-read'  # user-library-read, user-read-recently-played

# Prompt for user token using credentials
token = spotipy.util.prompt_for_user_token(user, scope, client_id=cid, client_secret=secret, redirect_uri=redirect_uri)

# Create Spotify token and check if successful
if token:
    sp = spotipy.Spotify(auth=token)
    print('Token created for', user)
else:
    print("Can't get token for", user)

# User data
user_data = sp.current_user()
print('My data:')
print('Name:', user_data['display_name'])
print('Followers:', user_data['followers']['total'])
print('Link:', user_data['external_urls']['spotify'])

Получение сохраненных песен из библиотеки Spotify

В следующем коде сохраненные песни извлекаются из библиотеки Spotify. Песни хранятся во фрейме данных pandas.

# Function to get all saved tracks
def get_saved_tracks():
    results = sp.current_user_saved_tracks()
    tracks = []
    while results['next']:
        tracks.extend(results['items'])
        results = sp.next(results)
    return tracks

# Converting tracks to dataframe
def deconstruct_tracks(tracks):
    saved_tracks = []
    for track in tracks:
        saved_track = {
            'added_at': track['added_at'],
            'id': track['track']['id'],
            'name': track['track']['name'],
            'popularity': track['track']['popularity'],
            'uri': track['track']['uri'],
            'artist': track['track']['artists'][0]['name'],
            'album': track['track']['album']['name'],
            'release_date': track['track']['album']['release_date'],
            'duration_ms': track['track']['duration_ms']
        }
        saved_tracks.append(saved_track)
    return pd.DataFrame(saved_tracks)

tracks_called = get_saved_tracks()
tracklist = deconstruct_tracks(tracks_called)

#%%
tracklist.head(10)

Загрузка аудиофункций

Чтобы выполнить предварительный анализ ваших сохраненных песен на Spotify, необходимо сначала извлечь из песен некоторые функции. Характеристики, которые будут получены:

Акустика : значение от 0,0 до 1,0, указывающее, является ли трек акустическим, при этом 1,0 означает высокую достоверность акустической природы.

Танцевальность : мера от 0,0 до 1,0, описывающая, насколько трек подходит для танцев на основе таких элементов, как темп, стабильность ритма, сила удара и регулярность, где 0,0 означает наименее танцевальный, а 1,0 — наиболее танцевальный.

Энергия : значение от 0,0 до 1,0, представляющее интенсивность и активность трека, при этом энергичные треки кажутся быстрыми, громкими и шумными. В этот атрибут вносят свой вклад такие характеристики восприятия, как динамический диапазон, воспринимаемая громкость, тембр, скорость начала и энтропия.

Инструментальность : предсказание того, содержит ли трек вокал, со значениями, близкими к 1,0, что указывает на более высокую вероятность отсутствия вокала. Значения выше 0,5 обычно представляют инструментальные треки с большей достоверностью, когда значение приближается к 1,0.

Живость : значение, указывающее на присутствие аудитории в записи, причем более высокие значения представляют более высокую вероятность живого выступления. Значение выше 0,8 предполагает высокую вероятность живого трека.

Громкость : общая громкость дорожки в децибелах (дБ), усредненная по всей дорожке и полезная для сравнения относительной громкости дорожек. Обычно значения находятся в диапазоне от -60 до 0 дБ.

Речевость : мера, указывающая на присутствие произнесенных слов на дорожке, со значениями, близкими к 1,0, что указывает на то, что записи более похожи на речь. Значения выше 0,66 описывают треки, полностью состоящие из произнесенных слов, а значения от 0,33 до 0,66 могут указывать на смесь музыки и речи, включая рэп. Значения ниже 0,33 в основном представляют музыкальные и неречевые треки.

Темп : общий предполагаемый темп дорожки в ударах в минуту (BPM), указывающий на скорость или темп музыки.

Тактовый размер : Музыкальный термин, определяющий количество ударов в каждом такте или такте.

Валентность : значение от 0,0 до 1,0, описывающее музыкальную позитивность, передаваемую треком, при этом высокая валентность указывает на более положительные эмоции, такие как счастье, а низкая валентность указывает на более негативные эмоции, такие как грусть.

Mode : Индикатор модальности (мажорной или минорной) дорожки, где 1 соответствует основному тону, а 0 — минорному.

Key : Предполагаемый общий тон дорожки, преобразованный в целые числа с использованием стандартной нотации Pitch Class (например, 0 = C, 1 = C♯/D♭, 2 = D и т. д.).

Используйте следующий код, чтобы получить все эти функции.

# Function to get all audio features of the saved tracks
def get_track_features(id):
    metadata = sp.track(id)
    features = sp.audio_features(id)

    # metadata
    id = metadata['id']
    name = metadata['name']
    album = metadata['album']['name']
    artist = metadata['album']['artists'][0]['name']
    release_date = metadata['album']['release_date']
    length = metadata['duration_ms']
    popularity = metadata['popularity']

    # audio features
    acousticness = features[0]['acousticness']
    danceability = features[0]['danceability']
    energy = features[0]['energy']
    instrumentalness = features[0]['instrumentalness']
    liveness = features[0]['liveness']
    loudness = features[0]['loudness']
    speechiness = features[0]['speechiness']
    tempo = features[0]['tempo']
    time_signature = features[0]['time_signature']
    valence = features[0]['valence']
    mode = features[0]['mode']
    key = features[0]['key']

    track = [name, album, artist, release_date, length, popularity, danceability, acousticness, danceability, energy,
             instrumentalness, liveness, loudness, speechiness, tempo, time_signature, valence, mode, key]
    return track

print("Function defined")
# Loop through each track id and get the tracks features
for i in range(len(tracklist)):
    try:
        track = get_track_features(tracklist['id'][i])
        tracklist.loc[i, 'name'] = track[0]
        tracklist.loc[i, 'album'] = track[1]
        tracklist.loc[i, 'artist'] = track[2]
        tracklist.loc[i, 'release_date'] = track[3]
        tracklist.loc[i, 'length'] = track[4]
        tracklist.loc[i, 'popularity'] = track[5]
        tracklist.loc[i, 'danceability'] = track[6]
        tracklist.loc[i, 'acousticness'] = track[7]
        tracklist.loc[i, 'danceability'] = track[8]
        tracklist.loc[i, 'energy'] = track[9]
        tracklist.loc[i, 'instrumentalness'] = track[10]
        tracklist.loc[i, 'liveness'] = track[11]
        tracklist.loc[i, 'loudness'] = track[12]
        tracklist.loc[i, 'speechiness'] = track[13]
        tracklist.loc[i, 'tempo'] = track[14]
        tracklist.loc[i, 'time_signature'] = track[15]
        tracklist.loc[i, 'valence'] = track[16]
        tracklist.loc[i, 'mode'] = track[17]
        tracklist.loc[i, 'key'] = track[18]

        # Save to df
        tracklist.to_csv('tracklist.csv', index=False, encoding='utf-8')
    except:
        print(f"Error with track {i}")
        pass

print(f"Features of {len(tracklist)} tracks extracted and saved to tracklist.csv")

Я получил одну ошибку на одну песню, так как это была не песня, а двухчасовой микс Керри Чандлер. Конечно, невозможно получить одно значение для всех этих звуковых характеристик. Поэтому эта «песня» не передается на следующий этап обработки.

Не поленитесь послушать ;)

Жанр

API Spotify не предоставляет ни одного жанра с песнями. Это то, над чем мы должны работать. Мы можем сделать это с помощью API, который может получить связанные жанры каждого исполнителя и добавить их к каждой песне.

# Add all genres of the artists to the dataframe
genres = []
for i in range(len(data)):
    artist = data['artist'][i]
    artist_id = sp.search(artist, type='artist')['artists']['items'][0]['id']
    artist_genres = sp.artist(artist_id)['genres']
    genres.append(artist_genres)

data['genres'] = genres
data.head(10)
# Transform the genre column to extract specific genres
data['genres'] = data['genres'].astype(str)
data['genres'] = data['genres'].str.replace('[', '')
data['genres'] = data['genres'].str.replace(']', '')
data['genres'] = data['genres'].str.replace("'", '')
data['genres'] = data['genres'].str.replace('"', '')
data.head(10)

# Search for predefined genres in the genre column
strings = ['pop', 'techno', 'house', 'disco', 'electronic',
           'trance', 'hip hop', 'rap', 'r&b', 'soul', 'rock',
           'metal', 'punk', 'jazz', 'blues', 'country', 'folk',
           'reggae', 'classical', 'indie', 'funk']

for string in strings:
    data.loc[data['genres'].str.contains(string), 'genre_group'] = string

data.head(10)

Подсчитайте для каждого жанра:

# Check how many tracks are in each genre group
data['genre_group'].value_counts()
# Count missing values
data['genre_group'].isnull().sum()
print(f"{data['genre_group'].isnull().sum()} tracks are missing a genre group")

# visualize the distribution of the genres
plt.figure(figsize=(15, 10))
sns.countplot(y='genre_group', data=data, order=data['genre_group'].value_counts().index)

for i, genre in enumerate(data['genre_group'].value_counts().index):
    count = data['genre_group'].value_counts()[genre]
    plt.text(count + 10, i, f'{count}', ha='left', va='center', color='black')

plt.title('Distribution of genres with counts')
plt.show()

Видно, что я часто нахожусь в настроении Funky и Housey, а также слушаю Indie, Disco и Soul.

Примечание: в 291 треке отсутствует жанр (группа). Это проблема, которую мы рассмотрим во второй части этой серии.

Следующие шаги

Сохраните этот фрейм данных в файл CSV:

data.to_csv('tracklist.csv', index=False, encoding='utf-8')

В следующих статьях я:

  • Проведите исследовательский анализ данных.
  • Покажите, как назначать жанры песням, у которых его нет.
  • Создавайте плейлисты из сохраненных песен, где музыка автоматически сортируется с помощью машинного обучения.
  • Автоматизируйте этот процесс.

Записная книжка доступна на моем GitHub:

Большое спасибо Нильсу Дженниссену и Габриэлю Ронно, с которыми я работал над этим проектом. Не забудьте подписаться на его Medium и GitHub:

  • https://medium.com/@nilsjennissen
  • https://github.com/nilsjenn
  • https://medium.com/@gabriel_renno
  • https://github.com/GabrielRenno

Прекрасная иллюстрация сделана Катериной Малачковой. Обязательно загляните на ее Medium и Instagram!

  • https://medium.com/@malachkovak
  • https://instagram.com/ph_malachkova?igshid=ZjE2NGZiNDQ=
  • https://github.com/rubentak
  • https://www.linkedin.com/in/ruben-tak-665b66194/