diff --git a/kozlov_alexey_lab_2/README.md b/kozlov_alexey_lab_2/README.md new file mode 100644 index 0000000..c00bf4b --- /dev/null +++ b/kozlov_alexey_lab_2/README.md @@ -0,0 +1,63 @@ +# Лабораторная работа №2. Ранжирование признаков +## 14 вариант +___ + +### Задание: +Используя код из [1](пункт «Решение задачи ранжирования признаков», стр. 205), выполните ранжирование признаков с помощью указанных по варианту моделей. Отобразите получившиеся значения\оценки каждого признака каждым методом\моделью и среднюю оценку. Проведите анализ получившихся результатов. Какие четыре признака оказались самыми важными по среднему значению? (Названия\индексы признаков и будут ответом на задание). + +### Модели по варианту: +- Случайное Лассо (RandomizedLasso) +- Сокращение признаков cлучайными деревьями (Random Forest Regressor) +- Линейная корреляция (f_regression) + +___ + +### Запуск +- Запустить файл lab2.py + +### Используемые технологии +- Язык программирования **Python** +- Среда разработки **PyCharm** +- Библиотеки: + * sklearn + * matplotlib + * numpy + +### Описание программы +1. Импортирует необходимые модули и классы: + - RandomForestRegressor из sklearn.ensemble для создания модели случайного леса регрессии; + - RandomizedLasso из RandomizedLasso для создания модели случайного Лассо (метода регуляризации линейной регрессии); + - f_regression из sklearn.feature_selection для выполнения линейной корреляции между признаками и целевой переменной; + - MinMaxScaler из sklearn.preprocessing для масштабирования оценок признаков к диапазону [0, 1]; + - numpy для работы с массивами данных. + +2. Определяет функцию generation_data, которая генерирует случайные данные для обучения модели. Для простоты, будут использованы заранее определенные случайные значения. + +3. Определяет функцию rank_to_dict, которая принимает ранговые оценки признаков и преобразует их в словарь с нормализованными значениями от 0 до 1. + +4. Определяет функцию get_estimation, которая вычисляет среднюю оценку по всем моделям и выводит отсортированный список признаков по убыванию оценки. + +5. Определяет функцию print_sorted_data, которая выводит отсортированные оценки признаков для каждой модели. + +6. Определяет функцию main, которая объединяет все шаги: генерацию данных, обучение моделей, расчет оценок признаков и вывод результатов. + +7. Вызывает функцию main для выполнения программы. + +___ +### Пример работы + +![Graphics](results.png) + + +### Вывод +На основе результатов можно сделать следующие выводы: + +1. Признаки x4, x2, x14 и x1 являются самыми важными. Их средние оценки по всем моделям составляют 0.82, 0.8, 0.66 и 0.56 соответственно. + +2. В модели случайного леса регрессии наиболее значимыми признаками являются x14, x2, x4 и x1. Они имеют оценки 1.0, 0.84, 0.77 и 0.74 соответственно. + +3. По результатам линейной корреляции (f-регрессия), самыми важными признаками также являются x4, x14, x2 и x12 с оценками 1.0, 0.97, 0.57 и 0.56 соответственно. + +4. В модели случайного Лассо наиболее значимыми признаками являются x2, x4, x1 и x5. Их оценки составляют 1.0, 0.69, 0.49 и 0.44 соответственно. + +Таким образом, можно сделать вывод, что признаки x4, x2, x14 и x1 являются наиболее значимыми для всех моделей. \ No newline at end of file diff --git a/kozlov_alexey_lab_2/RandomizedLasso.py b/kozlov_alexey_lab_2/RandomizedLasso.py new file mode 100644 index 0000000..8ac9681 --- /dev/null +++ b/kozlov_alexey_lab_2/RandomizedLasso.py @@ -0,0 +1,76 @@ +from sklearn.utils import check_X_y, check_random_state +from sklearn.linear_model import Lasso +from scipy.sparse import issparse +from scipy import sparse + + +def _rescale_data(x, weights): + if issparse(x): + size = weights.shape[0] + weight_dia = sparse.dia_matrix((1 - weights, 0), (size, size)) + x_rescaled = x * weight_dia + else: + x_rescaled = x * (1 - weights) + + return x_rescaled + + +class RandomizedLasso(Lasso): + """ + Randomized version of scikit-learns Lasso class. + + Randomized LASSO is a generalization of the LASSO. The LASSO penalises + the absolute value of the coefficients with a penalty term proportional + to `alpha`, but the randomized LASSO changes the penalty to a randomly + chosen value in the range `[alpha, alpha/weakness]`. + + Parameters + ---------- + weakness : float + Weakness value for randomized LASSO. Must be in (0, 1]. + + See also + -------- + sklearn.linear_model.LogisticRegression : learns logistic regression models + using the same algorithm. + """ + def __init__(self, weakness=0.5, alpha=1.0, fit_intercept=True, + precompute=False, copy_X=True, max_iter=1000, + tol=1e-4, warm_start=False, positive=False, + random_state=None, selection='cyclic'): + self.weakness = weakness + super(RandomizedLasso, self).__init__( + alpha=alpha, fit_intercept=fit_intercept, precompute=precompute, copy_X=copy_X, + max_iter=max_iter, tol=tol, warm_start=warm_start, + positive=positive, random_state=random_state, + selection=selection) + + def fit(self, X, y): + """Fit the model according to the given training data. + + Parameters + ---------- + X : {array-like, sparse matrix}, shape = [n_samples, n_features] + The training input samples. + + y : array-like, shape = [n_samples] + The target values. + """ + if not isinstance(self.weakness, float) or not (0.0 < self.weakness <= 1.0): + raise ValueError('weakness should be a float in (0, 1], got %s' % self.weakness) + + X, y = check_X_y(X, y, accept_sparse=True) + + n_features = X.shape[1] + weakness = 1. - self.weakness + random_state = check_random_state(self.random_state) + + weights = weakness * random_state.randint(0, 1 + 1, size=(n_features,)) + + # TODO: I am afraid this will do double normalization if set to true + #X, y, _, _ = _preprocess_data(X, y, self.fit_intercept, normalize=self.normalize, copy=False, + # sample_weight=None, return_mean=False) + + # TODO: Check if this is a problem if it happens before standardization + X_rescaled = _rescale_data(X, weights) + return super(RandomizedLasso, self).fit(X_rescaled, y) diff --git a/kozlov_alexey_lab_2/lab2.py b/kozlov_alexey_lab_2/lab2.py new file mode 100644 index 0000000..a65bf0b --- /dev/null +++ b/kozlov_alexey_lab_2/lab2.py @@ -0,0 +1,62 @@ +from sklearn.ensemble import RandomForestRegressor +from RandomizedLasso import RandomizedLasso +from sklearn.feature_selection import f_regression +from sklearn.preprocessing import MinMaxScaler +import numpy as np + +names = ["x%s" % i for i in range(1, 15)] +def main(): + x,y = generation_data() + # Сокращение признаков cлучайными деревьями (Random Forest Regressor) + rfr = RandomForestRegressor() + rfr.fit(x, y) + # Модель линейной корреляции + f, _ = f_regression(x, y, center=False) + # Случайное Лассо + randomized_lasso = RandomizedLasso(alpha=.01) + randomized_lasso.fit(x, y) + + ranks = {"Random Forest Regressor": rank_to_dict(rfr.feature_importances_), 'f-Regression': rank_to_dict(f), "Randomize Lasso": rank_to_dict(randomized_lasso.coef_)} + + get_estimation(ranks) + print_sorted_data(ranks) +def generation_data(): + 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)) + return X, Y +def rank_to_dict(ranks): + 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)) +def get_estimation(ranks: {}): + mean = {} + for key, value in ranks.items(): + for item in value.items(): + 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 = sorted(mean.items(), key=lambda item: item[1], reverse=True) + print("Средние значения") + print(mean_sorted) + print("4 самых важных признака по среднему значению") + for item in mean_sorted[:4]: + print('{0} - {1}'.format(item[0], item[1])) +def print_sorted_data(ranks: {}): + print() + for key, value in ranks.items(): + ranks[key] = sorted(value.items(), key=lambda item: item[1], reverse=True) + for key, value in ranks.items(): + print(key) + print(value) + + +main() \ No newline at end of file diff --git a/kozlov_alexey_lab_2/results.png b/kozlov_alexey_lab_2/results.png new file mode 100644 index 0000000..b901349 Binary files /dev/null and b/kozlov_alexey_lab_2/results.png differ