IIS_2023_1/istyukov_timofey_lab_5/lab5.py

108 lines
5.5 KiB
Python
Raw Normal View History

2024-01-11 00:25:09 +04:00
"""
Использовать регрессию по варианту для своих данных по варианту, самостоятельно сформулировав задачу.
Оценить, насколько хорошо она подходит для решения сформулированной вами задачи.
"""
"""
Задача, решаемая регрессией:
Предсказание популярности нового музыкального трека на основе его определённых характеристик.
Регрессионная модель может предсказывать числовую оценку популярности трека,
что может быть полезно для музыкальных платформ по типу 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()