Merge pull request 'istyukov_timofey_lab_4 is ready' (#289) from istyukov_timofey_lab_4 into main

Reviewed-on: http://student.git.athene.tech/Alexey/IIS_2023_1/pulls/289
This commit is contained in:
Alexey 2024-01-09 11:29:35 +04:00
commit 8673873a52
6 changed files with 50169 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -0,0 +1,78 @@
# Лабораторная работа №4. Кластеризация
## 12 вариант
___
### Задание:
Использовать для своих данных метод кластеризации по варианту,
самостоятельно сформулировав задачу. Интерпретировать результаты и оценить,
насколько хорошо он подходит для решения сформулированной вами задачи.
### Вариант:
- Алгоритм кластеризации: **linkage**
### Вариант набора данных по курсовой работе:
- Прогнозирование музыкальных жанров ("Prediction of music genre")
___
### Запуск
- Запустить файл lab4.py
### Используемые технологии
- Язык программирования **Python**
- Среда разработки **PyCharm**
- Библиотеки:
* pandas
* scipy
* matplotlib
### Описание программы
**Набор данных (Kaggle):** Полный список жанров, включенных в CSV:
«Электронная музыка», «Аниме», «Джаз», «Альтернатива», «Кантри», «Рэп»,
«Блюз», «Рок», «Классика», «Хип-хоп».
**Задача, решаемая алгоритмом кластеризации:**
Группировка музыкальных треков на основе их характеристик с целью создания
кластеров треков с схожими характеристиками. Алгоритм кластеризации может
помочь в создании плейлистов и рекомендаций, основанных на схожести
музыкальных треков по некоторым характеристикам.
**Задача оценки:**
Анализ получившейся иерархической структуры с помощью дендрограмме.
---
### Пример работы
*Датасет, сформированный из случайных строк csv-файла.*
![Graphics](2_dataset.jpg)
---
*Визуализация дерева, представляющего иерархическое слияние кластеров,
в виде дендрограммы. Это может быть полезно для понимания структуры данных.*
![Graphics](1_dendrogram.png)
---
*Вывод первых 10 музыльных треков из датасета с их
принадлежностью к кластеру*
![Graphics](3_clusters.jpg)
### Вывод
С моими данными алгоритм справляется довольно успешно. На результате выше
можно сравнить два трека — "Gake No Ue No Ponyo" и "He Would Have Laughed".
В результате работы программы они были присвоены к кластеру №10.
При этом первый трек отнесён к жанру "Anime", а второй — к "Alternative".
Тем не менее, эти две песни похожи преобладанием инструментала в них
(в особенности перкуссии), а так же наличием ирландских мотивов в нём.
В ходе работы было проверено 8 пар музыкальных треков, принадлежащих
к разным кластерам. Как итог, больше половины пар действительно имели
много схожего в звучании или концепте аранжировки, несмотря на различия
по некоторым характеристикам (в том числе жанр).
Из плюсов иерархической кластеризации можно выделить отсутствие
конкретного количества кластеров, для поиска похожей музыки это
явно преимущество. Из минусов же — слишком медленная работа
на больших наборах данных (из-за чего и было взято 50% от всего датасета).

View File

@ -0,0 +1,85 @@
"""
Использовать для своих данных метод кластеризации по варианту, самостоятельно сформулировав задачу.
Интерпретировать результаты и оценить, насколько хорошо он подходит для решения сформулированной вами задачи.
"""
"""
Задача, решаемая алгоритмом кластеризации:
Группировка музыкальных треков на основе их характеристик с целью создания кластеров треков
с схожими характеристиками. Алгоритм кластеризации может помочь в создании плейлистов и рекомендаций,
основанных на схожести музыкальных треков по некоторым характеристикам.
"""
# 12 вариант
# Набор данных по курсовой: "Prediction of music genre"
# Алгоритм кластеризации: linkage
import pandas as pd
from scipy.cluster.hierarchy import linkage, dendrogram, fcluster
import matplotlib.pyplot as plt
DATASET_FILE = 'music_genre.csv'
def main():
df = open_dataset(DATASET_FILE)
df = df.sample(frac=.5) # отбираем 50% рандомных строк с набора данных, т.к. он большой
print("\033[92m[-----> Набор данных <-----]\033[00m")
print(df)
# Перевод жанров и ладов (минор/мажор) в числовые признаки
df_genres = pd.get_dummies(df['music_genre'])
df_modes = pd.get_dummies(df['mode'])
# Объединение основной таблицы с числовыми признаками
df_music = pd.concat([df, df_genres, df_modes], axis=1).reindex(df.index)
# Удаление строковых стоблцов, которые заменили на числовые признаки
df_music = df_music.drop(columns=['music_genre', 'mode'])
# Датасет для работы с кластеризацией (без исполнителя и названия трека)
X = df_music.drop(columns=['artist_name', 'track_name'])
# Иерархическая кластеризация с связью ward
# (минимизация суммы квадратов разностей во всех кластерах)
linkage_matrix = linkage(X, method='ward', metric='euclidean')
# Формирование кластеров из матрицы связей
cluster_label = fcluster(Z=linkage_matrix, t=300, criterion='distance')
# Присвоение кластера треку
df['cluster'] = cluster_label
# Установка опции показа 3 столбцов при выводе
pd.set_option('display.max_columns', 3)
# Вывод результата кластеризации
print("\033[92m\nЫ[-----> Результат иерархической кластеризации <-----]\033[00m")
print(df[['artist_name', 'track_name', 'cluster']].head(10))
print("\033[92mКоличество кластеров: {}\033[00m" .format(cluster_label.max()))
# Дендрограмма
plt.figure(figsize=(12, 6))
dendrogram(linkage_matrix, truncate_mode='lastp', p=20, leaf_rotation=90., leaf_font_size=8., show_contracted=True)
plt.title('Дендрограмма иерархической кластеризации музыкальных треков')
plt.xlabel('Количество треков в узле')
plt.ylabel('Евклидово расстояние между треками')
plt.savefig('1_dendrogram')
plt.show()
# Функция считывания и очищения csv-файла
def open_dataset(csv_file):
# открываем файл с указанием знака-отделителя
df = pd.read_csv(csv_file, delimiter=',')
# выбираем необходимые признаки
df = df[['artist_name', 'track_name', 'mode', 'tempo', 'instrumentalness', 'acousticness',
'speechiness', 'danceability', 'energy', 'liveness', 'valence', 'music_genre']]
# очищаем набор данных от пустых и неподходящих значений
df = df[df['tempo'] != '?']
df = df.dropna()
return df
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff