AI Computer Institute
Expert-curated CS & AI curriculum aligned to CBSE standards. A bharath.ai initiative. About Us

Statistics with Python: Understanding Data

📚 Databases & Data Science⏱️ 23 min read🎓 Grade 8
✍️ AI Computer Institute Editorial Team Updated: August 2026 CBSE-aligned · Peer-reviewed · 23 min read
Content curated by subject matter experts with IIT/NIT backgrounds. All chapters are fact-checked against official CBSE/NCERT syllabi.

Suppose your school's cricket team just finished a T20 season, and your friend claims their best batter is "solid, scores around 40 runs every innings." You pull up the actual scorecard from the last 10 innings: 23, 45, 12, 67, 34, 8, 90, 15, 52, 34. Is your friend right? Add these up and divide by 10, and you do get 38 — close to 40. But look again at the raw list: an 8 sits right next to a 90. Is a batter who scores 8 one match and 90 the next really "solid"? A single number — the average — cannot answer that question. You need more than one statistic, and you need a way to compute those statistics quickly and correctly even when the list has 10 numbers today and 10,000 tomorrow. That is exactly what this chapter teaches: how to describe a collection of numbers precisely using Python, and how to avoid the traps that make a single statistic lie to you.

What Do We Mean by "Data"?

In everyday speech, "data" just means information. In statistics and programming, we narrow that down: data is a collection of individual measurements or observations, usually stored together so we can study them as a group. The 10 cricket scores above are data. So is a list of 30 students' marks in a unit test, the number of WhatsApp messages you send each day for a week, or the temperature in Delhi recorded every hour. In Python, the natural way to hold this kind of collection is a list — an ordered sequence of values inside square brackets, like [23, 45, 12, 67, 34, 8, 90, 15, 52, 34]. Everything in this chapter builds on that one idea: once your data is a Python list, you can write short programs to summarize it in ways that would take far too long by hand.

The Mean: Finding the Balance Point of Data

The mean (what most people casually call the "average") answers the question: if every value in the dataset were replaced by the same number, what would that number have to be so the total stays the same? You already know the formula from Maths class: add up all the values, then divide by how many values there are.

Let's compute it by hand first for our cricket scores, because seeing the arithmetic before the code makes the code meaningful rather than magical. The 10 scores are 23, 45, 12, 67, 34, 8, 90, 15, 52, 34. Adding them one at a time: 23 + 45 = 68, + 12 = 80, + 67 = 147, + 34 = 181, + 8 = 189, + 90 = 279, + 15 = 294, + 52 = 346, + 34 = 380. The total is 380 runs across 10 innings, so the mean is 380 ÷ 10 = 38.

Now let's write that same arithmetic as a Python program, using a loop, before reaching for any shortcut function. This matters: if you only ever call a ready-made function, you never learn what it's actually doing underneath.

runs = [23, 45, 12, 67, 34, 8, 90, 15, 52, 34]

total = 0
for score in runs:
    total = total + score

mean = total / len(runs)
print("Total runs:", total)
print("Number of innings:", len(runs))
print("Mean:", mean)
Output:
Total runs: 380
Number of innings: 10
Mean: 38.0

Trace it: total starts at 0. The loop visits each score in order and adds it to total, so after all 10 iterations total holds 380 — matching our hand calculation exactly. len(runs) counts the items in the list (10), and Python's / operator always performs true division, giving a decimal result even when it divides evenly — hence 38.0, not 38.

Once you understand the loop, Python's built-in statistics module gives you the same answer in one line, and it's worth knowing it exists:

import statistics

runs = [23, 45, 12, 67, 34, 8, 90, 15, 52, 34]
print(statistics.mean(runs))
Output:
38

Notice this prints 38, not 38.0. The statistics.mean() function computes the result using exact fractions internally and only converts to a decimal when the division doesn't come out to a whole number — so when the mean is exactly whole, it reports it as a plain integer. This is a real, useful quirk to know about the library, not something you need to memorize, but it explains why two "correct" pieces of code can print slightly different-looking (but numerically equal) results.

Common Misconception: "Average" Is Not Always "Typical"

Here is a mistake that trips up even adults reading news reports: assuming the mean represents a "typical" member of the group. It often does not, especially when one value is far from the rest — an outlier.

Suppose nine students in a class report their weekly pocket money in rupees: 80, 100, 60, 90, 120, 70, 110, 95, and one student who received a special ₹5000 birthday gift that week. The full list is [80, 100, 60, 90, 120, 70, 110, 5000, 95].

pocket_money = [80, 100, 60, 90, 120, 70, 110, 5000, 95]

total = 0
for amount in pocket_money:
    total = total + amount

mean = total / len(pocket_money)
print("Mean pocket money: ₹", round(mean, 2))
Output:
Mean pocket money: ₹ 636.11

Trace the addition: 80 + 100 = 180, + 60 = 240, + 90 = 330, + 120 = 450, + 70 = 520, + 110 = 630, + 5000 = 5630, + 95 = 5725. Dividing 5725 by 9 gives approximately 636.11. But look at the actual data: eight of the nine students have between ₹60 and ₹120. Not one of them has anywhere near ₹636. The mean has been dragged far away from where most of the data actually sits, purely because of a single unusual value. If a newspaper reported "average student pocket money: ₹636," it would technically be correct and completely misleading at the same time.

This is precisely why statisticians almost always report the median alongside the mean whenever a dataset might contain outliers — incomes, house prices, and app download counts are classic real-world examples where a few extreme values exist. We'll compute the median for this same dataset in the next section and see how differently it behaves.

Weekly Pocket Money of 9 Students (Rs.) 0 50 100 150 Median = Rs.95 Rs.5000 (birthday gift) Mean is approx Rs.636 - dragged right by the outlier axis break - the Rs.5000 point is not drawn to scale

The Median: The True Middle Value

The median is the value that sits exactly in the middle once the data is arranged in order, from smallest to largest. Half the values lie at or below it, and half lie at or above it. Unlike the mean, the median doesn't care how far away an extreme value is — only about its rank, its position in the sorted order — which is exactly why it resisted the ₹5000 outlier above.

Common misconception: skipping the sort. A very frequent student mistake is picking the "middle" element of the list as it was originally typed, without sorting it first. The position in an unsorted list means nothing — you must sort before you can talk about a "middle" value at all.

Let's find the median of our pocket-money data, [80, 100, 60, 90, 120, 70, 110, 5000, 95], which has 9 values (an odd count):

pocket_money = [80, 100, 60, 90, 120, 70, 110, 5000, 95]

sorted_money = sorted(pocket_money)
n = len(sorted_money)
mid = n // 2

median = sorted_money[mid]
print("Sorted:", sorted_money)
print("Median: ₹", median)
Output:
Sorted: [60, 70, 80, 90, 95, 100, 110, 120, 5000]
Median: ₹ 95

With 9 values, the middle position (using 0-based indexing, where the first item is index 0) is index 9 // 2 = 4, and the fifth item in the sorted list is 95. Compare this to the mean of ₹636.11 we found earlier — the median of ₹95 sits comfortably among the other eight students' amounts, giving a far more honest picture of what a "typical" student in this class actually has.

When there is an even number of values, there is no single middle item — you average the two middle values instead. Let's redo this for our 10 cricket scores:

runs = [23, 45, 12, 67, 34, 8, 90, 15, 52, 34]

sorted_runs = sorted(runs)
n = len(sorted_runs)
mid = n // 2

if n % 2 == 0:
    median = (sorted_runs[mid - 1] + sorted_runs[mid]) / 2
else:
    median = sorted_runs[mid]

print("Sorted runs:", sorted_runs)
print("Median:", median)
Output:
Sorted runs: [8, 12, 15, 23, 34, 34, 45, 52, 67, 90]
Median: 34.0

With n = 10, mid = 5. Since 10 is even, we average the item at index 4 and the item at index 5 of the sorted list — both happen to be 34 here — giving a median of 34.0. Compare this to the mean of 38: the mean is pulled slightly upward by the single 90, while the median stays anchored among the more common scores in the 20s and 30s.

The Mode: What Value Appears Most Often

The mode is simply the value that occurs most frequently in the dataset. It's the only one of these three measures that makes sense for non-numeric data too (the "mode" of favourite ice-cream flavours in a class survey, for instance), but it's just as useful for numbers, especially when a value repeats a lot.

Consider 10 students' scores out of 10 on a quick oral quiz: [7, 8, 9, 8, 6, 8, 10, 9, 8, 5]. Let's find the mode by building a frequency count from scratch, using a Python dictionary — a structure that stores pairs of (key, value), here mapping each score to how many times it appeared:

marks = [7, 8, 9, 8, 6, 8, 10, 9, 8, 5]

counts = {}
for score in marks:
    if score in counts:
        counts[score] += 1
    else:
        counts[score] = 1

highest_count = 0
mode_value = None
for score, freq in counts.items():
    if freq > highest_count:
        highest_count = freq
        mode_value = score

print("Frequency of each score:", counts)
print("Mode:", mode_value, "(appeared", highest_count, "times)")
Output:
Frequency of each score: {7: 1, 8: 4, 9: 2, 6: 1, 10: 1, 5: 1}
Mode: 8 (appeared 4 times)

Trace it: as the loop scans marks left to right, every time it meets a score it hasn't seen before it adds a new entry with count 1; every time it meets a repeat, it increases that entry's count by 1. The score 8 appears at four different positions in the list, so by the end counts[8] equals 4 — more than any other score — making 8 the mode.

Python's statistics module can do this in one line too: statistics.mode(marks) also returns 8. But here's a genuinely important detail that most introductory material skips: what if there is no single most-common value? Since Python 3.8, statistics.mode() no longer raises an error in that case — it silently returns whichever value it happened to see first, even if every value in the dataset is equally frequent. That can be misleading if you don't know to check for it. A safer tool is statistics.multimode(), which returns a list of every value tied for most frequent. If that list turns out to be as long as the dataset itself, it means every value appeared exactly once — there is no meaningful mode at all. We'll use this check in the consolidated program later in this chapter.

The Range: How Spread Out Is the Data?

Mean, median, and mode all try to describe where the "centre" of the data is. The range answers a different question entirely: how spread out is the data? It's the simplest spread measure — the highest value minus the lowest value.

pocket_money = [80, 100, 60, 90, 120, 70, 110, 5000, 95]

highest = pocket_money[0]
lowest = pocket_money[0]

for amount in pocket_money:
    if amount > highest:
        highest = amount
    if amount < lowest:
        lowest = amount

data_range = highest - lowest
print("Highest:", highest, "Lowest:", lowest)
print("Range: ₹", data_range)
Output:
Highest: 5000 Lowest: 60
Range: ₹ 4940

Trace it: both highest and lowest start at the first list value, 80. As the loop scans each amount, it updates highest whenever it finds something bigger and lowest whenever it finds something smaller. By the end, highest is 5000 and lowest is 60, giving a range of ₹4940. Notice that the range, just like the mean, is extremely sensitive to outliers — a single extreme value inflates it hugely, even though eight of the nine students only differ from each other by ₹60 at most (from ₹60 to ₹120). Python gives you a shortcut here too: max(pocket_money) - min(pocket_money) computes the same 4940 without writing the loop yourself. Interestingly, the statistics module has no dedicated range() function — Python's built-in max() and min() are considered sufficient, so that's the idiomatic way to compute it.

Seeing the Shape of Data: Frequency Tables and Histograms

Individual statistics summarize data with a single number, but sometimes you want to see the whole shape of a dataset at once — how many values fall in each range. This is what a frequency table and its visual form, a histogram, are for.

Take marks out of 100 for a class of 30 students on a unit test:

marks = [45, 78, 62, 91, 55, 38, 72, 84, 67, 59,
         42, 88, 73, 51, 96, 64, 29, 77, 60, 83,
         48, 71, 90, 56, 35, 79, 63, 87, 44, 58]

bins = {"0-20": 0, "21-40": 0, "41-60": 0, "61-80": 0, "81-100": 0}

for m in marks:
    if m <= 20:
        bins["0-20"] += 1
    elif m <= 40:
        bins["21-40"] += 1
    elif m <= 60:
        bins["41-60"] += 1
    elif m <= 80:
        bins["61-80"] += 1
    else:
        bins["81-100"] += 1

for range_label, count in bins.items():
    print(range_label, ":", count)
Output:
0-20 : 0
21-40 : 3
41-60 : 10
61-80 : 10
81-100 : 7

Each mark travels through the chain of if/elif conditions until it lands in exactly one bucket. For example, 45 fails the m <= 20 and m <= 40 tests but passes m <= 60, so it's counted in the "41-60" bucket. Working through all 30 marks this way, no student scored 20 or below, three scored between 21 and 40, ten each landed in the 41-60 and 61-80 ranges, and seven scored above 80. This kind of table tells you something a single mean can't: the class is bunched in the middle-to-upper range, with nobody struggling badly (the "0-20" bucket is empty) but also relatively few standout scores above 80.

A histogram is exactly this frequency table drawn as bars, one bar per range, with height equal to the count:

Class Test Marks - Frequency Distribution (n = 30) 0 2 4 6 8 10 0 0-20 3 21-40 10 41-60 10 61-80 7 81-100 Marks range

One Program, Four Statistics

Let's now put everything together on the same 30-mark dataset, using the statistics module for speed, and the outlier-safe mode check we learned about earlier:

import statistics

marks = [45, 78, 62, 91, 55, 38, 72, 84, 67, 59,
         42, 88, 73, 51, 96, 64, 29, 77, 60, 83,
         48, 71, 90, 56, 35, 79, 63, 87, 44, 58]

print("Mean:", round(statistics.mean(marks), 2))
print("Median:", statistics.median(marks))
print("Range:", max(marks) - min(marks))

modes = statistics.multimode(marks)
if len(modes) == len(marks):
    print("Mode: none (every mark is unique)")
else:
    print("Mode:", modes)
Output:
Mean: 64.83
Median: 63.5
Range: 67
Mode: none (every mark is unique)

Every one of these 30 marks happens to be different from every other, so no value repeats — the mode genuinely doesn't exist for this dataset, and our len(modes) == len(marks) check correctly detects that instead of blindly printing a meaningless "first value seen." The median (63.5, the average of the 15th and 16th values once sorted — 63 and 64) sits close to the mean (64.83), which tells you this dataset, unlike our pocket-money example, has no major outliers dragging it around. The range of 67 (from a lowest mark of 29 to a highest of 96) confirms a fairly wide but not extreme spread — consistent with the bell-ish shape we saw in the histogram.

Why Python Instead of Just a Calculator?

For 9 or 10 numbers, you could compute all of this by hand, and in Maths class you often will. The reason to learn it in Python is scale and reuse. During Tatkal ticket booking on IRCTC, or during a UPI payment surge, systems log enormous volumes of numeric events every second — no one is summing those by hand. The exact same four-line pattern you wrote above — a loop for the mean, a sort for the median, a dictionary for the mode, max()/min() for the range — works identically whether your list has 10 items or 10 million. That is the real power you're building here: not just knowing the formulas, but knowing how to make a machine apply them correctly, every time, at any scale.

Test Yourself

  • A week's rainfall in your city (in mm): [0, 12, 45, 0, 8, 60, 3]. Compute the mean, median, mode, and range by hand, then check your answers with a Python program that uses loops (not the statistics module).
  • Six friends' app screen-time in minutes today: [45, 50, 48, 300, 52, 47]. Which single value is an outlier? Compute both the mean and the median — which one better represents a "typical" friend's screen time, and why?
  • A dataset has 8 values and its median is reported as 47.5. What must be true about the two middle values once the data is sorted? Give one possible pair of middle values that would produce this median.
  • Write a Python program that takes any list of exam marks and prints "Mode: none" if statistics.multimode() returns as many values as the original list — reuse the pattern from the consolidated program above, but test it on your own class's real marks if you have them.

Summary

Data is simply a collection of values — in Python, usually a list — and statistics gives you precise tools to summarize it instead of eyeballing it. The mean is the balance point of the data (total divided by count), computed with a simple accumulating loop before you ever reach for statistics.mean(). The median is the true middle value after sorting — never before — and unlike the mean, it resists being pulled around by outliers, which is why the two can tell very different stories about the same dataset, as our ₹5000 pocket-money example showed. The mode is the most frequent value, found by counting occurrences in a dictionary; not every dataset has one, and modern Python's statistics.mode() will not warn you if it doesn't, so check with multimode() instead. The range (max minus min) measures spread rather than centre, and like the mean, it is highly sensitive to a single extreme value. Frequency tables and histograms let you see the full shape of a dataset — not just one number describing it — by counting how many values fall into each range. Together, these five ideas are the foundation of every larger data-analysis technique you'll meet later, from spreadsheets to machine learning: describe the centre, describe the spread, and never trust a single number without asking what it might be hiding.

Practice Exercises

Now it is time to practice! Complete these challenges to solidify your understanding:

  • Exercise 1: Write a short program that demonstrates the core concept from this chapter. Test it with at least 3 different inputs.
  • Exercise 2: Find a real-world example where statistics with python: understanding data is used in an Indian company (like TCS, Infosys, Flipkart, or ISRO). Write a paragraph explaining the connection.
  • Exercise 3: Create a mind-map connecting statistics with python: understanding data to at least 3 other topics you have studied.
← Data Visualization with MatplotlibWorking with CSV and JSON Data →

Found this useful? Share it!

📱 WhatsApp 🐦 Twitter 💼 LinkedIn