В этом руководстве мы создадим полный конвейер для генерации синтетических данных с использованием CTGAN и экосистемы SDV. Мы начнём с необработанных табличных данных смешанного типа и постепенно перейдём к ограниченной генерации, условной выборке, статистической проверке и тестированию полезности в последующих процессах.
Мы сосредоточимся не только на генерации образцов, но и на понимании того, насколько хорошо синтетические данные сохраняют структуру, распределения и прогностические сигналы. Это руководство демонстрирует, как можно ответственно и строго использовать CTGAN в реальных рабочих процессах в области науки о данных.
Установка среды
Для начала установим все необходимые библиотеки:
«`python
!pip -q install «ctgan» «sdv» «sdmetrics» «scikit-learn» «pandas» «numpy» «matplotlib»
«`
«`python
import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings(«ignore»)
import ctgan, sdv, sdmetrics
from ctgan import load_demo, CTGAN
from sdv.metadata import SingleTableMetadata
from sdv.single_table import CTGANSynthesizer
from sdv.cag import Inequality, FixedCombinations
from sdv.sampling import Condition
from sdmetrics.reports.single_table import DiagnosticReport, QualityReport
from sklearn.modelselection import traintest_split
from sklearn.metrics import rocaucscore
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
import matplotlib.pyplot as plt
«`
Загрузка данных
«`python
print(«Versions:»)
print(«ctgan:», ctgan.version)
print(«sdv:», sdv.version)
print(«sdmetrics:», sdmetrics.version)
real = load_demo().copy()
real.columns = [c.strip().replace(» «, «_») for c in real.columns]
target_col = «income»
real[targetcol] = real[targetcol].astype(str)
categoricalcols = real.selectdtypes(include=[«object»]).columns.tolist()
numericalcols = [c for c in real.columns if c not in categoricalcols]
print(«Rows:», len(real), «Cols:», len(real.columns))
print(«Categorical:», len(categoricalcols), «Numerical:», len(numericalcols))
display(real.head())
«`
Генерация синтетических данных с помощью CTGAN
«`python
ctgan_model = CTGAN(
epochs=30,
batch_size=500,
verbose=True
)
ctganmodel.fit(real, discretecolumns=categorical_cols)
syntheticctgan = ctganmodel.sample(5000)
print(«Standalone CTGAN sample:»)
display(synthetic_ctgan.head())
«`
Создание формального метаданных и введение структурных ограничений
«`python
metadata = SingleTableMetadata()
metadata.detectfromdataframe(data=real)
metadata.updatecolumn(columnname=target_col, sdtype=»categorical»)
constraints = []
if len(numerical_cols) >= 2:
collo, colhi = numericalcols[0], numericalcols[1]
constraints.append(Inequality(lowcolumnname=collo, highcolumnname=colhi))
print(f»Added Inequality constraint: {colhi} > {collo}»)
if len(categorical_cols) >= 2:
c1, c2 = categoricalcols[0], categoricalcols[1]
constraints.append(FixedCombinations(column_names=[c1, c2]))
print(f»Added FixedCombinations constraint on: [{c1}, {c2}]»)
synth = CTGANSynthesizer(
metadata=metadata,
epochs=30,
batch_size=500
)
if constraints:
synth.add_constraints(constraints)
synth.fit(real)
syntheticsdv = synth.sample(numrows=5000)
print(«SDV CTGANSynthesizer sample:»)
display(synthetic_sdv.head())
«`
Визуализация динамики потерь генератора и дискриминатора
«`python
lossdf = synth.getloss_values()
display(loss_df.tail())
x_candidates = [«epoch», «step», «steps», «iteration», «iter», «batch», «update»]
xcol = next((c for c in xcandidates if c in lossdf.columns), None)
gcandidates = [«generatorloss», «genloss», «gloss»]
dcandidates = [«discriminatorloss», «discloss», «dloss»]
gcol = next((c for c in gcandidates if c in lossdf.columns), None)
dcol = next((c for c in dcandidates if c in lossdf.columns), None)
plt.figure(figsize=(10,4))
if xcol is None:
x = np.arange(len(loss_df))
else:
x = lossdf[xcol].tonumpy()
if gcol is not None:
plt.plot(x, lossdf[gcol].tonumpy(), label=gcol)
if dcol is not None:
plt.plot(x, lossdf[dcol].tonumpy(), label=dcol)
plt.xlabel(xcol if xcol is not None else «index»)
plt.ylabel(«loss»)
plt.legend()
plt.title(«CTGAN training losses (SDV wrapper)»)
plt.show()
«`
Условная выборка
«`python
condcol = categoricalcols[0]
commonvalue = real[condcol].value_counts().index[0]
conditions = [Condition({condcol: commonvalue}, num_rows=2000)]
syntheticcond = synth.samplefrom_conditions(
conditions=conditions,
maxtriesper_batch=200,
batch_size=5000
)
print(«Conditional sampling requested:», 2000, «got:», len(synthetic_cond))
print(«Conditional sample distribution (top 5):»)
print(syntheticcond[condcol].value_counts().head(5))
display(synthetic_cond.head())
«`
Оценка синтетических данных
«`python
metadatadict = metadata.todict()
diagnostic = DiagnosticReport()
diagnostic.generate(realdata=real, syntheticdata=syntheticsdv, metadata=metadatadict, verbose=True)
print(«Diagnostic score:», diagnostic.get_score())
quality = QualityReport()
quality.generate(realdata=real, syntheticdata=syntheticsdv, metadata=metadatadict, verbose=True)
print(«Quality score:», quality.get_score())
«`
Проверка полезности синтетических данных
«`python
trainreal, testreal = traintestsplit(
real, testsize=0.25, randomstate=42, stratify=real[target_col]
)
def makepipeline(catcols, num_cols):
pre = ColumnTransformer(
transformers=[
(«cat», OneHotEncoder(handleunknown=»ignore»), catcols),
(«num», «passthrough», num_cols),
],
remainder=»drop»
)
clf = LogisticRegression(max_iter=200)
return Pipeline([(«pre», pre), («clf», clf)])
pipesyn = makepipeline(categoricalcols, numericalcols)
pipesyn.fit(syntheticsdv.drop(columns=[targetcol]), syntheticsdv[target_col])
probasyn = pipesyn.predictproba(testreal.drop(columns=[target_col]))[:, 1]
ytrue = (testreal[target_col].astype(str).str.contains(«>»)).astype(int)
aucsyn = rocaucscore(ytrue, proba_syn)
print(«Synthetic-train -> Real-test AUC:», auc_syn)
pipereal = makepipeline(categoricalcols, numericalcols)
pipereal.fit(trainreal.drop(columns=[targetcol]), trainreal[target_col])
probareal = pipereal.predictproba(testreal.drop(columns=[target_col]))[:, 1]
aucreal = rocaucscore(ytrue, proba_real)
print(«Real-train -> Real-test AUC:», auc_real)
«`
Сохранение синтезатора
«`python
modelpath = «ctgansdv_synth.pkl»
synth.save(model_path)
print(«Saved synthesizer to:», model_path)
from sdv.utils import load_synthesizer
synthloaded = loadsynthesizer(model_path)
syntheticloaded = synthloaded.sample(1000)
print(«Loaded synthesizer sample:»)
display(synthetic_loaded.head())
«`
В заключение, мы продемонстрировали, что генерация синтетических данных с помощью CTGAN становится значительно более мощной в сочетании с метаданными, ограничениями и тщательной оценкой. Путем проверки как статистической схожести, так и производительности в последующих задачах мы убедились, что синтетические данные не только реалистичны, но и полезны. Этот конвейер служит прочной основой для аналитики с сохранением конфиденциальности, обмена данными и моделирования рабочих процессов. При тщательной настройке и оценке CTGAN можно безопасно развёртывать в реальных системах обработки данных.
1. Какие библиотеки и инструменты используются для генерации синтетических данных в этом руководстве?
Ответ: в этом руководстве используются библиотеки CTGAN, SDV, SDMetrics, scikit-learn, pandas, numpy, matplotlib. Для генерации синтетических данных применяется CTGAN в сочетании с экосистемой SDV.
2. Какие шаги включает в себя процесс генерации синтетических данных с помощью CTGAN?
Ответ: процесс генерации синтетических данных с помощью CTGAN включает в себя установку необходимой среды, загрузку данных, генерацию синтетических данных с помощью CTGAN, создание формальных метаданных и введение структурных ограничений, визуализацию динамики потерь генератора и дискриминатора, условную выборку, оценку синтетических данных и проверку их полезности.
3. Какие метрики используются для оценки качества синтетических данных?
Ответ: для оценки качества синтетических данных используются DiagnosticReport и QualityReport. Они позволяют получить диагностические и качественные оценки синтетических данных по сравнению с исходными данными. Также для проверки полезности синтетических данных используется ROC AUC (площадь под кривой ошибок) для логистической регрессии.
4. Какие структурные ограничения можно ввести при генерации синтетических данных с помощью CTGAN?
Ответ: при генерации синтетических данных с помощью CTGAN можно ввести структурные ограничения, такие как неравенства между числовыми столбцами и фиксированные комбинации между категориальными столбцами. Это позволяет более точно настроить генерацию данных в соответствии с требованиями задачи.
5. Как можно сохранить синтезатор CTGAN для дальнейшего использования?
Ответ: синтезатор CTGAN можно сохранить с помощью метода save() в файл. Затем его можно загрузить обратно с помощью load_synthesizer() для генерации дополнительных синтетических данных.