Generating Repeatable Noisy Data
Synthetic data lets us test a fitting method against a known underlying relation. This lesson builds paired measurements from a linear signal and seeded normal noise, then checks the properties that should remain true across valid runs.
The project needs measurements before it can fit a line. Rather than begin with an unknown real dataset, we will generate synthetic data: artificial data created from a process whose important properties are known.
Knowing the process gives us an answer against which the fitting method can be checked.
Separate the signal from the noise
For each input value , generate one measurement:
Read this as: “y sub i equals the true slope times x sub i, plus noise epsilon sub i.”
The two parts have different roles:
- is the signal, the systematic relation we want the fitting method to recover;
- is noise, variation added to one measurement.
Suppose the true slope is 2.0, the input is x = 2.0, and the generated
noise is -0.3. The clean signal and noisy measurement are:
clean signal = 2.0 * 2.0 = 4.0
measurement = 4.0 + (-0.3) = 3.7
The measurement does not need to lie exactly on the line. The underlying relation is still present, but the program must estimate it from several imperfect measurements.
Use a simple line through the origin
This project uses:
There is no intercept term. When x is zero, the clean value of y is also
zero.
A more general line has the form , where is the intercept. Learning both slope and intercept would require searching over two unknown values. Keeping the intercept fixed at zero lets this project concentrate on one complete fitting workflow before adding another parameter.
Choose input coordinates deliberately
Create evenly spaced input coordinates with np.linspace:
The first coordinate is 0.0, the last is 5.0, and
config.point_count determines how many values appear between them. For
point_count=6, the result is:
[0. 1. 2. 3. 4. 5.]
The coordinate range affects how visible a slope difference becomes. For
example, slopes 2.0 and 2.1 differ by only 0.1 at x=1, but by 0.5 at
x=5. The chosen range is therefore part of the data-generating process, not
an arbitrary display detail.
Draw noise from a normal distribution
Create a NumPy generator from the configured seed:
rng = np.random.default_rng(config.seed)
Then draw one noise value for each input:
The normal distribution is centred at loc=0.0, so positive and negative
noise balance around zero over many draws. The scale argument is the standard
deviation. It controls the typical size of the variation.
The scale is not a strict maximum. With noise_scale=0.25, NumPy can generate
a value whose magnitude is greater than 0.25; such values become less common
as their distance from zero increases.
The noise array has the same shape as x. NumPy can therefore add one noise
value to each clean signal value:
Make one run reproducible
A seed establishes the generator's initial state. Creating a new generator with the same seed and making the same draws in the same order reproduces the same noise:
This prints True.
Two consecutive draws from one generator are normally different because the first draw advances its state:
This normally prints False. Repeatability depends on the seed and the
sequence of generator operations, not on the seed alone.
Implement the data-generating function
The function below validates the configuration, creates the input coordinates, draws noise, and returns paired arrays. Change the seed or noise scale and compare the clean and measured values.
Generate repeatable noisy measurements
The function creates a new generator from the configured seed. Calling it twice with the same configuration therefore reproduces the same x and y arrays.
Ready to run.
The expression y - clean_y recovers the noise that was added during data
generation. We can inspect it here because synthetic data gives us both the
clean signal and the noisy measurements.
Test guarantees rather than one printed array
The exact measurements depend on the seed and generator behavior. More durable
checks target the contract of make_data:
For repeatability under the same environment and operation order:
Do not require the sample noise to have an average of exactly zero. A zero-centred distribution describes the generating process over many draws; one small sample can have a positive or negative average.
Synthetic data is a controlled test, not proof of realism
Synthetic data is useful because:
- the true slope is known;
- the amount and kind of noise are controlled;
- mistaken shapes and formulas are easier to diagnose;
- a run can be reproduced from its configuration.
It also has important limits. Success on these measurements shows that the fitting code works for this constructed process. It does not show that real measurements follow a line, have normally distributed noise, pass through the origin, or contain no other sources of error.
In the equation , which expression is the non-random signal?
Select one choice, then check.
HintFind the clean relation
The signal is the value that would remain if the generated noise were zero.
SolutionThe signal is the true line
The signal is . The term is the generated noise, and their sum is the observed measurement.
The true slope is 2.0, the input is x = 3.0, and the generated noise is
-0.4. What measured y value is produced?
Answer it first, then check.
HintCompute the clean signal first
Calculate 2.0 * 3.0, then add -0.4.
SolutionAdd noise to the clean value
The clean value is 2.0 * 3.0 = 6.0. The measurement is
6.0 + (-0.4) = 5.6.
What does noise_scale=0.25 mean in
rng.normal(loc=0.0, scale=0.25, size=6)?
Select one choice, then check.
HintDistinguish spread from bounds
A normal distribution is not limited to a closed interval.
SolutionScale controls the distribution's spread
scale=0.25 sets the standard deviation to 0.25. Individual values may
have magnitude greater than 0.25, and a small sample need not have any
exact predetermined average.
What should you normally expect from this program?
Select one choice, then check.
HintTrack generator state
The first call changes the generator's current state before the second call.
SolutionSuccessive draws use successive states
The arrays normally differ. The seed establishes the initial state, and each draw advances that state. Recreating a generator with the same seed would restart the sequence.
Complete make_data so it creates four evenly spaced inputs from 0.0 through
3.0, draws one normal noise value per input, and returns paired x and y
arrays. The program must print:
shape: (4,)
paired: True
repeatable: True
Generate paired data from a seeded process
Ready to run.
HintUse one noise value for each x value
Create x with np.linspace(0.0, 3.0, num=4). Set the noise draw's size
to x.size.
SolutionBuild the signal and add seeded noise
np.linspace creates the four coordinates. The generator draws a noise array
with the same number of values, and elementwise addition produces the paired
measurements. Recreating the generator inside the function makes a repeated
call with the same arguments reproduce the arrays.
Preserve the data-generating process
A synthetic dataset is identified by more than the returned arrays. Preserve:
coordinate rule
true slope
intercept assumption
noise distribution
noise scale
seed
number and order of generator draws
Together, these choices explain where the measurements came from and make the
controlled test reproducible. The fitting stage can now use x and y
without knowing the true slope directly.