Это третья неделя моей серии « 52 недели науки о данных» .

Что такое исследовательский анализ данных?

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

«Понимание набора данных» может относиться к ряду вещей, включая, помимо прочего…

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

Вот почему это важно.

Вы слышали фразу «мусор на входе, мусор на выходе»?

С EDA это больше похоже на «мусор на входе, выполнение EDA, возможно мусор на выходе».

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

Исследовательский анализ данных выполняет две основные задачи:

1. Это помогает очистить набор данных.

2. Это дает вам лучшее понимание переменных и взаимосвязей между ними.

Компоненты EDA

Для меня есть основные компоненты исследования данных:

  1. Понимание ваших переменных
  2. Очистка набора данных
  3. Анализ отношений между переменными

В этой статье мы рассмотрим первые два компонента.

1. Понимание ваших переменных

Вы не знаете того, чего не знаете. А если вы не знаете того, чего не знаете, то как вы должны знать, имеют ли ваши идеи смысл или нет? Вы не сделаете этого.

Чтобы привести пример, я изучал данные, предоставленные NFL (данные здесь), чтобы увидеть, могу ли я найти какие-либо идеи относительно переменных, которые увеличивают вероятность травмы. Я понял, что полузащитники получают в восемь раз больше травм, чем тайт-энды. Однако я понятия не имел, в чем разница между полузащитником и тайт-эндом, и из-за этого не знал, имели ли мои идеи смысл или нет. Конечно, я могу погуглить, в чем разница между ними, но я не всегда могу положиться на Google! Теперь вы можете понять, почему так важно понимать ваши данные. Посмотрим, как это сделать на практике.

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

#Import Libraries
import numpy as np
import pandas as pd
import matplotlib.pylab as plt
import seaborn as sns
#Understanding my variables
df.shape
df.head()
df.columns

.shape возвращает количество строк по количеству столбцов для моего набора данных. Мой результат был (525839, 22), что означает, что в наборе данных 525839 строк и 22 столбца.

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

.columns возвращает имя всех ваших столбцов в наборе данных.

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

df.nunique(axis=0)
df.describe().apply(lambda s: s.apply(lambda x: format(x, 'f')))

.nunique (axis = 0) возвращает количество уникальных значений для каждой переменной.

.describe () суммирует количество, среднее значение, стандартное отклонение, минимальное и максимальное значения для числовых переменных. Код, который следует за этим, просто форматирует каждую строку в обычный формат и подавляет научную нотацию (см. Здесь).

Сразу заметил проблему с ценой, годом и одометром. Например, минимальная и максимальная цена равны 0,00 и 3 048 344 231,00 долларов США соответственно. В следующем разделе вы увидите, как я с этим справился. Я все еще хотел лучше понять свои дискретные переменные.

df.condition.unique()

Используя .unique (), я взглянул на свои дискретные переменные, включая «условие».

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

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

# Reclassify condition column
def clean_condition(row):
    
    good = ['good','fair']
    excellent = ['excellent','like new']       
    
    if row.condition in good:
        return 'good'   
    if row.condition in excellent:
        return 'excellent'    
    return row.condition
# Clean dataframe
def clean_df(playlist):
    df_cleaned = df.copy()
    df_cleaned['condition'] = df_cleaned.apply(lambda row: clean_condition(row), axis=1)
    return df_cleaned
# Get df with reclassfied 'condition' column
df_cleaned = clean_df(df)
print(df_cleaned.condition.unique())

И вы можете видеть, что значения были переклассифицированы ниже.

2. Очистка набора данных

Теперь вы знаете, как при необходимости переклассифицировать дискретные данные, но есть ряд вещей, на которые еще нужно обратить внимание.

а. Удаление избыточных переменных

Сначала я избавился от переменных, которые считал избыточными. Сюда входят url, image_url и city_url.

df_cleaned = df_cleaned.copy().drop(['url','image_url','city_url'], axis=1)

б. Выбор переменной

Затем я хотел избавиться от столбцов, в которых было слишком много нулевых значений. Благодаря моему другу Ричи я использовал следующий код для удаления всех столбцов, в которых 40% или более данных были нулевыми значениями. В зависимости от ситуации я могу увеличить или уменьшить порог. Остальные столбцы показаны ниже.

NA_val = df_cleaned.isna().sum()
def na_filter(na, threshold = .4): #only select variables that passees the threshold
    col_pass = []
    for i in na.keys():
        if na[i]/df_cleaned.shape[0]<threshold:
            col_pass.append(i)
    return col_pass
df_cleaned = df_cleaned[na_filter(NA_val)]
df_cleaned.columns

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

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

df_cleaned = df_cleaned[df_cleaned['price'].between(999.99, 99999.00)]
df_cleaned = df_cleaned[df_cleaned['year'] > 1990]
df_cleaned = df_cleaned[df_cleaned['odometer'] < 899999.00]
df_cleaned.describe().apply(lambda s: s.apply(lambda x: format(x, 'f')))

Вы можете видеть, что минимальные и максимальные значения изменились в результатах ниже.

d. Удаление строк с нулевыми значениями

Наконец, я использовал .dropna (axis = 0), чтобы удалить все строки с нулевыми значениями. После приведенного ниже кода я перешел с 371982 на 208765 строк.

df_cleaned = df_cleaned.dropna(axis=0)
df_cleaned.shape

На этом пока все! Во второй части мы рассмотрим взаимосвязь между переменными с помощью визуализаций. (Нажмите здесь, чтобы перейти к части 2.)

Вы можете увидеть мою записную книжку Kaggle здесь.