IIS_2023_1/istyukov_timofey_lab_5/lab5.py
2024-01-11 00:25:09 +04:00

108 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Использовать регрессию по варианту для своих данных по варианту, самостоятельно сформулировав задачу.
Оценить, насколько хорошо она подходит для решения сформулированной вами задачи.
"""
"""
Задача, решаемая регрессией:
Предсказание популярности нового музыкального трека на основе его определённых характеристик.
Регрессионная модель может предсказывать числовую оценку популярности трека,
что может быть полезно для музыкальных платформ по типу Spotify.
"""
# 12 вариант
# Набор данных по курсовой: "Prediction of music genre"
# Тип регрессии: Логистическая регрессия
import pandas as pd
import warnings
import sklearn.exceptions
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix, f1_score
from sklearn.feature_selection import RFE
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_music = df.copy()
df_music['mode'] = df_music['mode'].apply(lambda x: 1 if x == 'Major' else 0)
# разделим проценты популярности на 4 уровня (от 0 до 3)
df_music['popularity'] = df_music['popularity'].apply(lambda x: int(x // 25))
X = df_music.drop(columns=['popularity']) # характеристики музыкального трека
y = df_music['popularity'] # уровень популярности
# Разделение датасета на тренировочные (95%) и тестовые данные (5%)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.05)
# Создание и обучение модели логистической регрессии
model = LogisticRegression(solver='lbfgs', max_iter=2000)
model.fit(X_train.values, y_train)
# Поиск 5 важных признаков
rfe = RFE(estimator=model, n_features_to_select=5)
rfe = rfe.fit(X_train.values, y_train)
features_ranks = pd.DataFrame({'Признак': X.columns.values, 'Выбор': rfe.support_, 'Ранг': rfe.ranking_})
print("\033[92m\n[----------> Оценка признаков, влияющих на популярность трека <----------]\033[00m")
print(features_ranks.sort_values(by=['Ранг']))
# Убираем незначительные признаки из датасета
del_features = features_ranks['Признак'][features_ranks['Ранг'] == True]
X_train = X_train[del_features]
X_test = X_test[del_features]
# Переобучаем на них модель
model.fit(X_train.values, y_train)
# Предсказание на тестовых данных уровня популярности трека
y_pred = model.predict(X_test.values)
# Формирование матрицы путаницы
cm = confusion_matrix(y_test, y_pred)
print("\033[92m\n[----------> Матрица путаницы <----------]\033[00m")
print(cm)
pred_true = sum(cm[i][i] for i in range(len(cm))) # верные прогнозы
pred_false = cm.sum() - pred_true # неверные прогнозы
print("\033[94mКол-во правильных предсказаний (главная диагональ) = {}\033[00m" .format(pred_true))
print("\033[91mКол-во неправильных предсказаний (остальное) = {}\033[00m".format(pred_false))
print("\033[92m\n[----------> Оценка модели <----------]\033[00m")
print('Точность модели на тестовых данных: {:.2f}'.format(model.score(X_test.values, y_test)))
print("\033[92m\n[----------> Отчёт о классификации по уровням <----------]\033[00m")
# игнор ошибки отсутствия некоторых классах при прогнозе (в данном случае 0 и 3)
warnings.filterwarnings("ignore", category=sklearn.exceptions.UndefinedMetricWarning)
print(classification_report(y_test, y_pred))
print("\033[95mМаксимально предсказанный уровень: {}\033[00m".format(y_pred.max()))
# Функция считывания и очищения csv-файла
def open_dataset(csv_file):
# открываем файл с указанием знака-отделителя
df = pd.read_csv(csv_file, delimiter=',')
# выбираем необходимые признаки
df = df[['duration_ms', 'mode', 'tempo', 'instrumentalness', 'acousticness', 'speechiness',
'danceability', 'energy', 'liveness', 'valence', 'loudness', 'popularity']]
# очищаем набор данных от пустых и неподходящих значений
df = df[df['tempo'] != '?']
df = df.dropna()
return df
if __name__ == "__main__":
main()