Структурированный подход к изучению нового набора данных

Что такое ЭДА?

EDA, или исследовательский анализ данных, — это процесс изучения и понимания структуры набора данных. Это важная часть любого проекта по машинному обучению, и это инструмент в вашем наборе инструментов, который позволяет вам обращаться к данным, которые вы никогда раньше не видели, и освоиться со всеми видами характеристик.

Я обнаружил, что многие люди сразу же переходят к своим данным, не выполнив должным образом EDA. Особенно после того, как они сделали несколько проектов и думают, что знают, что делают. Для меня это важный первый шаг, который раскрывает так много скрытых жемчужин в данных, что это необходимо.

Для этого процесса я буду использовать набор банковских данных, доступный на Kaggle.

Мой подход к ЭДА

В этой статье описывается обобщенный процесс, который я использую для выполнения EDA. Это может варьироваться от набора данных к набору данных, в зависимости от типа данных, сложности и беспорядка. Однако эти шаги, как правило, одинаковы для всех наборов данных.

  1. Базовое исследование
  2. Проверка нулевых и повторяющихся значений
  3. Работа с выбросами
  4. Визуализируйте данные

Базовое исследование

Начните с импорта необходимых пакетов. Это мои настройки по умолчанию для всех новых исследований. Я склонен считать, что seaborn — это удобная оболочка поверх matplotlib, которая помогает быстрее создавать визуализации.

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

См. размер, столбцы и образцы строк

После того, как я импортирую данные, есть несколько функций из pandas, которые я запускаю в первую очередь. Давайте пройдемся по ним.

df.shape
(4521, 17)

Из вывода видно, что имеется 4,521 наблюдений с 17 столбцами.

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4521 entries, 0 to 4520
Data columns (total 17 columns):
 #   Column     Non-Null Count  Dtype 
---  ------     --------------  ----- 
 0   age        4521 non-null   int64 
 1   job        4521 non-null   object
 2   marital    4521 non-null   object
 3   education  4521 non-null   object
 4   default    4521 non-null   object
 5   balance    4521 non-null   int64 
 6   housing    4521 non-null   object
 7   loan       4521 non-null   object
 8   contact    4521 non-null   object
 9   day        4521 non-null   int64 
 10  month      4521 non-null   object
 11  duration   4521 non-null   int64 
 12  campaign   4521 non-null   int64 
 13  pdays      4521 non-null   int64 
 14  previous   4521 non-null   int64 
 15  poutcome   4521 non-null   object
 16  y          4521 non-null   object
dtypes: int64(7), object(10)
memory usage: 600.6+ KB

Способ, которым pandas импортирует данные, состоит в том, чтобы дать наилучшее предположение о типах данных. Вы можете изменить их позже, если они не импортировались должным образом. В моем случае выше похоже, что большинство типов данных — это integers и objects или строки.

Затем отобразите первую и последнюю несколько строк данных.

df.head()

и

df.tail()

См. статистическую сводку

Существует очень мощная команда, которая в одной функции df.describe() может дать вам представление о ваших данных с высоты птичьего полета. Он покажет количество, среднее значение, стандартное отклонение, минимум, максимум и многое другое. С этими данными вы можете получить довольно хорошее представление о том, с чем вы имеете дело; однако визуализация этого позже добавит к вашему анализу.

# Without any parameters passed into the describe function, it will return numerical only.
df.describe().round(2)
age   balance      day  duration  campaign    pdays  previous
count  4521.00   4521.00  4521.00   4521.00   4521.00  4521.00   4521.00
mean     41.17   1422.66    15.92    263.96      2.79    39.77      0.54
std      10.58   3009.64     8.25    259.86      3.11   100.12      1.69
min      19.00  -3313.00     1.00      4.00      1.00    -1.00      0.00
25%      33.00     69.00     9.00    104.00      1.00    -1.00      0.00
50%      39.00    444.00    16.00    185.00      2.00    -1.00      0.00
75%      49.00   1480.00    21.00    329.00      3.00    -1.00      0.00
max      87.00  71188.00    31.00   3025.00     50.00   871.00     25.00

Проверка категориальных значений

Следующая функция очень удобна при работе с категориальными данными. Сначала выбираются только столбцы типа object; в нашем случае все текстовые поля являются действительно категориальными. Затем он перебирает каждый из этих столбцов и печатает value_counts каждого.

# get categorical data
cat_data = df.select_dtypes(include=['object'])
# show counts values of each categorical variable
for colname in cat_data.columns:
    print (colname)
    print (cat_data[colname].value_counts(), '\n')

Вот как выглядит пример вывода для одного столбца. Обратите внимание, как здорово это обобщает категориальные данные.

marital
married     2797
single      1196
divorced     528
Name: marital, dtype: int64

Проверка нулевых и повторяющихся значений

И пустые значения, и повторяющиеся значения в конечном итоге становятся проблемой в моделях машинного обучения, поэтому давайте проверим их и разберемся с ними.

Нулевые значения

Во-первых, я начинаю с проверки нулевых значений. Потребуется некоторое исследование и интерпретация, чтобы понять, как с ними справляться. Это может варьироваться от простого удаления их, когда их очень мало, до заполнения их значением по умолчанию, например 0, или заполнения их на основе соседних значений. Заполнение их на основе соседних значений распространено в данных временных рядов, где вы можете заполнить отсутствующее значение средним предыдущего и последующего значений. Панды имеют обширную поддержку с их функцией fillna(), о которой вы можете прочитать здесь.

В этом примере я изучу, есть ли они, и уберу их из набора данных.

# check for nan/null
df.isnull().values.any()
# count of nulls per column
df.isnull().sum()

и бросить их

# Drop NULL values
df.dropna(inplace=True)

Повторяющиеся значения

Далее стоит искать дубликаты. Дубликаты аналогичны нулевым значениям, поскольку их необходимо интерпретировать как фактические чистые, полезные данные или ошибочные данные. Дубликаты также могут быть проблемой в машинном обучении, потому что они могут привести к чрезмерному смещению вашей модели к наблюдениям, которые не являются частью реального набора данных. Вы можете использовать приведенный ниже код либо для проверки дубликатов, либо для их удаления, как это реализовано здесь:

len_before = df.shape[0]
df.drop_duplicates(inplace=True)
len_after = df.shape[0]

print(f"Before = {len_before}")
print(f"After = {len_after}")
print("")
print(f"Total Removed = {len_before - len_after}")
Before = 4521
After = 4521

Total Removed = 0

В этом случае не было повторяющихся строк или нулевых значений, но очень важно проверить и обработать их соответствующим образом для вашего варианта использования.

Работа с выбросами

Выбросы — еще одна чрезвычайно распространенная проблема с данными. Выбросы необходимо оценивать, являются ли они хорошими наблюдениями в наборе данных или являются ошибками. Во-первых, вы можете проверить, сколько их. Для нормально распределенных данных наиболее распространенным методом является поиск любых наблюдений, которые лежат за пределами +/- 3 стандартных отклонения. Если вы помните свой урок статистики, правило 68–95–99,7. Это правило гласит, что 99,7% всех данных в нормальном распределении лежат в пределах трех стандартных отклонений от среднего. Когда ваши данные сильно смещены влево или вправо, это не будет правдой. Вы можете использовать диаграммы или гистограммы для проверки нормальности. Я расскажу об этом ниже.

def get_outliers(df):
    '''Identify the number of outliers +/- 3 standard deviations. 
    Pass this function a data frame and it returns a dictionary'''

    outs = {}

    df = df.select_dtypes(include=['int64'])


    for col in df.columns:

        # calculate summary statistics
        data_mean, data_std = np.mean(df[col]), np.std(df[col])

        # identify outliers
        cut_off = data_std * 3
        lower, upper = data_mean - cut_off, data_mean + cut_off

        # identify outliers
        outliers = [x for x in df[col] if x < lower or x > upper]

        outs[col] = len(outliers)

    return outs

Затем передайте dataframe в функцию, чтобы вернуть количество выбросов.

get_outliers(df)
{'age': 44,
 'balance': 88,
 'day': 0,
 'duration': 88,
 'campaign': 87,
 'pdays': 171,
 'previous': 99}

Удаление выбросов

Если вы решите удалить выбросы из набора данных, вот простой способ сделать это. Из scipy.stats вы можете использовать функцию zscore для легкого выявления выбросов, аналогично описанному выше методу:

from scipy import stats

# build a list of columns that you wish to remove ouliers from
out_list = ['balance', 'pdays', 'duration']

# overwrite the dataframe with outlier rows removed.
df = df[((np.abs(stats.zscore(df[out_list])) < 3)).all(axis=1)]

Визуализируйте данные

Мне нравится разбивать свои визуализации на две разные части. Явно сначала использовать только одномерные графики или графики, такие как гистограммы и диаграммы для отдельных переменных. Затем я предпочитаю накладывать двумерные (или многомерные) графики по разным переменным. Этот процесс помогает мне разбить анализ на уровни понимания данных.

Одномерные графики

Одномерный график — это именно то, что и звучит — график против одной переменной. Давайте начнем с просмотра диаграмм всех числовых переменных в наборе данных. Давайте начнем с двух самых распространенных: коробчатой ​​диаграммы и гистограммы.

Коробчатые участки

Блочная диаграмма принимает одну переменную и отображает информацию о том, как данные распределяются по ее квартилям, что по существу означает разделение данных на четверти. Этот простой графический пакет содержит много информации и может быть удобным инструментом для сравнения двух или более различных категориальных подсегментов. В приведенном ниже примере показана переменная duration на блочной диаграмме, а затем она разделена по переменной y' variable, in this case the y', являющейся целью в модели классификации (да/нет).

plt.figure(figsize=(7,6))
sns.boxplot(x="y", y="duration", data=df, showfliers=True)

Используя этот график, мы видим, что как медиана (линия в центре поля), так и межквартильный размах (IQR) или верхняя и нижняя части поля в целом больше для yes, чем no. ценности.

Фантастическая статья о науке о данных о том, как интерпретировать ящичные диаграммы: Понимание ящичных диаграмм.

Гистограммы

Гистограммы показывают распределение одной переменной в «ячейках» или группах данных в зависимости от частоты появления значения. Тем, кто не знаком с ними, может быть трудно сначала прочитать их, потому что их можно перепутать с гистограммами. Однако гистограмма, отображающая две переменные по оси X и оси Y, в то время как ось X в гистограмме представляет собой интервал а ось Y – это число в этой ячейке.

sns.histplot(x='age', data=df, bins=20, kde=True)

Если вы посмотрите на гистограмму переменной age, то увидите, что число людей в возрасте от 30 до 40 лет в наборе данных имеет наибольшую частоту. Поскольку гистограмма не центрирована, мы называем это асимметрией. В этом случае перекос называется Перекос вправо, поскольку правый конец длиннее.

Двумерные графики

Корреляционная матрица

Абсолютно обязательным двумерным (или многомерным) графиком, который вам нужно запустить, является корреляционная матрица. Это матрица, которая показывает корреляцию между всеми переменными в наборе данных. Это поможет вам определить, какие переменные сильно коррелированы, для таких случаев, как простая линейная регрессия или те, которые не коррелированы, для случаев, когда вы пытаетесь моделировать несколько функций, повышающих производительность вашей модели.

corr = df.corr()
f, ax = plt.subplots(figsize=(12, 8))
sns.heatmap(corr, annot=True, square=False, ax=ax, linewidth = 1)
plt.title('Pearson Correlation of Features')

По большей части нет сильно коррелированных переменных, кроме pdays и previous, между которыми значение положительной корреляции 0.62. Было бы полезно понять, почему это так и связаны ли они с аналогичными действиями.

Парные участки

Далее идет фантастический инструмент под названием Pair Plots. Аналогичен корреляционной матрице, но дает вам диаграмму рассеяния для каждой из пар X и Y. По диагонали находится KDE или гистограмма переменной.

g.fig.set_size_inches(12,12)
g=sns.pairplot(df, diag_kind = 'auto', hue="y")

С помощью всего одной строки кода вы можете быстро визуально оценить отношения, показанные в матрице корреляции. Теперь мы видим визуально, что корреляция между переменными pdays и previous невелика.

Дополнительные участки

Отсюда вы можете создать любое количество визуальных элементов, которые помогут вам лучше понять данные. Вам решать, какая история кроется в данных. У меня есть много других примеров в Notebook на Github.

Заключение

EDA — это мощная техника, с которой вы должны освоиться каждый раз, когда начинаете работать с новым набором данных. Существует множество других техник, которые вы можете добавить к этим основам. Отправляйтесь туда, изучите и узнайте свои данные, прежде чем приступить к машинному обучению.

Если вам нравится читать такие истории и вы хотите поддержать меня как писателя, подумайте о том, чтобы зарегистрироваться и стать участником Medium. Это 5 долларов в месяц, что дает вам неограниченный доступ к тысячам статей. Если вы зарегистрируетесь по моей ссылке, я получу небольшую комиссию без каких-либо дополнительных затрат для вас.

Рекомендации

  1. Как удалить выбросы для машинного обучения
  2. Понимание боксплотов