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

Типы пропущенных значений

Есть три типа отсутствующих данных;

  1. MCAR (Missing Completet at Random): Это случай, когда вероятность отсутствия значений в переменной одинакова для всех выборок. Например, респонденты в процессе сбора данных решают, включать ли номер своего дома в опрос совершенно случайно. Здесь все пропущенные значения являются случайными. Это редкая ситуация.
  2. MAR (Missing at Random): это случай, когда переменная имеет пропущенные значения, которые распределены случайным образом, однако они связаны со значениями некоторых других переменных. Например, если мужчины более склонны скрывать свой уровень дохода, доход равен MAR. Отсутствие данных о доходах зависит от пола респондента.
  3. MNAR (Missing not at Random): Это случай, когда отсутствие данных связано с событиями или факторами, которые не измеряются исследователем. Например, люди с высоким уровнем дохода реже отвечают на вопрос об уровне дохода из-за страха перед более высокими налогами. Здесь отсутствие данных о доходах не случайно, оно связано с уровнем дохода, но уровень дохода нам неизвестен.

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

Данные временных рядов

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

Почему пропущенные значения являются особенными в данных временных рядов?

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

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

# Import necessary libraries
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import random
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from statsmodels.tsa.seasonal import STL
from sklearn.impute import KNNImputer
import seaborn as sns

sns.set_style("darkgrid")
# Set the random seed for reproducibility
np.random.seed(0)

# Define the start date
start_date = datetime(2022, 1, 1)

# Generate dates for 365 days
dates = [start_date + timedelta(days=i) for i in range(365)]

# Generate more pronounced trend component (increasing linearly)
trend = np.power(np.linspace(0.1, 20, 365), 2)

# Generate more pronounced seasonal component (sinusoidal pattern) with weekly period
seasonal = 50 * np.sin(np.linspace(0, 2 * np.pi * 52, 365)) # 52 weeks in a year

# Generate random noise
noise = np.random.normal(0, 5, 365)

# Combine components to generate sales data
sales = trend + seasonal + noise

# Create ad_spent feature
# Using a scaled version of sales and adding more noise
ad_spent = 0.2 * sales + np.random.normal(0, 30, 365)  # Increased the noise and decreased the scale factor
ad_spent = np.maximum(ad_spent, 0)  # Making sure all ad_spent values are non-negative

# Create a dataframe
df = pd.DataFrame(
    {
        'date': dates,
        'sales': sales,
        'ad_spent': ad_spent
    }
)

# Set the date as the index
df.set_index('date', inplace=True)

# Generate missing values for a larger gap
for i in range(150, 165):  # A 15-day gap
    df.iloc[i, df.columns.get_loc('sales')] = np.nan

# Randomly choose indices for missing values (not including the already missing gap)
random_indices = random.sample(list(set(range(365)) - set(range(150,165))), int(0.20 * 365))

# Add random missing values
for i in random_indices:
    df.iloc[i, df.columns.get_loc('sales')] = np.nan

# Display the dataframe
display(df.head())

# Print the percentage of missing values 
print('% missing data in sales: ', 100*df['sales'].isnull().sum()/len(df))

# Plot the data
df[['sales', 'ad_spent']].plot(style='.-', figsize=(10,6), title='Sales and Ad Spent Over Time')
plt.show()

# Print correlation between sales and ad_spent
print("Correlation between sales and ad_spent: ", df['sales'].corr(df['ad_spent']))

% missing data in sales:  24.10958904109589

Correlation between sales and ad_spent:  0.6556099955159692

Наш набор данных содержит ежедневные данные за один год с двумя переменными: продажи и расходы на рекламу. Приблизительно 25% данных о продажах содержат пропущенные значения, которые появляются случайным образом и в некоторых случаях представляют собой полные пробелы в данных. С другой стороны, функция ad_spent лишена каких-либо отсутствующих значений. Между затратами на рекламу и продажами существует заметная корреляция около 66%.

Подходы к обработке пропущенных значений

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

  • Удаление. Эта стратегия подразумевает удаление всех строк, содержащих пропущенные значения. Несмотря на простоту выполнения, если отсутствующие данные не отсутствуют полностью случайным образом (MCAR), этот подход может привести к потере ценной информации.
  • Константное вменение: этот метод заменяет все пропущенные значения константой, которая может быть обычным значением, например нулем, или необычным значением, которое эффективно устанавливает новую категорию для пропущенных значений. Хотя его просто применять, он может исказить распределение данных и, возможно, дать необъективные оценки. Если нет веских причин для выбора конкретной константы, этот метод обычно не рекомендуется.
  • Перенос последнего наблюдения вперед (LOCF) и Перенос следующего наблюдения назад (NOCB): эти методы заменяют отсутствующие значения либо непосредственно предшествующим наблюдаемым значением (LOCF), либо последующим наблюдаемым значением. (НОКБ). Они потенциально полезны для данных временных рядов, но могут привести к смещению, если данные не являются стационарными.
  • Вменение среднего/медианы/моды. В этом подходе отсутствующие значения заменяются средним (для непрерывных данных), медианой (для порядковых данных) или модой (для категориальных данных) доступных значений. Несмотря на простоту реализации, этот метод потенциально может недооценивать дисперсию.
  • Импутация скользящей статистики. Этот метод заменяет отсутствующие значения скользящей статистикой (например, средним значением, медианой или модой) за указанный период окна. Обычно используемый в данных временных рядов, он предполагает, что точки данных, ближайшие во времени, более похожи. Хотя этот метод может обрабатывать неслучайные пропуски и сохранять временную зависимость, выбор размера окна и статистики может существенно повлиять на результаты, что делает крайне важным тщательный выбор этих параметров. Этот метод может оказаться неэффективным для данных с большими пропусками пропущенных значений.
  • Линейная интерполяция: здесь отсутствующие значения заменяются на основе линейного уравнения, полученного из доступных значений. Этот метод подходит для данных временных рядов, но предполагает линейную связь между наблюдениями.
  • Сплайн-интерполяция. В этом методе отсутствующие значения заменяются на основе сплайн-интерполяции доступных значений. Сплайн-интерполяция использует кусочные полиномы для аппроксимации данных, фиксируя нелинейные закономерности. Этот метод подходит для данных временных рядов, но предполагает определенную гладкость данных.
  • Вменение K-ближайших соседей (KNN). Этот метод заменяет отсутствующие значения на основе значений «k» ближайших соседей. Хотя он может фиксировать сложные закономерности в данных, для больших наборов данных он может быть дорогостоящим в вычислительном отношении.
  • STL-декомпозиция для временных рядов: этот метод разбивает временные ряды на тренд, сезонность и остатки, а затем вводит отсутствующие значения в остатки перед повторной сборкой компонентов. Это может оказаться полезным для данных временных рядов с отчетливой тенденцией и сезонностью.

Удаление

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

Когда использовать:

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

Плюсы:

  • Легко реализовать.
  • Не вносит смещения в данные.

Минусы:

  • Может привести к потере информации, если набор данных недостаточно велик.
  • Может привести к необъективным результатам, если отсутствующие данные не являются MCAR.
  • Не подходит для больших объемов недостающих данных.

Влияние на процесс построения модели:

Удаление уменьшает размер набора данных, что может привести к потере информации и потенциально менее точным моделям. Если отсутствующие данные не относятся к MCAR, удаление также может внести систематическую ошибку в модели. Давайте реализуем удаление на наших синтетических данных.

# Create a copy of the dataframe
df_deletion = df.copy()

# Remove rows with missing values
df_deletion.dropna(inplace=True)

# Display the dataframe
display(df_deletion.head())
# plot the data

df_deletion[['sales']].plot(style='.-', figsize=(12, 8), title='Missing Values Deletion ')
plt.show()

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

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

Постоянное вменение

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

Когда использовать:

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

Плюсы:

  • Легко реализовать.
  • Сохраняет структуру и размер набора данных.
  • Может зафиксировать смысл или значимость пропущенных значений в определенных случаях.

Минусы:

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

Влияние на процесс построения модели:

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

# Apply the forward fill method
df_imputed = df.fillna(-1)

# Plot the main line with markers
df_imputed['sales'].plot(style='.-', figsize=(12,8), title='Sales with Constant Imputation')

# Add points where data was imputed with red color
plt.scatter(df_imputed[df['sales'].isnull()].index, df_imputed[df['sales'].isnull()]['sales'], color='red')

# Set labels
plt.xlabel('Time')
plt.ylabel('Sales')

plt.show()

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

Последнее наблюдение перенесено вперед (LOCF)

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

Когда мы должны его использовать?

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

Плюсы

  • Просто и легко реализовать.
  • Не требует подгонки модели.
  • Может быть разумным предположением в определенных наборах данных временных рядов.

Минусы

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

Влияние на процесс построения модели:

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

Давайте посмотрим демонстрацию с использованием кода.

# Apply the forward fill method
df_imputed = df.fillna(method="ffill")

# Plot the main line with markers
df_imputed['sales'].plot(style='.-', figsize=(12,8), title='Sales with LOCF Imputation')

# Add points where data was imputed with red color
plt.scatter(df_imputed[df['sales'].isnull()].index, df_imputed[df['sales'].isnull()]['sales'], color='red')

# Set labels
plt.xlabel('Time')
plt.ylabel('Sales')

plt.show()

Следующее наблюдение, перенесенное назад (NOCB)

Следующее наблюдение, перенесенное назад (NOCB) — еще один простой метод обработки отсутствующих данных. Этот метод противоположен LOCF. Вместо того, чтобы заполнить пропущенное значение последним наблюдением, оно заполняет его следующим наблюдением. Это как заглянуть в будущее и заполнить недостающее значение тем значением, которое должно произойти.

Когда мы должны его использовать?

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

Плюсы

  • Просто и легко реализовать.
  • Не дорого в вычислительном отношении.

Минусы

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

Давайте посмотрим, как NOCB работает с нашими синтетическими данными.

# Apply the backward fill method
df_imputed = df.fillna(method="bfill")

# Plot the main line with markers
df_imputed['sales'].plot(style='.-', figsize=(12,8), title='Sales with NOCB Imputation')

# Add points where data was imputed with red color
plt.scatter(df_imputed[df['sales'].isnull()].index, df_imputed[df['sales'].isnull()]['sales'], color='red')

# Set labels
plt.xlabel('Time')
plt.ylabel('Sales')

plt.show()

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

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

Вменение среднего/медианы/моды

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

Когда мы должны его использовать?

Вменение среднего/медианы/моды можно использовать, когда данные полностью случайным образом отсутствуют (MCAR). Если отсутствующие данные не случайны, этот метод может привести к необъективным и неэффективным оценкам.

Плюсы

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

Минусы

  • Это может привести к недооценке дисперсии.
  • Он не учитывает корреляции между признаками.
  • Это может привести к смещенным оценкам ковариаций и корреляций.

Влияние на процесс построения модели:

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

# Apply the mean imputation method
df_imputed = df.fillna(df['sales'].mean())

# Plot the main line with markers
df_imputed['sales'].plot(style='.-', figsize=(12,8), title='Sales with Mean Imputation')

# Add points where data was imputed with red color
imputed_indices = df[df['sales'].isnull()].index
plt.scatter(imputed_indices, df_imputed.loc[imputed_indices, 'sales'], color='red')

# Set labels
plt.xlabel('Time')
plt.ylabel('Sales')

plt.show()

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

Вменение скользящей статистики

Вменение скользящей статистики — это метод, который часто используется в данных временных рядов для обработки отсутствующих данных. Он использует временную структуру данных, заменяя отсутствующие значения скользящей статистикой (например, средним значением, медианой или модой) за определенный период окна. Чаще всего используется скользящее среднее (или скользящее среднее), которое берет среднее значение предыдущих «n» точек.

Когда мы должны его использовать?

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

Плюсы

  • Учитывает временную структуру данных, сохраняя временную зависимость.
  • Может обрабатывать неслучайные пропуски, что делает его более универсальным, чем вменение среднего/медианы/моды.
  • Относительно прост в реализации благодаря гибкому выбору скользящего окна и используемой статистики.

Минусы

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

Влияние на процесс построения модели:

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

# Make a copy of the original DataFrame
df_copy = df.copy()

# Mark the missing values before imputation
imputed_indices = df_copy[df_copy['sales'].isnull()].index


# Apply the rolling mean imputation method
df_copy['sales'] = df_copy['sales'].fillna(df_copy['sales'].rolling(window=4, min_periods=1).mean().shift(1))

# Plot the main line with markers
df_copy['sales'].plot(style='.-', figsize=(12,8), title='Sales with Rolling Mean Imputation')

# Add points where data was imputed with red color
plt.scatter(imputed_indices, df_copy.loc[imputed_indices, 'sales'], color='red')

# Set labels
plt.xlabel('Time')
plt.ylabel('Sales')

plt.show()

Как видите, из-за выбора размера окна этот метод совершенно не влияет на наличие зазоров. Хотя более широкий выбор размера окна может помочь, но это также приведет к искажению.

Линейная интерполяция

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

Когда мы должны его использовать?

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

Плюсы

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

Минусы

  • Это может дать плохие оценки, когда данные не показывают линейный тренд.
  • Он не подходит для данных с сезонным характером.

Влияние на процесс построения модели:

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

Давайте посмотрим демонстрацию кода линейной интерполяции.

# Apply the linear interpolation method
df_imputed = df.interpolate(method ='linear', limit_direction ='forward')

# Plot the main line with markers
df_imputed['sales'].plot(style='.-', figsize=(12,8), title='Sales with Linear Interpolation')

# Add points where data was imputed with red color
imputed_indices = df[df['sales'].isnull()].index
plt.scatter(imputed_indices, df_imputed.loc[imputed_indices, 'sales'], color='red')

# Set labels
plt.xlabel('Time')
plt.ylabel('Sales')

plt.show()

Сплайн-интерполяция

Сплайн-интерполяция — это форма интерполяции, в которой интерполянтом является особый тип кусочного полинома, называемый сплайном. Сплайн-интерполяция часто предпочтительнее полиномиальной интерполяции, потому что ошибку интерполяции можно сделать малой даже при использовании полиномов низкой степени для сплайна. Сплайн-интерполяция также не страдает проблемой феномена Рунге.

Когда мы должны его использовать?

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

Плюсы

  • Обеспечивает более плавную и гибкую подгонку, чем линейная интерполяция.
  • Не страдает от проблемы переобучения, которая может возникнуть при полиномиальной интерполяции.

Минусы

  • Более требовательны к вычислительным ресурсам, чем линейная интерполяция.
  • Может создавать нереалистичные оценки, если данные не являются гладкими.

Влияние на процесс построения модели:

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

Давайте посмотрим демонстрацию кода сплайн-интерполяции.

# Apply the spline interpolation method
df_imputed = df.interpolate(method='spline', limit_direction='forward', order=2)

# Plot the main line with markers
df_imputed['sales'].plot(style='.-', figsize=(12,8), title='Sales with Spline Interpolation')

# Add points where data was imputed with red color
imputed_indices = df[df['sales'].isnull()].index
plt.scatter(imputed_indices, df_imputed.loc[imputed_indices, 'sales'], color='red')

# Set labels
plt.xlabel('Time')
plt.ylabel('Sales')

plt.show()

Как ясно видно из графика, вменение отсутствующего пробела совершенно нереально!

Вменение регрессии

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

Когда мы должны его использовать?

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

Плюсы

  • Использует связь между переменными.
  • Может быть более точным, чем вменение среднего, медианы или режима.

Минусы

  • Может привести к переоценке корреляции между переменными.
  • Вмененные значения являются оценками, а не фактическими наблюдениями.

Влияние на процесс построения модели:

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

Давайте посмотрим демонстрацию кода импутации регрессии.

# Drop missing values to fit the regression model
df_imputed = df.copy()
df_non_missing = df.dropna()

# Instantiate the model
model = LinearRegression()

# Reshape data for model fitting (sklearn requires 2D array for predictors)
X = df_non_missing['ad_spent'].values.reshape(-1, 1)
Y = df_non_missing['sales'].values

# Fit the model
model.fit(X, Y)

# Get indices of missing sales
missing_sales_indices = df_imputed[df_imputed['sales'].isnull()].index

# Predict missing sales values
predicted_sales = model.predict(df_imputed.loc[missing_sales_indices, 'ad_spent'].values.reshape(-1, 1))

# Fill missing sales with predicted values
df_imputed.loc[missing_sales_indices, 'sales'] = predicted_sales

# Plot the main line with markers
df_imputed[['sales']].plot(style='.-', figsize=(12,8), title='Sales with Regression Imputation')

# Add points where data was imputed with red color
plt.scatter(missing_sales_indices, predicted_sales, color='red', label='Regression Imputation')

# Set labels
plt.xlabel('Time')
plt.ylabel('Sales')

plt.show()

K-ближайшие соседи (KNN) Импутация

K-ближайшие соседи (KNN) — это алгоритм машинного обучения, который используется для задач классификации и регрессии. Однако его также можно использовать для заполнения отсутствующих данных. Метод вменения KNN работает, находя K-ближайших соседей к наблюдению с отсутствующими данными, а затем вменяя их на основе неотсутствующих значений в соседях.

Когда мы должны его использовать?

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

Плюсы

  • KNN прост и удобен в реализации.
  • Он не делает никаких предположений о данных.
  • Он может быть намного точнее других методов, особенно если данные распределены равномерно.

Минусы

  • KNN может быть дорогостоящим в вычислительном отношении, особенно если набор данных большой со многими функциями.
  • Он чувствителен к масштабу данных и нерелевантным функциям.
  • Он плохо обрабатывает категориальные данные.

Влияние на процесс построения модели:

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

# Initialize the KNN imputer with k=5
imputer = KNNImputer(n_neighbors=3)

# Apply the KNN imputer
# Note: the KNNImputer requires 2D array-like input, hence the double brackets.
df_imputed = df.copy()
df_imputed[['sales', 'ad_spent']] = imputer.fit_transform(df_imputed[['sales', 'ad_spent']])

# Create a matplotlib plot
plt.figure(figsize=(12,8))
df_imputed['sales'].plot(style='.-', label='Sales')

# Add points where data was imputed
imputed_indices = df[df['sales'].isnull()].index
plt.scatter(imputed_indices, df_imputed.loc[imputed_indices, 'sales'], color='red', label='KNN Imputation')

# Set title and labels
plt.title('Sales with KNN Imputation')
plt.xlabel('Time')
plt.ylabel('Sales')
plt.legend()
plt.show()

Разложение сезонного тренда с использованием импутации лёсса (STL)

Разложение сезонного тренда с использованием лесса (STL) — это статистический метод разложения временного ряда на три компонента: тренд, сезонность и остаток (случайный). Его можно использовать для заполнения отсутствующих данных во временном ряду. В методе вменения STL отсутствующие значения первоначально оцениваются посредством интерполяции, чтобы учесть разложение STL. После этого из разложенного временного ряда извлекаются сезонные и трендовые компоненты. Затем отсутствующие значения повторно оцениваются путем интерполяции компонента тренда и повторного добавления сезонного компонента.

Когда мы должны его использовать?

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

Плюсы

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

Минусы

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

Влияние на процесс построения модели:

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

# Make a copy of the original dataframe
df_copy = df.copy()

# Fill missing values in the time series
imputed_indices = df[df['sales'].isnull()].index
# Apply STL decompostion
stl = STL(df_copy['sales'].interpolate(), seasonal=31)
res = stl.fit()

# Extract the seasonal and trend components
seasonal_component = res.seasonal

# Create the deseasonalised series
df_deseasonalised = df_copy['sales'] - seasonal_component

# Interpolate missing values in the deseasonalised series
df_deseasonalised_imputed = df_deseasonalised.interpolate(method="linear")

# Add the seasonal component back to create the final imputed series
df_imputed = df_deseasonalised_imputed + seasonal_component

# Update the original dataframe with the imputed values
df_copy.loc[imputed_indices, 'sales'] = df_imputed[imputed_indices]

# Plot the series using pandas
plt.figure(figsize=[12, 6])
df_copy['sales'].plot(style='.-',  label='Sales')
plt.scatter(imputed_indices, df_copy.loc[imputed_indices, 'sales'], color='red')

plt.title("Sales with STL Imputation")
plt.ylabel("Sales")
plt.xlabel("Time")
plt.show()

Обо мне

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

Здесь вы можете найти и поддержать мою работу:

  • Medium: я публикую свои статьи на Medium. Если вы найдете их полезными, не стесняйтесь хлопать в ладоши!
  • LinkedIn: свяжитесь со мной в LinkedIn, чтобы быть в курсе моей профессиональной деятельности и идей.
  • Kaggle: я эксперт по Kaggle. Следуйте за мной, чтобы увидеть мои проекты и решения в области науки о данных.

Ваша поддержка через подписки, аплодисменты на Medium и голоса на Kaggle очень ценна и побуждает меня продолжать создавать и делиться ценным контентом. Давайте учиться и расти вместе!