Make your synthesis reproducible#

In the previous example, we created our first synthetic dataset. You may have noticed that we created the Synthesiser using the random_seed parameter:

synthesiser = Synthesiser(random_seed=1)

Without specifying a random_seed, if you run the same code again, you may notice that the generated synthetic dataset is different each time. This is expected. Synthetic data generation is a stochastic process: many synthesis methods involve randomness in, for example, sampling.

Sometimes this is exactly what you want. However, when developing analyses, writing reports or collaborating with others, it is often useful to generate exactly the same synthetic dataset every time. This is called reproducibility.

Generate two synthetic datasets#

Let’s start by fitting a Synthesiser without specifying a random seed.

from sklearn.datasets import load_diabetes
from synthpop import Synthesiser

data = load_diabetes(as_frame=True).frame

synthesiser = Synthesiser()
synthesiser.fit(data)

synthetic_data_1 = synthesiser.generate()
synthetic_data_2 = synthesiser.generate()

Both datasets were generated from the same fitted Synthesiser, but they are not identical.

Note: the results below may vary from yours as they are not reproducible.

synthetic_data_1.head(3)

age

sex

bmi

bp

s1

s2

s3

s4

s5

s6

target

0

-0.107226

-0.0446416

-0.011595

-0.0400989

-0.0153285

-0.00131388

-0.0323559

0.0158583

-0.027129

0.0196328

55

1

0.0489735

-0.0446416

-0.0256066

-0.00567042

0.0176944

0.0434664

0.0707299

-0.0247329

-0.0159989

0.0610539

113

2

-0.0563701

-0.0446416

0.0444512

-0.0194418

-0.00707277

-0.0238606

-0.0139477

-0.00259226

0.0757406

-0.013504

121

synthetic_data_2.head(3)

age

sex

bmi

bp

s1

s2

s3

s4

s5

s6

target

0

0.0671362

0.0506801

-0.0148285

0.0586076

0.0176944

0.0494162

-0.00658447

-0.00259226

-0.0332456

0.0569118

111

1

-0.0273098

0.0506801

-0.00728377

-0.0297704

0.0465894

0.0732155

-0.0286743

0.0343089

-0.00149595

-0.0466409

200

2

0.0417084

0.0506801

-0.0223731

-0.0400989

-0.030464

0.00119131

-0.021311

0.0158583

-0.0109033

0.0444855

83

Although both datasets preserve similar statistical properties, the individual synthetic records differ because new random samples are drawn each time.

synthetic_data_1.describe()

age

sex

bmi

bp

s1

s2

s3

s4

s5

s6

target

count

442

442

442

442

442

442

442

442

442

442

442

mean

0.000345173

0.00150962

0.000777878

-0.00262506

-0.00255579

-0.00409148

-0.00128691

-0.00179496

0.0023855

-0.0012089

151.928

std

0.0484934

0.0476909

0.0485026

0.0476364

0.0488929

0.049221

0.0486984

0.0477245

0.0468386

0.0464237

76.3776

min

-0.107226

-0.0446416

-0.0891975

-0.112399

-0.126781

-0.115613

-0.102307

-0.0763945

-0.104366

-0.129483

31

25%

-0.0409318

-0.0446416

-0.0331513

-0.0366561

-0.0373437

-0.0356819

-0.0360376

-0.0394934

-0.0307479

-0.033179

89

50%

0.00538306

-0.0446416

-0.00620595

-0.0108347

-0.00707277

-0.010082

-0.00658447

-0.00259226

0.00200444

0.00306441

137.5

75%

0.0380759

0.0506801

0.0315175

0.0287581

0.0245741

0.0262432

0.0302319

0.0343089

0.0354587

0.0279171

202

max

0.110727

0.0506801

0.170555

0.125158

0.153914

0.198788

0.173816

0.185234

0.133597

0.135612

341

synthetic_data_2.describe()

age

sex

bmi

bp

s1

s2

s3

s4

s5

s6

target

count

442

442

442

442

442

442

442

442

442

442

442

mean

0.000575288

0.00021566

0.00363823

0.001088

1.55649e-05

-0.00141909

-0.00410228

0.00398565

0.00285974

0.00231471

155.394

std

0.0492173

0.0476323

0.047053

0.0482004

0.0471131

0.0470191

0.0447474

0.0500362

0.0491795

0.0484639

77.315

min

-0.107226

-0.0446416

-0.0902753

-0.108956

-0.108893

-0.112795

-0.102307

-0.0763945

-0.126097

-0.137767

31

25%

-0.0418399

-0.0446416

-0.0320734

-0.0366561

-0.0345918

-0.0338813

-0.0397192

-0.0394934

-0.0316777

-0.0300724

88.25

50%

0.0090156

-0.0446416

-0.0013558

-0.00567042

-0.00363289

-0.00976889

-0.0139477

-0.00259226

0.00286131

0.000993356

151

75%

0.0380759

0.0506801

0.0358287

0.0390866

0.0256061

0.0293747

0.0265503

0.0343089

0.037667

0.0279171

216.75

max

0.0961965

0.0506801

0.137143

0.125158

0.153914

0.155887

0.159089

0.185234

0.133597

0.135612

341

Set a random seed#

To obtain reproducible results, specify the random_seed parameter when creating the Synthesiser.

synthesiser_1 = Synthesiser(random_seed=1)

synthesiser_1.fit(data)

synthetic_data_1 = synthesiser_1.generate()

Now create a new Synthesiser with the same random seed.

synthesiser_2 = Synthesiser(random_seed=1)

synthesiser_2.fit(data)

synthetic_data_2 = synthesiser_2.generate()

Both datasets are now identical.

synthetic_data_1.equals(synthetic_data_2)
True

Because every random decision is made from the same initial random state, the complete synthesis process can be reproduced exactly.

When should you use a random seed?#

Using a random seed is recommended when you want reproducible results, for example when:

  • writing documentation or tutorials;

  • comparing different synthesis methods;

  • debugging your synthesis pipeline;

  • sharing analyses with colleagues;

  • running automated tests.

Reproducibility and multiple synthetic datasets#

Sometimes you may want several different synthetic datasets from the same fitted Synthesiser, for example to quantify the variability introduced by the synthesis process.

However, if a random seed is provided, you cannot simply call generate() multiple times as we saw in the first code block of this page.

synthesiser = Synthesiser(random_seed=1)
synthesiser.fit(data)

synthetic_data_1 = synthesiser.generate()
synthetic_data_2 = synthesiser.generate()
synthetic_data_1.equals(synthetic_data_2)
True

To create multiple reproducible synthetic dataset from the same fitted synthesiser, you can use the random_seed parameter in the generate() function.

synthetic_data_3 = synthesiser.generate(random_seed=2)

Each generated dataset with a different random seed will be different, because the synthesiser continues drawing new random samples.

synthetic_data_3.equals(synthetic_data_1)
False

Omitting the random_seed parameter will again provide you with the first synthetic dataset.

synthetic_data_4 = synthesiser.generate()

synthetic_data_4.equals(synthetic_data_1)
True

Next steps#

Now that your synthesis is reproducible, the next examples in this module show you how to generate larger datasets and how to choose a synthesis order.