import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = (12,5)
# Для кириллицы на графиках
font = {'family': 'Verdana',
'weight': 'normal'}
plt.rc('font', **font)
Избавляться от размерности можно методами отбора признаков (Feature Selection) и методами уменьшения размерности (Feature Reduction)
Методы деляться на три группы:
Сколько информации $x$ сообщает об $y$. $$NormalizedMI(y,x) = \frac{MI(y,x)}{H(y)}$$
Загрузим довольно известный набор данных о выживаемости после катастрофы титаника.
df_titanic = pd.read_csv('titanic.csv')
df_titanic.head()
pd.crosstab(df_titanic.Survived, df_titanic.Sex)
Найдем MI между выживаемостью и остальными признаками
def calc_mutual_information(y, x):
## Your Code Here
При данном подходе из (линейной) модели последовательно удаляются признаки с наименьшим коэффициентом
Используйте реализацию RFE в sklean c кросс-валидацией.
from sklearn.linear_model import LogisticRegression
from sklearn.feature_selection import RFECV
from sklearn.model_selection import StratifiedKFold
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=123)
def titanic_preproc(df_input):
df = df_input.copy()
# Удаляем пропуски
df = df.dropna()
# Создаем такой признак
df.loc[:, 'has_cabin'] = df.loc[:, 'Cabin'].isnull().astype(int)
# Удаляем колонки
cols2drop = ['PassengerId', 'Name', 'Ticket', 'Cabin']
df = df.drop(cols2drop, axis=1)
# Нормализуем Age Fare и SibSp (Так делать не оч хорошо)
df.loc[:, 'Age'] = (df.loc[:, 'Age'] - df.loc[:, 'Age'].mean())/df.loc[:, 'Age'].std()
df.loc[:, 'Fare'] = (df.loc[:, 'Fare'] - df.loc[:, 'Fare'].mean())/df.loc[:, 'Fare'].std()
df.loc[:, 'SibSp'] = (df.loc[:, 'SibSp'] - df.loc[:, 'SibSp'].mean())/df.loc[:, 'SibSp'].std()
# Закодируем поле Sex
df.loc[:, 'Sex'] = df.loc[:, 'Sex'].replace({'male': 0, 'female':1})
# Pclass и Embarked можно рассматривать как категориальный признак
df = pd.get_dummies(df, prefix_sep='=', columns=['Pclass', 'Embarked'], drop_first=True)
return df
df_prep = df_titanic.pipe(titanic_preproc)
X, y = df_prep.iloc[:, 1:].values, df_prep.iloc[:, 0].values
model = LogisticRegression(random_state=123)
rfe = RFECV(model, step=1, cv=cv, scoring='roc_auc', verbose=1, n_jobs=-1)
rfe.fit(X, y)
## Your code here
## Your code here
Аналогичными выкладками приходим к тому, что $a_2$ - собственный вектор $\Sigma$ при $\lambda_2$
Для любой матрицы $X$ размера $n \times m$ можно найти разложение вида: $$ X = U S V^\top ,$$ где
Матрицы $U$ и $V$ ортогональны и могут быть использованы для перехода к ортогональному базису: $$ XV = US$$
Сокращение размерности заключается в том, что вместо того, чтобы умножать $X$ на всю матрицу $V$, а лишь на первые $k<m$ её столбцов - матрицу $V'$
Квадраты сингулярных чисел в $S$ содержат дисперсию, объясненную в главных компонентах
from sklearn.decomposition import PCA
from numpy.linalg import svd
from sklearn.datasets import load_digits
C = np.array([[0., -0.7], [1.5, 0.7]])
X = np.dot(np.random.randn(200, 2) + np.array([4, 2]), C)
plt.scatter(X[:, 0], X[:, 1])
plt.axis('equal')
pca = PCA(n_components=2)
PC = pca.fit_transform(X)
coef = pca.components_
coef
m = np.mean(X,axis=0)
fig, ax = plt.subplots(1,2)
ax[0].plot([0, coef[0,0]*2]+m[0], [0, coef[0,1]*2]+m[1],'--k')
ax[0].plot([0, coef[1,0]*2]+m[0], [0, coef[1,1]*2]+m[1],'--k')
ax[0].scatter(X[:,0], X[:,1])
ax[0].set_xlabel('$x_1$')
ax[0].set_ylabel('$x_2$')
ax[1].scatter(PC[:,0], PC[:,1])
ax[1].set_xlabel('$pc_1$')
ax[1].set_ylabel('$pc_2$')
ax[0].axis('equal')
ax[1].axis('equal')
## Your Code Here
digits = load_digits()
X = digits.images
y = digits.target
plt.imshow(X[2,:], cmap='Greys', interpolation='none')
y
X
на нужную матрицу и убедитесь, что у вас получается тот же результат### Your Code Here
diet.csv
df = pd.read_csv('diet.csv', sep=';')
df = df.dropna(axis=1)
df = df.drop('Energy (kcal/day)', axis=1)
df = df.set_index('Countries')
df.head()
X = df.values
X = (X - X.mean(axis=0))/X.std(axis=0)
## Your Code Here
## Your Code Here