Обзор:

  • KKBox — это платформа потоковой передачи музыки, такая как gaana.com, saavan.com.., они предоставили свой набор данных ML_community через kaggle.com, и они хотят, чтобы ML_community создала лучшую систему музыкальных рекомендаций с использованием новых алгоритмов, в настоящее время они используют совместную фильтрацию. алгоритмы на основе матричной факторизации и встраивания слов в свою рекомендательную систему.
  • https://www.kaggle.com/c/kkbox-music-recommendation-challenge/обзор

Содержание:

  1. Постановка задачи машинного обучения
  2. Обсуждение данных
  3. ЭДА
  4. Разработка функций
  5. Предварительная обработка данных
  6. Модели
  7. Сравнение
  8. Резюме и будущая работа
  9. использованная литература

1. Постановка задачи ML:

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

2. Обсуждение данных:

Источник набора данных: https://www.kaggle.com/c/kkbox-music-recommendation-challenge/data

задача имеет 6 файлов данных:

1.train.csv: этот файл включает

user_id (msno), song_id, source_system_tab (где было инициировано событие),
source_type (точка входа, когда пользователь впервые проигрывает музыку), source_screen_name (имя макета, которое видит пользователь) и target ( 1 означает повторяющееся события прослушивания, инициированные в течение месяца после самого первого наблюдаемого события прослушивания пользователем, в противном случае target=0 ).

2. test.csv: этот файл включает

user_id (msno), song_id, source_system_tab (где было инициировано событие),
source_type (точка входа, в которой пользователь впервые воспроизводит музыку) и source_screen_name (имя макета, которое видит пользователь).

3. song.csv: в этом файле есть такие функции, как

song_id, song_length, жанр_id, artist_name, композитор, автор текста и язык.

4.members.csv: этот файл имеет msno (user_id), city, bd (может содержать выбросы), пол, register_via (метод регистрации), register_init_time (дата) и expiartion_date (дата).

5. song_extra_info.csv: этот файл содержит такие функции, как song_id, song_name и
ISRC (международный стандартный код записи), используемые для идентификации песен.

3. ЭДА:

Цель EDA — понять наш набор данных, какие функции будут важны для построения моделей машинного обучения, а также найти ошибку в нашем наборе данных с использованием различных методов визуализации, которые мы собираемся изучить в этом сообщении блога.

  • members.csv: для этого CSV-файла, если мы используем Members.head(), он отобразит первые пять строк CSV-файла участников.

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

бд столбец:

Коробчатая диаграмма: как мы знаем, любое значение/точка вне рамки считается выбросом.

Графический график:

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

count=0
for i in members["bd"]:
 if i<=50 and i>=10:
   count+=1
percentage=(count/len(members["bd"]))*100
percentage=("{:.2f}".format(percentage))
print(percentage,"% of user is between 10 and 50")
output: 40.74 % of user is between 10 and 50

Мы видим, что только около 41% пользователей имеют возраст от 10 до 50 лет, что является правильным возрастом для этой проблемы.

Столбец Пол:

Сверху пирога можно сказать, что соотношение мужского и женского пола почти уравновешено.

Столбец "Город":

Из приведенного выше подсчета мы можем сказать, что город 1 имеет наибольшее количество пользователей.

инициализация_регистрации:

Из графика гистограммы можно сказать, что большинство пользователей зарегистрировались после 2016 года.

expiration_date:

Из приведенного выше графика гистограммы для даты истечения срока действия мы можем сказать, что срок действия большинства учетных записей пользователей истекает незадолго до 2020 года, и это очевидно, поскольку большинство пользователей зарегистрировались сразу после 2016 года.

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

Примечание. у нас есть файлы song_extra.csv и song.csv, и оба содержат информацию о песнях, поэтому мы можем объединить эти два CSV-файла, чтобы получить один файл как song_info.

song_info = song_extra.merge(songs, on='song_id', how='left') #merging song_extra.csv and songs.csv

Давайте найдем процентное значение NaN во всех функциях:

Мы видим, что композитор и автор текстов имеют самый высокий процент значений NaN s.

train.csv:

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

из приведенного выше графика видно, что большинство пользователей предпочитают слушать из локального плейлиста

Примечание. Как мы знаем, файл train.csv содержит msno и song_id, что означает, что информация о песнях, а также участники могут быть объединены в него.

train_and_members = pd.merge(train, members, on='msno', how='left')
final_train       = pd.merge(train_and_members, song_info,                   on='song_id', how='left')

Тепловая карта final_train:

› Из приведенной выше тепловой карты мы можем сказать, что композитор, автор текстов, isrc, имя имеют наибольшее количество пропущенных значений

› Композитор и автор текстов имеют сильную корреляцию между собой и source_sytem_tab, а source_type также имеет сильную корреляцию между собой

4. Особенности проектирования:

До сих пор мы исследовали наши CSV-файлы и обнаружили, что большинство функций сбалансированы, за исключением того, что функция bd и столбец гендера имеют значения NaN, поэтому при разработке функций мы заполним недостающие значения и попытаемся извлечь новую функцию из существующей функции и попытаться создать новую функцию. путем группировки двух или более признаков.

— Лука Массарон В основном, чтобы решить любую задачу ML, нам нужны данные, которые мы передаем нашему алгоритму ML, и для правильного вывода ему нужны соответствующие данные в качестве входных данных, поэтому необходимо сгенерировать или найти полезную функцию из существующих данных, что называется проектированием функций.

Численное вменение:

Это означает заполнение пропущенных значений соответствующим значением, поскольку в нашем наборе данных мы видели, что в столбцах bd и gender файлаmembers.csv много пропущенных значений.

Столбец Пол:

Как мы знаем, у нас есть 58% значения NaN в признаке пола, и, поскольку это текстовый/категориальный признак, мы можем приписать значение NaN с помощью поле_не_доступен.

from numpy import nan
# mark zero values as missing or NaN
# fill missing values with mean column values
final_train["gender"].fillna("gender_not_available", inplace=True)
# count the number of NaN values in each column

Для каждой текстовой/категориальной функции мы можем выполнить вменение следующим образом.

Функция БД:

Мы знаем, что функция ib bd имеет значение 50% как ноль, и есть некоторая крайняя точка, поэтому мы можем заполнить это значение средним значением функции bd.

final_train["bd"].fillna(members["bd"].mean(), inplace=True)
# count the number of NaN values in each column
print(members["bd"].isnull().sum())

Мы попытаемся найти год, месяц и день из Registration_init и expire_date для того, чтобы сначала мы преобразовали эту функцию в формат date.time.

import pandas as pd
import numpy as np
import datetime
members["expiration_date"]= pd.to_datetime(members["expiration_date"],format='%Y%m%d')
members["registration_init_time"]= pd.to_datetime(members["registration_init_time"],format='%Y%m%d')

Нахождение года, месяца и дня из Registration_init аналогично тому, что мы можем сделать с expire_date

код, используемый из: https://medium.com/@swethalakshmanan14/simple-ways-to-extract-features-from-date-variable-using-python-60c33e3b0501

final_train['year']=  final_train['registration_init_time'].dt.year
final_train['month']= final_train['registration_init_time'].dt.month
final_train['day'] =final_train['registration_init_time'].dt.day

сгруппировать несколько функций, чтобы получить больше контекста из наших данных и получить новую функцию:

как мы видели, есть много повторяющихся значений song_id и msno, что означает, что есть много пользователей, которые слушают одну и ту же песню и предпочитают какого-то исполнителя, например, мне нравится arjit singh.

https://github.com/khushi810/KKBOX_Music_Recommendation_Challenge/blob/master/Music_Recommendation_(EDA%2BFE).ipynb

member_song_count = final_train.groupby('msno').count()['song_id'].to_dict()
final_train['member_song_count'] = final_train['msno'].apply(lambda x: member_song_count[x])
#artist count for each song
artist_song_count = final_train.groupby('artist_name').count()['song_id'].to_dict()
final_train['artist_song_count'] = final_train['artist_name'].apply(lambda x: artist_song_count[x])
#genre count for each song
first_genre_id_song_count = final_train.groupby('genre_id').count()['song_id'].to_dict()
final_train['genre_id'] = final_train['genre_id'].apply(lambda x: first_genre_id_song_count[x])
#language count for each song
lang_song_count = final_train.groupby('language').count()['song_id'].to_dict()
final_train['lang_song_count'] = final_train['language'].apply(lambda x: lang_song_count[x])
#user count for each song
song_member_count = final_train.groupby('song_id').count()['msno'].to_dict()
final_train['song_member_count'] = final_train['song_id'].apply(lambda x: song_member_count[x])
#agecount for each song
age_song_count = final_train.groupby('bd').count()['song_id'].to_dict()
final_train['age_song_count'] = final_train['bd'].apply(lambda x: age_song_count[x])

Итак, теперь у нас есть final_train в качестве нашего окончательного набора данных, поверх которого мы попробуем построить другую модель мл

5. Предварительная обработка данных:

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

Y = final_train['target'].values
X = final_train.drop(['target'], axis=1)
#splitting data into train, test and cross validation
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(X,Y,test_size=0.40,random_state=42)
x_train,x_cv,y_train,y_cv    =train_test_split(x_train,y_train,test_size=0.33,random_state=42)

Примечание. Из-за ограничения ОЗУ я использую меньше данных, но если у нас больше ОЗУ, чем мы можем использовать целиком, результат будет лучше.

x_train = x_train[:2965721]
y_train = y_train[:2965721]
x_cv = x_cv[:100000]
y_cv = y_cv[:100000]
x_test = x_test[:2556790]
y_test = y_test[:2556790]

Кодировка метки для числового объекта:

numeric_features = ['bd','city','language','registered_via','song_duration_minutes','genre_id','song_year','member_song_count', 'artist_song_count',\
'lang_song_count', 'song_member_count', 'age_song_count']
# transform numeric values
pd.set_option('mode.chained_assignment', None)
for feature in numeric_features:
   scaler           = StandardScaler()
   
   x_train[feature] =   
   scaler.fit_transform(x_train[feature].values.reshape(-1,1))
   x_cv[feature]    =   
   scaler.transform(x_cv[feature].values.reshape(-1,1))
   x_test[feature]  =  
   scaler.transform(x_test[feature].values.reshape(-1,1))

Мы можем сделать то же самое с нашей категориальной функцией.

6.Модели:

Логистическая регрессия: в нашей задаче очень важно выполнять настройку гиперпараметров.

# Hyper parameter tuning using GridearchCV for LR
start = time.time()
parameters = {
'penalty':['l2', 'l1'],
'alpha':[10 ** x for x in range(0, 1)]
}
clf = SGDClassifier(loss='log', n_jobs=-1, random_state=23, class_weight='balanced')
model = GridSearchCV(clf, parameters, scoring = 'roc_auc', n_jobs=-1, verbose=2, cv=3)
model.fit(x_train, y_train)
print(model.best_estimator_)
print('train AUC = ',model.score(x_train, y_train))
print('val AUC = ',model.score(x_cv, y_cv))
print('Time taken for hyper parameter tuning is : ', (time.time() -  start))
print('Done!')

Обучение нашей логистической регрессии с нашим лучшим параметром:

# train LR with best parameters
lr = SGDClassifier(alpha=1, average=False, class_weight='balanced',
early_stopping = False, epsilon=0.1, eta0=0.0, fit_intercept=True,
l1_ratio=0.15, learning_rate='optimal', loss='log', max_iter=1000,
n_iter_no_change=5, n_jobs=-1, penalty='l2', power_t=0.5,
random_state=23, shuffle=True, tol=0.001, validation_fraction=0.1,
verbose=0, warm_start=False)
lr.fit(x_train, y_train)

Поиск важной функции:

# create dataframe for features and it importance
sorted_indices = lr.coef_[0].argsort()
features = x_train.columns[sorted_indices]
lr_fea_imp = pd.DataFrame({'features' : features,'importance' lr.coef_[0]})

Важная функция:

Мы видим, что месяц и язык имеют наивысшую важность функции.

Матрица путаницы:

Чувствительность:

Он отвечает на вопрос: «Насколько чувствителен классификатор при обнаружении положительных экземпляров?»

Конкретность:

Он отвечает на вопрос: «Насколько специфичен или избирательен классификатор в прогнозировании положительных случаев?»

График чувствительности и специфичности:

РЕЗЮМЕ для логистической регрессии:

  • Для логистической регрессии точность является лучшей метрикой, потому что точность показывает, насколько точна наша модель. В нашем случае наша модель имеет точность 50%, потому что мы используем меньше данных из-за ограничения ОЗУ и чувствительности матрицы путаницы, а специфичность показывает большую часть точек, которые предсказывает наша модель. правильный

Мы можем сделать то же самое со всеми различными моделями, такими как дерево решений, классификатор случайного леса, классификатор XGB, классификатор повышения Ada и легкий gbm.

Модель глубокого обучения (LSTM):

Давайте попробуем глубокое обучение, для dl мы будем использовать модель LSTM, перед моделью LSTM мы должны знать архитектуру модели LSTM, эта модель использует трехмерную функцию, но у нас есть двумерная функция, поэтому мы можем np.reshape() для преобразования 2D в 3D

data_xcv   = x_cv.to_numpy()
x_cv_new   = data_xcv.reshape(100000,1,31)
data_xte   = x_test.to_numpy()
x_test_new = data_xte.reshape(2556790,1,31)
data_xtr   = x_train.to_numpy()
x_train_new= data_xtr.reshape(2965721,1,31)
BATCH_SIZE = 64
FEATURES   = 31
def define_model(BATCH_SIZE, FEATURES):
'''Function to define model'''
  tf.keras.backend.clear_session()
  tf.random.set_seed(1234)
  input = Input(shape=(None, FEATURES), name='Input_layer')
  hidden1 = LSTM(256)(input)
  hidden2 = Dense(256, activation='relu')(hidden1)
  output  = Dense(1, activation='sigmoid')(hidden2)
  model   = Model(inputs=input, outputs=output)
  model.summary()
  return model
model = define_model(BATCH_SIZE, FEATURES)

Построение архитектуры LSTM:

Обучение нашей модели LSTM:

EPOCHS = 10
print("Fit model on training data")
history = model.fit(x_train_n,y_train,
batch_size=64, epochs=EPOCHS,
validation_data=(x_cv_new, y_cv),callbacks=[tensorboard_callback, early_stoppings])

7. Сравнение: модели и их соответствующие оценки поездов, оценки проверки и оценки kaggle:

8. РЕЗЮМЕ и будущая работа

  • На изображении выше мы видим, что LogisticRegression получила наивысший балл Kaggle, поэтому мы можем использовать нашу обученную LogisticRegression для прогнозирования невидимых данных.
  • EDA: мы проанализировали весь наш набор данных, используя различные методы визуализации, такие как столбчатая диаграмма, коробчатая диаграмма, PDF и т. д., мы обнаружили, что многие пропущены, NaN, присутствовали неверные данные.
  • Разработка функций: на этапах разработки функций мы удалили все отсутствующие значения и значения NaN и заменили их медианным значением столбца, исправили неверные данные, а затем извлекли новые функции из существующих функций, например, мы извлекли месяц, год, день. из столбцов Registration_init_time и expirate_date, и мы также сделали группировку по операциям, придумав больше новой функции
  • Подготовка данных. Мы разделили наш набор данных на пропорции 60–40 с помощью sklearn. Из-за ограничения ОЗУ мы не использовали весь наш набор данных, что привело к меньшей точности и оценке.
  • Предварительная обработка данных. Мы преобразовали все наши числовые характеристики с помощью стандартизации. Для категориальных функций мы использовали кодировку меток.
  • Примененные модели: перед применением любого алгоритма машинного обучения мы выполнили настройку гиперпараметров, чтобы получить наилучшие параметры, а затем применили различные алгоритмы машинного обучения, такие как LR, DT, RF, XgBoost, AdaBoost, LightGBM. Мы также попробовали алгоритм глубокого обучения LSTM.
  • Будущие работы :Поскольку у нас меньше данных из-за ограничения ОЗУ, мы не получаем желаемого результата, но если мы можем использовать все данные, мы можем получить лучший результат. Мы можем добавить больше функций в будущем, и если мы сделаем больше гиперпараметров, мы определенно сможем получить результат.

9. Ссылки:

  1. https://medium.com/@briansrebrenik/introduction-to-music-recommendation-and-machine-обучение
  2. https://www.kaggle.com/rohandx1996/recommendation-system-with-83-accuracy-lgbm
  3. https://github.com/llSourcell/recommender_live/blob/master/Song%20Recommender_Python.ipynb
  4. https://towardsdatascience.com/the-keys-building-collaborative-filtering-music-recommendder-65ec3900d19f
  5. https://www.appliedaicourse.com/course/11/Applied-Machine-learning-course

ссылка на github: https://github.com/anzaraquil/KKBOX-music-recommendation-system

Профиль LinkdIn:https://www.linkedin.com/in/md-anzar-aquil-ansari-46431617b/

Не стесняйтесь подключаться, если у вас есть какие-либо сомнения.

Спасибо за ваше драгоценное время