Python, Графики

Генерация синтетических табличных данных на Python

Время прочтения: 5 мин.

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

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

Отсюда вопрос – что делать?

Для начала рассмотрим инструментарий.

Для тех, кто не знает, на Python активно разрабатывается библиотека SDV (Synthetic Data Vault). Достоинство этой библиотеки в том, что она позволяет не особо сведущему в этой области специалисту генерировать данные следующим образом:

Import pandas as pd
from sdv.tabular import <<Model>>

data = pd.read_csv(‘data.csv’)
model = <<Model>>()
model.fit(data)
new_data = model.sample(200)

Прямо в стиле “model.fit – model.predict”! Просто и лаконично.

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

  • Gaussian Copula;
  • CTGAN;
  • CopulaGAN;
  • TVAE.

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

CTGAN и CopulaGAN базируются на генеративно-состязательных нейронных сетях (Generative-Adversarial Networks), которые представляют из себя комбинацию из двух нейронных сетей, одна из которых генерирует наблюдения, а другая — оценивает их на правдоподобность. Модель TVAE базируется на вариационных автоэнкодерах (VAE).

Подробнее о всех тонкостях устройства каждой модели можно почитать в документации библиотеки.

Чтобы увидеть SDV в действии, возьмем из Интернета какой-нибудь набор данных:

И попробуем на них обучить самую простую модель — Gaussian Copula — и сгенерировать новый набор данных:

model = GaussianCopula()
model.fit(data)

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

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

Сравнительные гистограммы в python можно построить с помощью следующего кода:

def draw_comparative_hist (parametr: str, original_data: pd.DataFrame, data_sampled: pd.DataFrame):
    final_df = pd.DataFrame()
    df1 = pd.DataFrame()
    df1[parametr] = original_data[parametr]
    df1['Data'] = 'Original data'
    df1['Probability'] = df1[parametr].apply(lambda x: (df1.groupby(parametr)[parametr].count()[x])/original_data.shape[0])
    df2 = pd.DataFrame()
    df2[parametr] = data_sampled[parametr]
    df2['Data'] = 'Synthetic data'
    df2['Probability'] = df2[parametr].apply(lambda x: (df2.groupby(parametr)[parametr].count()[x])/data_sampled.shape[0])
    final_df = pd.concat([df1, df2])
    sns.barplot(x=parametr, y="Probability", hue="Data", data=final_df)
    plt.show()

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

Oops…

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

Как это можно сделать для данной модели? Покопавшись в коде библиотеки на GitHub, я нашел в исходниках GaussianCopula интересный словарь, который позволяет задать конкретному столбцу конкретное распределение:

_DISTRIBUTIONS = {, 
'univariate': copulas.univariate.Univariate,
'parametric': copulas.univariate.Univariate(
parametric=copulas.univariate.ParametricType.PARAMETRIC),
'bounded': copulas.univariate.Univariate(
bounded=copulas.univariate.BoundedType.BOUNDED),
'semi_bounded': copulas.univariate.Univariate(
bounded=copulas.univariate.BoundedType.SEMI_BOUNDED),
'parametric_bounded': copulas.univariate.Univariate(
parametric=copulas.univariate.ParametricType.PARAMETRIC,
bounded=copulas.univariate.BoundedType.BOUNDED,
),
'parametric_semi_bounded': copulas.univariate.Univariate(
parametric=copulas.univariate.ParametricType.PARAMETRIC,
bounded=copulas.univariate.BoundedType.SEMI_BOUNDED,
),
'gaussian': copulas.univariate.GaussianUnivariate,
'gamma': copulas.univariate.GammaUnivariate,
'beta': copulas.univariate.BetaUnivariate,
'student_t': copulas.univariate.StudentTUnivariate,
'gaussian_kde': copulas.univariate.GaussianKDE,
'truncated_gaussian': copulas.univariate.TruncatedGaussian,
}

Вот как на практике выглядит применение этого словаря:

data = pd.read_csv(‘bank.csv’)
from sdv.tabular import GaussianCopula
field_distributions_cont = {'age':'gamma', 'job':'beta', 'marital':'gaussian','previous':'student_t','campaign':'gaussian_kde'}
model = GaussianCopula(field_distributions = field_distributions_cont)
model.fit(data)
new_data = model.sample(5000)

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

Как видите, получилось неплохо. Не идеально, но процесс настройки можно продолжать. Изюминкой GaussianCopula на практике является достаточная точность при щадящем потреблении ресурсов машины — в отличие от тех же GAN-моделей, которые точнее моделируют распределения признаков, но в то же время их не рекомендуется запускать на маломощных машинах, например, на ноутбуках.

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

Спасибо за внимание!

Советуем почитать