See How Outliers Change Mean and Median
Calculate mean and median and explain why an extreme value affects them differently.
Example check: Worked and guided code samples are checked against CPython 3.13. Practice uses Pyodide 0.29.5 (Python 3.13) in your browser. How we check lessons
Video lesson: See How Outliers Change Mean and Median
The preview is stored on this site. YouTube loads only when you press Play. Watch on YouTube
Jump to a chapter
Read the video transcript
Select a timestamp to watch that moment on YouTube.
- 00:00
A dashboard says the average value is 22.8, but four of its five observations are no larger than five. Is the dashboard wrong? It may simply be using the arithmetic mean, which includes the magnitude of every value. The median, the center of the sorted data, is four. Both are correct calculations, but a vague label such as average hides the difference. Today we will make a report that shows both measures and their signed gap. We will also reproduce a practical Python bug that appears when the input is a generator: one statistic consumes the iterator, leaving no values for the second statistic.
- 00:41
The fix is to materialize the data once before asking for two passes. We will test an odd-sized skewed group, an even-sized group, a generator, and an empty input. The value one hundred might be a rare valid event, a typing mistake, or a member of another group. The difference between mean and median tells us to inspect context; it does not authorize deleting data. You can run every sample in the lesson's browser console and then complete the checked function. The mean call receives all five generated values, adds them, and returns 22.8. A generator is a one-shot iterator; after those values have been yielded, it has
- 01:23
nothing left. median then sees empty input and raises StatisticsError. The try block catches that error so our video can display the symptom rather than stopping. This bug can hide when a function is tested only with lists, because lists can be traversed repeatedly. The public function should accept an iterable, and that includes a generator unless we deliberately restrict its contract. We could redesign a streaming statistical algorithm for very large datasets, but computing an exact median generally needs more information than a simple running sum. For this small lesson, copying the iterable into a list once is the clear solution.
- 02:05
We must also decide what happens when the original input is truly empty. Returning zero would invent a measurement; this task rejects emptiness with ValueError. Before implementing that repair, look closely at what the two statistics would mean on the actual data. With one hundred included, the mean is 22.8 and the median is four. When we temporarily remove it, both summaries are 3.5. This exercise is a comparison, not a recommendation to discard the last observation. The mean responds strongly because one hundred contributes directly to the sum and the denominator still counts five values.
- 02:46
The median of the five-item list is the third value after sorting. It remains four even though the largest value is much farther away. For the four-item list, median has no single center value, so it averages the two middle values, three and four, to obtain 3.5. This distinction is useful when explaining salaries, transaction sizes, response times, or any distribution with a long tail. It is also easy to misuse. A median can conceal the magnitude of a severe high-end event, while a mean can be dominated by that event. Showing both often tells a more honest story than choosing one silently.
- 03:27
Our function returns a signed mean-minus- median gap to make the difference visible. It is not an outlier detector; no statistical threshold has been defined, and a positive gap alone cannot tell us whether the high value is valid. The list conversion is the central repair. It consumes the generator exactly once and gives both statistics the same observations. The empty check provides the function's own useful failure message instead of asking the library to fail later. We compute mean and median, then return each alongside their signed difference. In this dataset the gap is positive 18.8 because the large upper value pulls the
- 04:08
mean above the middle position. A different distribution could produce a negative gap. Keeping the input as a list has a memory cost proportional to the number of observations, which is reasonable for a small report but should be reconsidered for millions of records. This function also leaves a caller's existing list unchanged: list(values) makes a new outer list and statistics.mean and median do not sort the input in place. Do not conflate that with deep copying nested objects; the function only reads numeric values. On the companion page, the starter code already materializes an iterable but
- 04:49
incorrectly calls the mean the median and hard-codes a zero gap. Replace those placeholders and handle the empty case explicitly. Then compare the result with the visible example before running the checker. We first confirm the skewed result and that the source list has not changed. The even-sized sample checks an important median rule: with four sorted values the two center numbers are three and four, so the median is 3.5. That case also produces a zero gap, which is a genuine result, not a default for every input. The generator assertion proves the function can consume a one-shot iterable once and still compute both statistics.
- 05:32
An empty list is deliberately rejected because no mean or median exists for it; we print a short message only after catching ValueError. If any implementation returns a made-up zero or silently ignores the generator problem, the check will fail. Consider a final exercise: add a second large value, perhaps 90, and predict what happens to both measures before running the code. The center position may move once enough large values are present. That helps explain why neither statistic is magically immune to a dataset's composition. For a real dashboard, include the sample size and units, inspect whether extreme
- 06:13
observations are legitimate, and label the measure you show. The task on the website checks the function's output and behavior; the quiz checks the interpretation. Completing both makes the lesson more than a memorized call to statistics.mean or statistics.median.
Understand the concept
An average can mean several different things. The arithmetic mean is the sum divided by the number of observations. The median is the middle value after ordering the data, or the average of the two middle values when the count is even. Python's statistics module implements both. Before choosing one for a report, ask what question the report should answer. The mean uses every magnitude; the median describes the middle position.
An extreme observation can move the mean dramatically while barely moving the median. In [2, 3, 4, 5, 100], the mean is 22.8 even though four of five values are at most five, while the median remains four. The value 100 could be a valid rare case, a recording error, or a different population. Do not delete it merely because the mean looks odd. Inspect the source and state whether the summary includes it.
The median for an even count is halfway between the two center values. For [2, 3, 4, 5], both mean and median are 3.5. An empty dataset has neither a meaningful mean nor a median; the statistics functions raise StatisticsError for empty input. This lesson's wrapper raises ValueError with an application message before calling them. The wrapper also accepts any finite iterable by first making one list, avoiding consumption of a generator twice.
mean_median_gap returns a dictionary with the mean, median, and their signed difference. A large gap may prompt investigation, but it is not an outlier detector or a proof of bad data. The tests use a skewed group, an even group, a generator, and an empty input. They also ensure the input list is unchanged. This keeps the statistical interpretation honest and the implementation reusable.
- Mean uses every magnitude
- Median is the center after sorting
- Even-size median averages two center values
- A mean–median gap suggests inspection, not automatic deletion
See it step by step
Read the code, predict the output, then compare it with the result.
01. Compare a skewed group's centers
from statistics import mean, median
data = [2, 3, 4, 5, 100]
print(mean(data))
print(median(data))22.8
4The extreme 100 contributes to the mean's sum; it does not become the middle observation.
02. Check an even number of values
from statistics import mean, median
data = [2, 3, 4, 5]
print(mean(data))
print(median(data))3.5
3.5The median is the average of the two center values, 3 and 4.
03. Handle empty input deliberately
from statistics import mean, StatisticsError
try:
mean([])
except StatisticsError:
print('no mean for empty data')no mean for empty dataA wrapper may translate this library error into a clearer application-specific ValueError.
A closer look
Follow the reasoning, inspect each result, then try the suggested changes in the console below.
Watch one extreme observation move the mean
Use a small dataset that can be checked by hand. Four observations are near each other and the fifth is one hundred. The mean adds all five magnitudes and divides by five, so that one extreme value pulls it far above most observations. The median takes the central position of the ordered values and remains four.
Both answers are mathematically correct, but they answer different questions. A report labelled only 'average' hides that choice. Do not delete the value one hundred because it is inconvenient: it might represent a legitimate high order or a data-entry mistake. First check its source, then state whether the analysis includes it.
from statistics import mean, median
values = [2, 3, 4, 5, 100]
print(mean(values))
print(median(values))
print(mean(values) - median(values))22.8
4
18.8- The mean uses every magnitude.
- The median identifies the center position.
- Their signed gap flags a difference worth interpreting.
Check the even-size rule and empty case
With an even number of observations, no single value occupies the center. Python's median averages the two middle values after sorting. For two, three, four, and five, those middle values are three and four, so the median is 3.5. This is a defined rule, not the same as always choosing the lower or upper center.
Empty input is different: there is no center and no denominator for a mean. The statistics functions signal this with StatisticsError. The public function in this lesson translates that condition to ValueError before calculating so callers receive an error tied to its own data contract. Avoid returning zero; zero would misleadingly look like a measured summary.
from statistics import mean, median, StatisticsError
print(mean([2, 3, 4, 5]), median([2, 3, 4, 5]))
try:
mean([])
except StatisticsError:
print('empty data has no mean')3.5 3.5
empty data has no mean- Even-size median averages two center values.
- The empty set has no numerical center.
- A wrapper can provide a clearer domain exception.
Summarize a one-shot iterable safely
A list can be traversed repeatedly, but a generator is consumed as it yields values. Calling mean(values) and then median(values) on one generator can leave the second call with no data. Materialize it once into a list when a calculation genuinely needs multiple passes. The cost is memory proportional to the input; a huge stream would call for another design.
The completed function checks for empty data, computes both statistics on the same observations, and returns a signed gap without altering the caller's list. The browser task includes a generator precisely to catch a solution that accidentally reads it twice. A gap is a prompt for investigation, not an automatic outlier classifier.
from statistics import mean, median
def mean_median_gap(values):
items = list(values)
if not items:
raise ValueError('at least one value is required')
average = mean(items)
middle = median(items)
return {'mean': average, 'median': middle, 'gap': average - middle}
print(mean_median_gap(x for x in [2, 3, 4, 5, 100])){'mean': 22.8, 'median': 4, 'gap': 18.8}- Materialize once before both computations.
- Reject emptiness explicitly.
- Return both measures so the caller can interpret their difference.
Try it in Python
Edit the example and run it. Python starts in your browser the first time you click Run.
Python console
Ready to runNeed input()? Add one value per line
Your output appears here.
Need a hint?
Import median next to mean. After items = list(values), reject an empty list, then calculate average = mean(items), middle = median(items), and their difference.
Complete the task and select Check task to verify your code.
Quick quiz
Three questions. You can change your answers and try again.
Typical mistakes
Everyone meets these errors. See what causes them and how to fix them.
Calling the mean the typical observation
print(mean([2,3,4,5,100])) # typical valueprint('mean', mean(data), 'median', median(data))What happens: The label suggests an ordinary observation around 22.8, but none is nearby.
Show both summaries and interpret their disagreement.
Iterating a generator twice
average = mean(values)
middle = median(values)items = list(values)
average = mean(items)
middle = median(items)What happens: A one-shot iterator may be empty on its second use.
Materialize once when multiple passes are required.