diff --git a/kochkareva_elizaveta_lab_2/README.md b/kochkareva_elizaveta_lab_2/README.md new file mode 100644 index 0000000..155ff05 --- /dev/null +++ b/kochkareva_elizaveta_lab_2/README.md @@ -0,0 +1,136 @@ + +# Лабораторная работа 2. Вариант 15 + +### Задание +Выполнить ранжирование признаков с помощью указанных по +варианту моделей. Отобразить получившиеся значения\оценки каждого +признака каждым методом\моделью и среднюю оценку. + +3 модели: +- Случайное Лассо (RandomizedLasso) +- Рекурсивное сокращение признаков (Recursive Feature Elimination – RFE) +- Линейная корреляция (f_regression) + +### Как запустить лабораторную работу +Для запуска программы необходимо с помощью командной строки в корневой директории файлов прокета прописать: +``` +python main.py +``` + +### Какие технологии использовали +- Библиотека *numpy* для работы с массивами. +- Библиотека *itemgetter* для использования функции для выбора элементов из коллекции. +- Библиотека *sklearn*: + - *LinearRegression* для создания и работы с моделью Линейной регрессии. + - *Ridge* для создания и работы с моделью линейной регрессии с регуляризацией + - *MinMaxScaler* - для нормализации данных путем масштабирования значений признаков в диапазоне от 0 до 1. + - *RFE, f_regression* - RFE используется для рекурсивного отбора признаков, а f_regression - для вычисления корреляции между каждым признаком и целевой переменной. + + +### Описание лабораторной работы +#### Генерация данных +Создаем массив `X` размером (750, 14), где каждый элемент выбирается случайным образом из равномерного распределения на интервале от 0 до 1. Затем вычисляем массив `Y`, используя формулу, отрадающую зависимость значения `Y` от значений в массиве `X` и состоящую из случайного шума. +Изменяем значения последних четырех столбцов массива `X`. Значения этих столбцов становятся суммой первых четырех столбцов и случайного шума. Создаем список names, который содержит названия признаков, и пустой словарь ranks, который будет использоваться для хранения значений важности признаков. + +```python +np.random.seed(0) +size = 750 +X = np.random.uniform(0, 1, (size, 14)) +# Задаем функцию-выход: регрессионную проблему Фридмана +Y = (10 * np.sin(np.pi*X[:, 0]*X[:, 1]) + 20*(X[:, 2] - .5)**2 + 10*X[:, 3] + 5*X[:, 4]**5 + np.random.normal(0, 1)) +# Добавляем зависимость признаков +X[:, 10:] = X[:, :4] + np.random.normal(0, .025, (size, 4)) +names = ["x%s" % i for i in range(1, 15)] # - список признаков вида ['x1', 'x2', 'x3', ..., 'x14'] +ranks = dict() +``` +#### Обработка результатов + Создаем функцию `rank_to_dict`, которая принимает два аргумента: `ranks` (оценки важности признаков) и `names` (названия признаков). В данной функции создается словарь, используя `zip` для объединения названий признаков и округленных оценок важности признаков. Названия признаков становятся ключами словаря, а округленные оценки - значениями. + +```python +def rank_to_dict(ranks, names): + # получение абсолютных значений оценок(модуля) + ranks = np.abs(ranks) + minmax = MinMaxScaler() + # преобразование данных + ranks = minmax.fit_transform(np.array(ranks).reshape(14, 1)).ravel() + # округление элементов массива + ranks = map(lambda x: round(x, 2), ranks) + # преобразование данных + return dict(zip(names, ranks)) +``` + +#### Модель Ridge + +Так как по заданию необходимо работать с устаревшей моделью случайное *Лассо (RandomizedLasso)*, воспользуемся *Ridge-регрессией (Ridge Regression)*. +Создадим экземпляр модели *Ridge*, которая используется для выполнения регрессии с использованием линейной комбинации признаков, которая применяет регуляризацию L2 для уменьшения влияния мультиколлинеарности в данных. +Обучаем модель *Ridge* с использованием метода `.fit(X, Y)`. Здесь `X` представляет собой матрицу признаков (независимые переменные), а `Y` - вектор целевой переменной (зависимая переменная). Модель обучается на этих данных, чтобы найти оптимальные значения коэффициентов регрессии. Далее отправляем полученные коэффициенты в метод `rank_to_dict` для обрезования данных в необходимый вид. + +```python +ridge_model = Ridge() +ridge_model.fit(X, Y) +ranks['Ridge'] = rank_to_dict(ridge_model.coef_, names) +``` + +#### Модель рекурсивное сокращение признаков (Recursive Feature Elimination – RFE) +Для работы с моделью рекурсивного сокрщения признаков создадим две функции: `recursive_feature_elimination()` и `rank_to_dict_rfe(ranking, names)`. + +В функции `recursive_feature_elimination()` создаем экземпляр модели *LinearRegression* под именем `estimator`. Далее создаем экземпляр модели *RFE (Recursive Feature Elimination)* под именем `rfe_model`, передавая `estimator` в качестве аргумента конструктора. Обучаем `rfe_model` на данных `X` и `Y`. Затем добавляем ранги признаков, полученные от `rfe_model`, в словарь `ranks` под ключом *'Recursive Feature Elimination'*, используя функцию `rank_to_dict_rfe()`. + +```python +def recursive_feature_elimination(): + # создание модели LinearRegression + estimator = LinearRegression() + # создание модели RFE + rfe_model = RFE(estimator) + rfe_model.fit(X, Y) + ranks['Recursive Feature Elimination'] = rank_to_dict_rfe(rfe_model.ranking_, names) +``` +В функции `rank_to_dict_rfe(ranking, names)` находит обратные значения рангов признаков, делим 1 на каждый ранг. Округляем элементы полученного массива до двух знаков после запятой, используя функцию `round()`. И возвращаем словарь, где имена признаков из `names` являются ключами, а значениями являются округленные обратные значения рангов. +```python +def rank_to_dict_rfe(ranking, names): + # нахождение обратных значений рангов + n_ranks = [float(1 / i) for i in ranking] + # округление элементов массива + n_ranks = map(lambda x: round(x, 2), n_ranks) + # преобразование данных + return dict(zip(names, n_ranks)) +``` + +#### Линейная корреляция (f_regression) +Для работы с линейной корреляцией выполним линейную корреляцию между признаками в матрице `X` и целевой переменной `Y`. Для этого используем функцию `f_regression()` для выполнения линейной регрессии между каждым признаком в матрице `X` и целевой переменной `Y`. После этого возвращается два массива: `correlation` содержит значения коэффициентов корреляции между признаками и `Y`, а `p_values` содержит соответствующие p-значения для каждого коэффициента корреляции. После чего создаем новую запись в словаре `ranks` с ключом *'linear correlation'*. + +```python +correlation, p_values = f_regression(X, Y) +ranks['linear correlation'] = rank_to_dict(correlation, names) +``` + +### Вывод + +Согласно условию задания значимыми параметрами были: *x1, x2, x3, x4, x5*. А зависимыми от них *x10, x11, x12, x13, x14*. + +После сортировки полученных результатов работы моделей, можем увидеть следующее: +``` +Ridge +[('x4', 1.0), ('x1', 0.98), ('x2', 0.8), ('x14', 0.61), ('x5', 0.54), ('x12', 0.39), ('x3', 0.25), ('x13', 0.19), ('x11', 0.16), ('x6', 0.08), ('x8', 0.07), ('x7', 0.02), ('x10', 0.02), ('x9', 0.0)] +Recursive Feature Elimination +[('x1', 1.0), ('x2', 1.0), ('x3', 1.0), ('x4', 1.0), ('x5', 1.0), ('x11', 1.0), ('x13', 1.0), ('x12', 0.5), ('x14', 0.33), ('x8', 0.25), ('x6', 0.2), ('x10', 0.17), ('x7', 0.14), ('x9', 0.12)] +linear correlation +[('x4', 1.0), ('x14', 0.98), ('x2', 0.45), ('x12', 0.44), ('x1', 0.3), ('x11', 0.29), ('x5', 0.04), ('x8', 0.02), ('x7', 0.01), ('x9', 0.01), ('x3', 0.0), ('x6', 0.0), ('x10', 0.0), ('x13', 0.0)] + +``` +Как можно заметить в модели *Ridge* параметры *x1, x2, x4, x5* имеют наибольшую значимость, что соответстует исходному условию задания, однако был потерян признак *x3*, значимость которого была показана низкой. + +Модель *Recursive Feature Elimination* правильно показала все наиболее значиме признаки *x1, x2, x3, x4, x5*. + +В модели линейной корреляции параметры *'x4'* и *'x14'* имеют наибольшую корреляцию, равную 1.0. Параметры *'x3', 'x6', 'x10' и 'x13'* имеют наименьшую корреляцию, равную 0.0. Таким образом, показав наихудний результат среди трех моделей. + +В среднем по работе трех моделей имеем следующий результат, где параметр *'x4'* имеет наибольшую значимость, равную 1.0, параметр *'x9'* имеет наименьшую значимость, равную 0.04.: + +``` +Mean +[('x4', 1.0), ('x1', 0.76), ('x2', 0.75), ('x14', 0.64), ('x5', 0.53), ('x11', 0.48), ('x12', 0.44), ('x3', 0.42), ('x13', 0.4), ('x8', 0.11), ('x6', 0.09), ('x7', 0.06), ('x10', 0.06), ('x9', 0.04)] + +``` + + +Таким образом, можно сделать вывод о том, лучше всех справилась модель *Recursive Feature Elimination*, а также, что порядок значимости параметров может немного различаться в зависимости от модели. \ No newline at end of file diff --git a/kochkareva_elizaveta_lab_2/main.py b/kochkareva_elizaveta_lab_2/main.py new file mode 100644 index 0000000..31376e1 --- /dev/null +++ b/kochkareva_elizaveta_lab_2/main.py @@ -0,0 +1,88 @@ +from operator import itemgetter +import numpy as np +from sklearn.feature_selection import RFE, f_regression +from sklearn.preprocessing import MinMaxScaler +from sklearn.linear_model import Ridge +from sklearn.linear_model import LinearRegression + +# генерируем исходные данные: 750 строк-наблюдений и 14 столбцов-признаков +np.random.seed(0) +size = 750 +X = np.random.uniform(0, 1, (size, 14)) +# Задаем функцию-выход: регрессионную проблему Фридмана +Y = (10 * np.sin(np.pi*X[:, 0]*X[:, 1]) + 20*(X[:, 2] - .5)**2 + 10*X[:, 3] + 5*X[:, 4]**5 + np.random.normal(0, 1)) +# Добавляем зависимость признаков +X[:, 10:] = X[:, :4] + np.random.normal(0, .025, (size, 4)) +names = ["x%s" % i for i in range(1, 15)] # - список признаков вида ['x1', 'x2', 'x3', ..., 'x14'] +ranks = dict() + + +def rank_to_dict(ranks, names): + # получение абсолютных значений оценок(модуля) + ranks = np.abs(ranks) + minmax = MinMaxScaler() + # преобразование данных + ranks = minmax.fit_transform(np.array(ranks).reshape(14, 1)).ravel() + # округление элементов массива + ranks = map(lambda x: round(x, 2), ranks) + # преобразование данных + return dict(zip(names, ranks)) + + +# Модель: случайное Лассо (RandomizedLasso) - устаревшее, поэтому используем Ridge-регрессия (Ridge Regression) +def ridge_regressions(): + # Создание экземпляра модели Ridge + ridge_model = Ridge() + ridge_model.fit(X, Y) + ranks['Ridge'] = rank_to_dict(ridge_model.coef_, names) + + +# Модель: рекурсивное сокращение признаков (Recursive Feature Elimination – RFE) +def recursive_feature_elimination(): + # создание модели LinearRegression + estimator = LinearRegression() + # создание модели RFE + rfe_model = RFE(estimator) + rfe_model.fit(X, Y) + ranks['Recursive Feature Elimination'] = rank_to_dict_rfe(rfe_model.ranking_, names) + + +def rank_to_dict_rfe(ranking, names): + # нахождение обратных значений рангов + n_ranks = [float(1 / i) for i in ranking] + # округление элементов массива + n_ranks = map(lambda x: round(x, 2), n_ranks) + # преобразование данных + return dict(zip(names, n_ranks)) + + +# Модель: линейная корреляция (f_regression) +def linear_correlation(): + # вычисление линейной корреляции между X и y + correlation, p_values = f_regression(X, Y) + ranks['linear correlation'] = rank_to_dict(correlation, names) + + +if __name__ == '__main__': + ridge_regressions() + recursive_feature_elimination() + linear_correlation() + + for key, value in ranks.items(): # Вывод нормализованных оценок важности признаков каждой модели + ranks[key] = sorted(value.items(), key=itemgetter(1), reverse=True) + for key, value in ranks.items(): + print(key) + print(value) + + mean = {} # - нахождение средних значений оценок важности по 3м моделям + for key, value in ranks.items(): + for item in value: + if item[0] not in mean: + mean[item[0]] = 0 + mean[item[0]] += item[1] + for key, value in mean.items(): + res = value / len(ranks) + mean[key] = round(res, 2) + mean = sorted(mean.items(), key=itemgetter(1), reverse=True) + print("Mean") + print(mean) \ No newline at end of file