Why does my Jupyter notebook give different results when I re-run it?
Short answer
A notebook keeps hidden state from every cell you have run, in whatever order you ran them, so the visible code may not be what produced the output. Restart and run all before trusting a result.
The short version
A notebook holds state from every cell you have executed, in the order you executed them, not the order they appear on screen. So a result can depend on a cell you have since edited or deleted. Before trusting or sharing any result, use Restart and Run All, which reproduces the output from the code as it actually stands.
How the problem arises
You run a cell that defines df. Later you edit that cell but do not re-run it. The old df is still in memory, so every downstream cell keeps working, producing results from code that no longer exists anywhere.
Worse, running cells out of order can create a state that the notebook, read top to bottom, would never produce. The execution counts (In [7], In [3]) reveal this: if they are not in ascending order down the page, the notebook did not run in the order you are reading it.
The mutation trap
This bites especially hard with pandas, because many operations look idempotent but are not.
df = df[df["amount"] > 0] # run twice, filters twice (harmless here)
df["amount"] = df["amount"] * 1.2 # run twice, applies the increase TWICE
The second line is the dangerous kind: re-running the cell silently compounds the change. Your numbers are now 44 per cent higher, not 20, and nothing tells you.
The discipline
Write cells so that re-running them is safe. Read from a source, transform, and assign to a new name, rather than mutating in place.
raw = pd.read_csv("orders.csv") # the source, never modified
clean = raw[raw["amount"] > 0].copy() # derived, rebuilt each run
clean["with_vat"] = clean["amount"] * 1.2 # rebuilt from clean, not compounded
Now running any cell twice produces the same result, because each derives from an unchanged source rather than editing itself.
Restart and Run All, every time
Before reporting a number, sharing a notebook or committing it, restart the kernel and run everything from the top. If it fails or the numbers change, the notebook was lying to you, and better to find out now.
Set your seeds
Any sampling, shuffling or model fitting without a fixed seed gives different numbers each run, which looks like non-determinism but is simply unseeded randomness. Fix the seed so a re-run reproduces the result exactly.
When to leave the notebook
Notebooks are excellent for exploration and terrible for pipelines that must run reliably. Once the analysis is settled, move the logic into functions in a module, import it into the notebook, and test it. The notebook then becomes a thin presentation layer over code that is version-controlled, testable and free of hidden state, which is the arrangement that scales.