Подготовка данных для алгоритмов машинного обучения
Описание стека и некоторые вводные
Далее будем рассматривать данные из Kaggle: "Mental Health in Tech Survey".
Первый взгляд на датасет и понимание его специфики
import pandas as pd import numpy as np df = pd.read_csv("survey.csv") df.head()
Это даст нам первое представление о том, что есть наши данные. Далее посмотрим на размеры наших табличных данных. Выполнив построчно код ниже
df.shape # мы увидим информацию о размерности нашего датафрейма df.info() # покажет информацию о размерности данных # описание индекса, количество not-a-number элементов df.describe() # показывает статистики count,mean, std, min, 25%-50%-75% percentile, max df.nunique() # количество уникальных значений для каждого столбца
Также было бы неплохо увидеть информацию о количестве каждого уникального значения для каждого столбца в наборе данных:
feature_names = df.columns.tolist() for column in feature_names: print column print df[column].value_counts(dropna=False)
Большинство столбцов выглядят хорошо, но есть несколько нуждающихся в очистке. Примеры некорректных значений данных ниже.
- Столбец «age» содержит людей, которые еще не родились (отрицательные числа).
- Столбец «age» содержит детей (например, 5-летнего возраста), которые вряд ли будут проводить опрос о своем рабочем месте.
- Столбец «age» содержит возраст в 99999999999 лет
- Существует 49 различных значений для «gender». Для примера, «Male» и «male» обозначают одно и то же, но в рассматриваются как две разные категории.
- self_employed и work_interfere содержат несколько пропущенных полей.
Разделение на обучающую выборку и целевую переменную
features = df.drop('treatment', 1) labels = df['treatment']
Обработка пропусков в данных
Один из способов простых способов решения этой проблемы - просто игнорировать или удалять строки, в которых отсутствуют данные, выбрасывая их из нашего анализа. Однако этот метод может быть плох из-за потери информации.
Еще один способ — это заполнение пропусков, где мы заменяем отсутствующее значение каким-либо образом. Базовые реализации просто заменят все отсутствующие значения средним, медианным, либо же константой.
Для начала выясним, что делать с пропущенными значениями, найденными в self_employed и work_interfere. В обоих случаях столбец содержит категориальные данные.
Возьмем следующий пример, который представляет собой небольшой набор данных, содержащий три признака (погодное условие, температуру и влажность), чтобы предсказать, могу ли я играть в теннис или нет.
id | weather | temperature | humidity | play tennis? |
---|---|---|---|---|
1 | cloudy | 60 | NaN | yes |
2 | rainy | 75 | 80% | NaN |
3 | cloudy | NaN | 50% | no |
4 | sunny | 65 | 40% | yes |
Scikit-learn предоставляет реализацию для обработки пропусков
from sklearn.preprocessing import Imputer imputer = Imputer(missing_values = 'NaN', strategy = 'mean', axis = 0) imputer.fit(features) features = imputer.transform(features)
Поиск неявных дубликатов
Если бы требовалось создать механизм предварительной обработки, который мог бы очищать входящие данные, требовалось бы воспользоваться более умным подходом. Но так как наша задача — это работа с уже имеющемся датасетом, то мы просто используем этот подход с заменой определенных типов.
male_terms = ["male", "m", "mal", "msle", "malr", "mail", "make", "cis male", "man", "maile", "male (cis)", "cis man"] female_terms = ["female", "f", "woman", "femake", "femaile", "femake", "cis female", "cis-female/femme", "female (cis)", "femail", "cis woman"] def clean_gender(response): if response.lower().rstrip() in male_terms: return "Male" elif response.lower().rstrip() in female_terms: return "Female" else: return "Other" df['Gender'] = df["Gender"].apply(lambda x: clean_gender(x))
Обнаружение выбросов
Для этого возьмем нашу эвристическую оценку, в каком возрасте могут работать люди: от 14 до 100 лет. И все величины, не попадающие в этот диапазон, преобразуем в формат Not-a-Number.
df.Age.loc [(df.Age <14) | (df.Age> 100)] = np.nan
Эти нулевые значения затем могут быть обработаны с использованием описанного выше sklearn Imputer.
После определения диапазона для работающего человека, визуализируем распределение возраста, присутствующего в этом наборе данных.
%matplotlib inline import seaborn as sns sns.set(color_codes=True) plot = sns.distplot(df.Age.dropna()) plot.figure.set_size_inches(6,6)
Кодирование данных
Одним из решений этого было бы произвольное присвоение числового значения для каждой категории и отображение набора данных из исходных категорий в каждое соответствующее число. Например, давайте посмотрим на столбец «leave» (как легко вам взять отпуск по болезни для состояния психического здоровья?) В нашем наборе данных
df['leave'].value_counts(dropna=False)
Который возвращает следующие значения
Don't know 563 Somewhat easy 266 Very easy 206 Somewhat difficult 126 Very difficult 98 Name: leave, dtype: int64
Для кодирования этих данных, сопоставим каждое значение с числом.
df['leave'] = df['leave'].map({'Very difficult': 0, 'Somewhat difficult': 1, 'Don\'t know': 2, 'Somewhat easy': 3, 'Very easy': 4})
Этот процесс известен как Label Encoding и sklearn может сделать это за нас.
from sklearn import preprocessing label_encoder = preprocessing.LabelEncoder() label_encoder.fit(df['leave']) label_encoder.transform(df['leave'])
Проблема с этим подходом заключается в том, что вы вводите порядок, который может отсутствовать в исходных данных. В нашем случае можно утверждать, что данные являются ранжированными («Very difficult» меньше «Somewhat difficult», который меньше «Very easy», который меньше «Somewhat easy»), но в большинстве своем категориальные данные не имеют порядка. Например, если у вас есть признак обозначающий вид животного, зачастую высказывание кошка больше собаки не имеет смысла. Опасность кодирования меток заключается в том, что ваш алгоритм может научиться отдавать предпочтение собак, кошкам из-за искусственных порядковых значений, введенных вами во время кодирования.
Общим решением для кодирования номинальных данных является one-hot-encoding.
Вместо того, чтобы заменять категориальное значение на числовое значение (кодирование меток), как показано ниже
id | type | numerical |
---|---|---|
1 | cat | 1 |
2 | dog | 2 |
3 | snake | 3 |
4 | cat | 1 |
5 | dog | 2 |
6 | turtle | 4 |
7 | dog | 2 |
Вместо этого мы создаем столбец для каждого значения и используем 1 и 0 для обозначения выражения каждого значения. Эти новые столбцы часто называются фиктивными переменными.
id | type | is_cat | is_dog | is_snake | is_turtle |
---|---|---|---|---|---|
1 | cat | 1 | 0 | 0 | 0 |
2 | dog | 0 | 1 | 0 | 0 |
3 | snake | 0 | 0 | 1 | 0 |
4 | cat | 1 | 0 | 0 | 0 |
5 | dog | 0 | 1 | 0 | 0 |
6 | turle | 0 | 0 | 0 | 1 |
7 | dog | 0 | 1 | 0 | 0 |
Вы можете выполнить one-hot-encoding непосредственно в Pandas или использовать sklearn, хотя sklearn немного более прозрачен, поскольку one-hot-encoding из него работает только для целых значений. В нашем примере (где входные данные представляют собой строки) нам нужно сначала выполнить кодировку меток, а затем one-hot-encoding.
# Using Pandas import pandas as pd pd.get_dummies(features['leave']) # Using sklearn from sklearn.preprocessing import LabelEncoder, OneHotEncoder label_encoder = LabelEncoder() ohe = OneHotEncoder(categorical_features = ['leave']) label_encoded_data = label_encoder.fit_transform(features['leave']) ohe.fit_transform(label_encoded_data.reshape(-1,1))
Нормализация тренировочных данных
ML алгоритмы, которые требуют нормализации данных:
- Логистическая регрессия
- Метод опорных векторов
- Нейронная сеть
- PCA
ML алгоритмы, которые не требуют нормализации данных:
- Деревья принятия решений (и случайные леса)
- Градиентный бустинг
- Наивный Байес
Предположим, у вас есть набор данных с различными единицами: температура в Кельвине, относительная влажность и день года. Мы можем увидеть следующие диапазоны для каждой функции.
- Температура: от 270 K до 305 K
- Влажность: от 0 до 1 (т. е. Влажность 30%, равная 0,3)
- День года: от 0 до 365
Алгоритм нормализации
Если вы используете такой инструмент, как градиентный спуск, для оптимизации алгоритма, нормализация данных позволяет проводить последовательное обновление весов во всех измерениях.
Первое изображение представляет две функции с разными шкалами, в то время как последняя представляет собой нормализованное пространство признаков. Оптимизация градиентным спуском в первом случае может занять большее количество времени и в конечном итоге не прийти к минимуму.
Существует несколько различных методов нормализации данных, самые популярные из них:
Нормализация Min-max устанавливает наименьшее наблюдаемое значение равным 0, а наибольшее наблюдаемое значение — 1.
Нормализация на стандартное отклонение.
Для выполнения нормализации мы можем использовать функции в sklearn.
# Feature scaling with StandardScaler from sklearn.preprocessing import StandardScaler scale_features_std = StandardScaler() features_train = scale_features_std.fit_transform(features_train) features_test = scale_features_std.transform(features_test) # Feature scaling with MinMaxScaler from sklearn.preprocessing import MinMaxScaler scale_features_mm = MinMaxScaler() features_train = scale_features_mm.fit_transform(features_train) features_test = scale_features_mm.transform(features_test)
Несколько замечаний по этой реализации:
На практике вы можете выбрать только определенные столбцы. Например, вам не нужно нормализовать фиктивные переменные из one-hot-encoding.
Разделение данных для обучения и тестирования
Разделение данных на две подвыборки
from sklearn.model_selection import train_test_split features_train, features_test, labels_train, labels_test = train_test_split(features, labels, test_size=0.2, random_state = 0)
Комментарии
Отправить комментарий