import numpy as np
import pandas as pd
from sklearn.datasets import make_regression
from sklearn.linear_model import LinearRegression
from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestRegressor
from sklearn.preprocessing import MinMaxScaler

# Используя код из [1](пункт «Решение задачи ранжирования признаков», стр.  205),  выполните  ранжирование признаков
# с помощью указанных по варианту моделей.  Отобразите получившиеся значения\оценки каждого признака каждым
# методом\моделью и среднюю оценку.  Проведите анализ получившихся результатов.  Какие четыре признака оказались
# самыми важными по среднему значению?  (Названия\индексы признаков и будут ответом на задание).

# Линейная регрессия (LinearRegression), Рекурсивное сокращение признаков (Recursive Feature Elimination –RFE),
# Сокращение признаков Случайными деревьями (Random Forest Regressor)
random_state = np.random.RandomState(2)

# Генерация случайных данных для регрессии
X, y = make_regression(n_samples=100, n_features=10, noise=0.1, random_state=random_state)

# Создание DataFrame для данных
data = pd.DataFrame(X, columns=[f'признак_{i}' for i in range(X.shape[1])])
data['целевая_переменная'] = y

# Разделение данных на признаки (X) и целевую переменную (y)
X = data.drop('целевая_переменная', axis=1)
y = data['целевая_переменная']

# Создаем модели
models = [
    ("Линейная регрессия", LinearRegression()),
    ("Рекурсивное сокращение признаков", RFE(LinearRegression(), n_features_to_select=1)),
    ("Сокращение признаков Случайными деревьями", RandomForestRegressor())
]

# Словарь для хранения оценок каждой модели
model_scores = {}

# Обучение и оценка моделей
for name, model in models:
    model.fit(X, y)
    if name == "Рекурсивное сокращение признаков":
        # RFE возвращает ранжирование признаков
        rankings = model.ranking_
        # Нормализация рангов так, чтобы они находились в диапазоне от 0 до 1
        normalized_rankings = 1 - (rankings - 1) / (np.max(rankings) - 1)
        model_scores[name] = normalized_rankings
    elif name == "Сокращение признаков Случайными деревьями":
        # Важность признаков для RandomForestRegressor
        feature_importances = model.feature_importances_
        # Нормализация значений важности признаков в диапазоне от 0 до 1
        normalized_importances = MinMaxScaler().fit_transform(feature_importances.reshape(-1, 1))
        model_scores[name] = normalized_importances.flatten()
    elif name == "Линейная регрессия":
        # Коэффициенты признаков для Linear Regression
        coefficients = model.coef_
        # Нормализация коэффициентов так, чтобы они находились в диапазоне от 0 до 1
        normalized_coefficients = MinMaxScaler().fit_transform(np.abs(coefficients).reshape(-1, 1))
        model_scores[name] = normalized_coefficients.flatten()

# Вывод оценок каждой модели
for name, scores in model_scores.items():
    print(f"{name} оценки признаков:")
    for feature, score in enumerate(scores, start=1):
        print(f"Признак {feature}: {score:.2f}")
    print(f"Средняя оценка: {np.mean(scores):.2f}")
    print()

# Находим четыре наиболее важных признака по средней оценке
all_feature_scores = np.mean(list(model_scores.values()), axis=0)
sorted_features = sorted(enumerate(all_feature_scores, start=1), key=lambda x: x[1], reverse=True)
top_features = sorted_features[:4]
print("Четыре наиболее важных признака:")
for feature, score in top_features:
    print(f"Признак {feature}: {score:.2f}")