Как я могу сделать разделение на обучающую и тестовую выборки для несбалансированного панельного датасета в Python?

Вопрос или проблема

У меня есть несбалансированная панельная дата-рама pandas.

Я хотел бы разделить эти данные на обучающую и тестовую выборки. Метод train_test_split в Python не сработает, потому что он выполняет случайное разделение, и, следовательно, вероятно, поместит наблюдения из t + 1 в обучающую выборку, а наблюдения из t в тестовую.

Что, конечно, не имеет смысла, потому что будущее не может предсказать прошлое.

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

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

Не совсем уверен, что вы имеете в виду под панельным измерением, я думаю, было бы лучше уточнить это. Тем не менее, я могу сказать вам по вашему второму вопросу, что стратифицированная выборка учитывает дисбаланс. И если вы хотите иметь одну группу t в обучающей и t+1 в тестовой, вы можете использовать выборку по группам. Sklearn имеет обе реализации [1] [2].

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

def split_train_test(data: np.ndarray, distribution: list, test_ratio: float) -> Union:
    skf = StratifiedKFold(n_splits=int(test_ratio * 100), random_state=1374, shuffle=False)
    return next(skf.split(data, distribution))

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

split_train_test(data, labels, test_ratio)

Ответ или решение

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

Задача

У вас есть неуравновешенная панельная выборка, и вам необходимо провести разделение данных так, чтобы более ранние наблюдения попали в обучающую выборку, а более поздние — в тестовую. Базовые методы, такие как train_test_split из библиотеки scikit-learn, не годятся, так как они проводят случайное разделение, которое может нарушать временной порядок данных. Похожим образом, метод TimeSeriesSplit не учитывает панельное измерение вашего набора данных.

Решение

Для разделения такой выборки мы можем воспользоваться подходом, который будет учитывать как временной порядок, так и панельное измерение. Возможный способ это сделать — использовать метод, который основан на групповой выборке (group sampling), при этом будет полезно создать отдельный индикатор для каждого уровня панели.

Шаг 1: Подготовка данных

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

import pandas as pd

# Пример данных
data = {
    'id': [1, 1, 1, 2, 2, 2],
    'time': [1, 2, 3, 1, 2, 3],
    'value': [10, 20, 30, 15, 25, 5]
}
df = pd.DataFrame(data)
df['time'] = pd.to_datetime(df['time'], format='%Y%m%d')
df.set_index('time', inplace=True)

Шаг 2: Реализация функции для разделения

Создадим функцию, которая делит DataFrame по уникальным идентификаторам панелей и времени:

import numpy as np

def split_panel_data(df, test_ratio=0.2):
    # Список уникальных идентификаторов панелей
    unique_ids = df['id'].unique()

    train_indices = []
    test_indices = []

    for uid in unique_ids:
        # Получаем данные для конкретного идентификатора
        panel_data = df[df['id'] == uid]

        # Разбиваем данные на обучающий и тестовый наборы
        split_index = int(len(panel_data) * (1 - test_ratio))
        train_indices.extend(panel_data.index[:split_index])
        test_indices.extend(panel_data.index[split_index:])

    train_data = df.loc[train_indices]
    test_data = df.loc[test_indices]

    return train_data, test_data

train_set, test_set = split_panel_data(df, test_ratio=0.2)

Шаг 3: Обработка несбалансированности

Если у вас есть необходимость учитывать несбалансированность в обучающем наборе данных, вы можете применить метод стратифицированной выборки. Это можно сделать, используя StratifiedShuffleSplit из scikit-learn, сохраняя при этом временной порядок.

Пример использования ансамбля:

from sklearn.model_selection import StratifiedShuffleSplit

# Допустим, у нас есть целевая переменная
df['target'] = np.where(df['value'] > 15, 1, 0)

sss = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)

for train_index, test_index in sss.split(df, df['target']):
    strat_train_set = df.loc[train_index]
    strat_test_set = df.loc[test_index]

Заключение

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

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

Оцените материал
Добавить комментарий

Капча загружается...