Statistics Range and IQR

Range and the interquartile range (IQR) measure how spread out a data set is, with the IQR giving a more robust picture by ignoring extreme outliers.

Two Ways to Measure Spread

Knowing the center of a data set (like the mean or median) only tells half the story. Two classes could both average 75 on a test, yet one class might have scores tightly packed between 70 and 80 while the other ranges from 20 to 100. Measures of spread capture that difference. The simplest measure is the range: the maximum value minus the minimum value. It is easy to compute but extremely sensitive to a single unusual value.

A Class With One Unusual Score

Suppose 13 students took a quiz (out of 50). Twelve of them scored between 32 and 50, but one student, who felt ill and left early, scored only 15. Sorted, the scores are: 15, 32, 35, 38, 40, 41, 43, 44, 45, 47, 48, 49, 50.

Position (sorted)Score
115
232
335
438
540
641
743
844
945
1047
1148
1249
1350

Example: Range

scores = [15, 32, 35, 38, 40, 41, 43, 44, 45, 47, 48, 49, 50]
data_range = max(scores) - min(scores)
print(f"Range: {data_range}")

# Output:
# Range: 35

The Interquartile Range (IQR)

The IQR describes the spread of the middle 50% of the data, ignoring the extreme top and bottom quarters. It is calculated as IQR = Q3 - Q1, where Q1 is the 25th percentile and Q3 is the 75th percentile. Because it deliberately excludes the tails, one extreme value barely moves it.

Example: Q1, Q3, IQR, and Outlier Fences

scores = [15, 32, 35, 38, 40, 41, 43, 44, 45, 47, 48, 49, 50]
scores.sort()
n = len(scores)

def percentile(data, p):
    rank = (p / 100) * (n - 1)
    lower = int(rank)
    upper = lower + 1 if lower + 1 < n else lower
    fraction = rank - lower
    return data[lower] + fraction * (data[upper] - data[lower])

q1 = percentile(scores, 25)
q3 = percentile(scores, 75)
iqr = q3 - q1
lower_fence = q1 - 1.5 * iqr
upper_fence = q3 + 1.5 * iqr

print(f"Q1: {q1}, Q3: {q3}, IQR: {iqr}")
print(f"Outlier fences: [{lower_fence}, {upper_fence}]")

outliers = [x for x in scores if x < lower_fence or x > upper_fence]
print(f"Outliers: {outliers}")

# Output:
# Q1: 38, Q3: 47, IQR: 9
# Outlier fences: [24.5, 60.5]
# Outliers: [15]
  1. Find Q1 (25th percentile) and Q3 (75th percentile).
  2. Compute IQR = Q3 - Q1.
  3. Compute the lower fence: Q1 - 1.5 x IQR.
  4. Compute the upper fence: Q3 + 1.5 x IQR.
  5. Any value outside the fences is flagged as an outlier.
Note: In this data set, the lower fence is 24.5, and the ill student's score of 15 falls below it -- so it is statistically flagged as an outlier. That does not automatically mean it should be deleted; it means it deserves a closer look (in this case, we already know the reason: illness).
Note: If you drop the outlier of 15, the range shrinks dramatically from 35 to 18, but Q1 and Q3 barely move. That is the key difference: range reacts strongly to extreme values, while the IQR stays stable, which is why it is called a 'robust' measure of spread.

Exercise: Statistics Measures of Spread

What does the range of a dataset measure?