Привет, Хабр!
Сегодня рассмотрим одну из важных тем для джунов, которые развиваются в области машинного обучения, а именно – вопросы на собеседовани. В этой статье поделимся тремя основными вопросами, которые частенько попадаются на собеседованиях.
И первый вопрос касается перекрестной проверки.
Что такое перекрестная проверка?
Перекрестная проверка — это метод оценки модели, при котором данные делятся на несколько наборов, и модель обучается и тестируется на различных комбинациях этих наборов. Основная идея здесь — получить более точную и надежную оценку производительности модели.
Основные техники перекрестной проверки
K-Fold Cross-Validation
Самый популярный метод. Заключается в следующем:
Разделение данных на k частей: данные делятся на k равных подмножеств или "фолдов".
Обучение и тестирование: модель обучается на
фолдах и тестируется на оставшемся фолде. Этот процесс повторяется
раз, каждый раз с новым фолдом для тестирования.
Среднее значение результатов: все
результатов тестирования усредняются, чтобы получить окончательную оценку производительности модели.
Например, если есть 1000 наблюдений и мы используем 5-fold cross-validation, то данные будут разделены на 5 частей по 200 наблюдений. Модель обучается на 800 наблюдениях и тестируется на 200. Этот процесс повторяется 5 раз, каждый раз с новым набором для тестирования.
Time-Series Cross-Validation
Особый случай перекрестной проверки используется для временных рядов — time-series cross-validation. Поскольку данные временных рядов имеют временную зависимость, традиционные методы перекрестной проверки не подходят. В данном методе данные делятся так, чтобы каждый набор данных для тестирования содержал более поздние временные точки по сравнению с обучающими наборами.
Пример:
Разделение данных по времени: Данные делятся на обучающие и тестовые наборы таким образом, что тестовые наборы всегда следуют за обучающими по времени.
Обучение и тестирование: Модель обучается на более ранних данных и тестируется на более поздних. Этот процесс повторяется несколько раз, каждый раз с новым интервалом данных.
Перекрестная проверка помогает избежать ситуации, когда модель слишком хорошо обучается на тренировочных данных и плохо работает на новых данных.
Переходим к следующему вопросу.
Как бы вы обработали набор данных с пропущенными значениями?
Если пропущенные значения встречаются в небольшом количестве строк, самый простой способ — удалить эти строки. В Python это можно сделать с помощью функции dropna()
из pandas:
df = df.dropna()
Подход подходит, если пропуски случайны и их немного. Однако, если пропущенные данные не случайны, можно потерять важную информацию.
Если в каком-то столбце много пропущенных значений, возможно, имеет смысл удалить весь столбец:
df = df.dropna(axis=1)
Этот метод применим, если столбец не содержит важной информации и его удаление не повлияет на анализ данных.
Для числовых данных часто используют замещение средним или медианой значением:
df['column_name'] = df['column_name'].fillna(df['column_name'].mean())
df['column_name'] = df['column_name'].fillna(df['column_name'].median())
Среднее значение подходит для нормального распределения данных, а медиана — для данных с выбросами.
Для категориальных данных можно использовать замещение наиболее частым значением:
df['column_name'] = df['column_name'].fillna(df['column_name'].mode()[0])
Можно использовать регрессионные модели для предсказания пропущенных значений на основе других признаков:
from sklearn.linear_model import LinearRegression
# создаем копию данных без пропусков
complete_data = df.dropna()
missing_data = df[df['column_name'].isnull()]
# обучаем модель
model = LinearRegression()
model.fit(complete_data[['feature1', 'feature2']], complete_data['column_name'])
# прогнозируем пропущенные значения
df.loc[df['column_name'].isnull(), 'column_name'] = model.predict(missing_data[['feature1', 'feature2']])
Так можно учитывать зависимость между признаками, что в целом улучшает точность замещения.
В случайной иммутации пропущенные значения заменяются случайным образом выбранными значениями из имеющихся данных:
import numpy as np
def random_imputation(df, feature):
missing = df[feature].isnull()
num_missing = missing.sum()
sampled = np.random.choice(df[feature].dropna(), num_missing)
df.loc[missing, feature] = sampled
return df
df = random_imputation(df, 'column_name')
Так можно сохранить распределение данных, но может ввести шум.
Множественная иммутация выполняет несколько итераций замещения пропущенных значений и усредняет результаты:
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
imp = IterativeImputer(max_iter=10, random_state=0)
df_imputed = imp.fit_transform(df)
Метод лучше сохраняет вариативность данных.
Можете ли вы объяснить принцип работы метода главных компонент (PCA)?
PCA помогет упростить анализ данных, уменьшить их размерность и при этом сохранить как можно больше информации.
Первый шаг в PCA — стандартизация данных. Это нужно, чтобы каждая переменная в данных вносила равный вклад в анализ. Для стандартизации вычитается среднее значение и оно делится на стандартное отклонение каждой переменной:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaled_data = scaler.fit_transform(data)
Стандартизация нужна, потому что PCA чувствителен к масштабу переменных. Если переменные имеют разные масштабы, те, которые имеют больший масштаб, будут доминировать в анализе.
После стандартизации вычисляется ковариационная матрица, чтобы понять, как переменные связаны друг с другом:
import numpy as np
cov_matrix = np.cov(scaled_data, rowvar=False)
Ковариационная матрица показывает, как изменения одной переменной связаны с изменениями других переменных.
Следующий шаг — вычисление собственных векторов и собственных значений ковариационной матрицы. Собственные векторы указывают направления, в которых данные имеют наибольшую дисперсию, а собственные значения показывают, сколько дисперсии в данных объясняется каждой главной компонентой:
eig_values, eig_vectors = np.linalg.eig(cov_matrix)
Собственные векторы определяют оси новых координат, в которых дисперсия данных максимальна.
Собственные векторы сортируются в порядке убывания их собственных значений. Так можно определить, какие главные компоненты содержат наибольшую часть информации:
sorted_index = np.argsort(eig_values)[::-1]
sorted_eig_values = eig_values[sorted_index]
sorted_eig_vectors = eig_vectors[:, sorted_index]
Первые несколько главных компонент будут содержать большую часть вариации в данных.
На последнем этапе данные преобразуются в новое пространство, заданное главными компонентами:
n_components = 2 # выбор количества главных компонент
pca_components = sorted_eig_vectors[:, :n_components]
transformed_data = np.dot(scaled_data, pca_components)
Так мы сократили размерность данных, сохраняя при этом большую часть их информации.
Больше практических навыков по машинному обучению вы можете получить в рамках практических онлайн-курсов от экспертов отрасли.
Также приглашаем всех начинающих в этой области на открытый урок, посвященный подготовке данных в Pandas. На нем мы последовательно рассмотрим этапы обработки данных: обработка пропусков, обработка дубликатов и поиск аномалий.
Записаться на урок можно по ссылке.