Statistics: Descriptive (Mean, Median, Mode, Std Dev)

Python descriptive statistics summarize a whole dataset in a handful of numbers: where the center sits (mean, median, mode), how scattered the values are (variance, standard deviation, percentiles), and what shape the data has (skewness, kurtosis). This post calculates all of them by hand first, then with scipy and Pandas.

“We don’t have better algorithms. We just have more data.”

Peter Norvig

Last Updated: July 2026 | Tested on: Python 3.14.6, SciPy 1.18, Pandas 2.3.3 | Difficulty: Intermediate | Reading Time: 20 minutes

Think about how you describe a friend you have not met in years. You do not list every single thing they have ever done. You say a few summary things: roughly how old they are, how tall, whether their mood is steady or all over the place. Descriptive statistics do the same job for a dataset. They answer the first honest question you can ask about any pile of numbers: what does this data actually look like?

Here is why the summary has to be more than one number. Picture two teams of five people standing on a weighing scale, one team at a time. Both teams average 75 kg. But the first team is five people who each weigh close to 75 kg, and the second team is four light teenagers and one heavyweight wrestler. Same average, completely different group. The average alone hid the wrestler. That is the trap, and it is exactly why we also measure spread and shape, not just the center.

Prathamesh, a 27-year-old analyst, once presented a slide saying average customer satisfaction was 4.2 out of 5. The stakeholders smiled. Then someone asked what the spread looked like. It turned out most customers scored either 5 (delighted) or 1 (furious), and almost nobody scored a 4. The 4.2 average described a customer who did not exist. Knowing the spread and the shape, not just the average, is what keeps you out of that meeting.

The math for data science tutorial introduced these ideas at a glance. Now we go deeper: the formulas, the by-hand calculation, the Python code that confirms it, and the real decisions you make when summarizing messy data. Every number you compute here feeds straight into the machine learning algorithms in Part 5.

ShapeSkewness:left/righttail asymmetryKurtosis:tail heavinessvs normalDispersionRange:max minus minVariance:avg squareddeviationStd Dev:square rootof varianceIQR:Q3 minus Q1Central TendencyMean:average valueMedian:middle valueMode:most frequent📊 Descriptive StatisticsPython Descriptive Statistics: Central Tendency, Dispersion, and Shape Measures

Tip: click the diagram to open it full screen, then use the zoom and pan controls for a closer look.

The diagram sorts Python descriptive statistics into three families. Central tendency (mean, median, mode) asks “where is the center?”. Dispersion (variance, standard deviation, range, IQR or interquartile range) asks “how spread out is the data?”. Shape (skewness, kurtosis) asks “is the data lopsided or heavy-tailed?”. Each family answers a different question, and together they are the summary you compute at the very start of any data analysis. The code below calculates each measure with NumPy, Pandas, and scipy.

Prerequisites

You should be comfortable with Pandas Series and DataFrames from the Pandas vs Polars comparison, and you should have skimmed the math for data science tutorial. Basic arithmetic and the idea of a square root are all the math you need here. Install the libraries with pip install numpy pandas scipy. Everything below was tested on Python 3.14.6 with NumPy 2.4.6, Pandas 2.3.3, and SciPy 1.18.0.

The Math by Hand, on Five Numbers

Before any library does the work for us, let us do it ourselves on a dataset small enough to fit in your head. Here are five test scores from a study group: 70, 72, 75, 78, 90. Four of them are bunched together, and one (the 90) sits a bit higher. We will compute the mean, the median, the variance, and the standard deviation with nothing but a pencil, then ask Python to check our arithmetic.

Mean (the average). Add all five scores and divide by how many there are. The sum is 70 + 72 + 75 + 78 + 90 = 385, and there are 5 scores, so the mean is 385 / 5 = 77. Notice the mean is 77 even though four of the five scores are below it. That single 90 dragged the average upward, the same way one wrestler dragged the team weight up in the opening example.

Median (the middle value). Sort the scores (they already are) and pick the one in the middle. With five values, the middle is the third one: 75. The median ignores how big the 90 is. It only cares that the 90 sits to the right of the middle. That is exactly why the median shrugs off extreme values while the mean chases them.

Variance and standard deviation (the spread). Variance measures how far the scores sit from the mean, on average, after squaring each gap so that positive and negative gaps do not cancel out. The squared gaps from 77 are: (70-77)² = 49, (72-77)² = 25, (75-77)² = 4, (78-77)² = 1, (90-77)² = 169. They add up to 248. We divide by 4 (that is n minus 1, the sample version we explain later) to get a variance of 248 / 4 = 62. The standard deviation is just the square root of the variance, which brings the number back into the original units (points, not points-squared): the square root of 62 is about 7.87.

📄 by_hand.py: confirm the pencil-and-paper math in Python

import statistics

# Five test scores from one study group
scores = [70, 72, 75, 78, 90]

n = len(scores)
total = sum(scores)
mean = total / n
print(f"Sum: {total}, Count: {n}")
print(f"Mean = {total} / {n} = {mean}")

# Median: middle value of the sorted list
print(f"Median = {statistics.median(scores)}")

# Variance and standard deviation (sample, ddof=1)
squared_devs = [(x - mean) ** 2 for x in scores]
print(f"Squared deviations from mean: {squared_devs}")
print(f"Sum of squared deviations: {sum(squared_devs)}")
sample_var = sum(squared_devs) / (n - 1)
print(f"Sample variance = {sum(squared_devs)} / {n - 1} = {sample_var}")
print(f"Sample std dev = sqrt({sample_var}) = {sample_var ** 0.5:.4f}")

# Confirm with the stdlib statistics module
print(f"statistics.variance: {statistics.variance(scores)}")
print(f"statistics.stdev:    {statistics.stdev(scores):.4f}")

▶ Output

Sum: 385, Count: 5
Mean = 385 / 5 = 77.0
Median = 75
Squared deviations from mean: [49.0, 25.0, 4.0, 1.0, 169.0]
Sum of squared deviations: 248.0
Sample variance = 248.0 / 4 = 62.0
Sample std dev = sqrt(62.0) = 7.8740
statistics.variance: 62
statistics.stdev:    7.8740

What happened here: the numbers match our pencil work line for line. The mean is 77.0, the median is 75, the squared gaps add to 248, the sample variance is 62, and the standard deviation is 7.8740. We used Python’s built-in statistics module here (it ships with every Python install, no extra packages) just to prove the formulas are not magic. For real datasets with thousands of rows, you would never type this out. You reach for NumPy and Pandas, which is exactly what we do for the rest of the post. But now you know what those one-line method calls are actually computing.

Central Tendency: Where Is the Center?

Central tendency is your one-number answer to “what is typical here?”. You have three tools for it. The mean is the everyday average. The median is the middle value once the data is sorted. The mode is the value that shows up most often. They usually agree on friendly data and disagree loudly on messy data, and that disagreement is itself useful information. Watch what happens to a list of salaries the moment a CEO walks into the room.

📄 central_tendency.py: mean, median, and mode with real decisions

import numpy as np
import pandas as pd
from scipy import stats

# Employee salaries at a startup
salaries = pd.Series([
    45000, 48000, 52000, 55000, 58000, 60000,
    62000, 65000, 68000, 72000, 250000  # CEO
])

print(f"Mean:   {salaries.mean():>12,.0f}")
print(f"Median: {salaries.median():>12,.0f}")
print(f"Mode:   {salaries.mode().values}")

# Trimmed mean: drop the most extreme values, then average the rest
trimmed = stats.trim_mean(salaries, proportiontocut=0.1)
print(f"Trimmed mean (10%): {trimmed:>8,.0f}")

print(f"\n--- The story ---")
print(f"Mean ({salaries.mean():,.0f}) is pulled up by the CEO's 250K")
print(f"Median ({salaries.median():,.0f}) represents the typical employee")
print(f"Trimmed mean ({trimmed:,.0f}) is a compromise")

# When they agree vs disagree
symmetric = pd.Series(np.random.default_rng(42).normal(100, 10, 1000))
print(f"\nSymmetric data: mean={symmetric.mean():.1f}, median={symmetric.median():.1f}")
print("They agree! Data is roughly symmetric.")

▶ Output

Mean:         75,909
Median:       60,000
Mode:   [ 45000  48000  52000  55000  58000  60000  62000  65000  68000  72000
 250000]
Trimmed mean (10%):   60,000

--- The story ---
Mean (75,909) is pulled up by the CEO's 250K
Median (60,000) represents the typical employee
Trimmed mean (60,000) is a compromise

Symmetric data: mean=99.7, median=100.1
They agree! Data is roughly symmetric.

What happened here: the mean salary is 75,909, but only one person out of eleven actually earns near that figure (and they are well below it). The median, 60,000, is the salary of a genuinely typical employee. That gap of almost 16,000 between mean and median is the CEO’s 250K leaking into the average. The trimmed mean lops off the top and bottom 10% before averaging, so it lands on 60,000 too, agreeing with the median.

The mode printed all eleven salaries because every value appears exactly once, so technically they are all “most frequent”. Mode is great for repeated categories (shirt sizes, star ratings) and useless for continuous numbers like these. The takeaway: when mean and median disagree this much, trust the median and reach for the mean only when your data is roughly symmetric, which the second dataset confirms (mean 99.7, median 100.1, near enough to call a tie).

Spread: How Scattered Is the Data?

The center tells you where the data sits. Spread tells you how tightly it huddles around that center. Two classes can both average 85 on a test, yet one is full of steady B-students and the other is a mix of strugglers and prodigies. The averages hide that. Spread does not. Think of two darts players who both average the bullseye: one keeps landing near the center, the other scatters darts all over the board and only averages the bullseye by luck. Variance, standard deviation, range, and IQR are four ways to put a number on that scatter.

📄 spread_measures.py: variance, standard deviation, range, and IQR

import numpy as np
import pandas as pd

# Two classes with the same average but different spreads
class_a = pd.Series([78, 82, 85, 88, 92])  # Consistent
class_b = pd.Series([55, 70, 85, 95, 120])  # Wild variation

for name, data in [("Class A (consistent)", class_a), ("Class B (varied)", class_b)]:
    print(f"{name}:")
    print(f"  Mean:     {data.mean():.1f}")
    print(f"  Variance: {data.var():.1f}")
    print(f"  Std Dev:  {data.std():.1f}")
    print(f"  Range:    {data.max() - data.min()}")
    print(f"  IQR:      {data.quantile(0.75) - data.quantile(0.25):.1f}")
    print()

# Percentiles: the backbone of box plots
exam_scores = pd.Series(np.random.default_rng(42).normal(75, 12, 200).astype(int))
print(f"Percentiles for exam scores:")
for p in [10, 25, 50, 75, 90]:
    print(f"  {p}th percentile: {exam_scores.quantile(p/100):.0f}")

# Coefficient of variation (CV): spread relative to the size of the mean
print(f"\nCV (Class A): {class_a.std() / class_a.mean() * 100:.1f}%")
print(f"CV (Class B): {class_b.std() / class_b.mean() * 100:.1f}%")
print("Higher CV = more relative variability")

▶ Output

Class A (consistent):
  Mean:     85.0
  Variance: 29.0
  Std Dev:  5.4
  Range:    14
  IQR:      6.0

Class B (varied):
  Mean:     85.0
  Variance: 612.5
  Std Dev:  24.7
  Range:    65
  IQR:      25.0

Percentiles for exam scores:
  10th percentile: 60
  25th percentile: 67
  50th percentile: 74
  75th percentile: 81
  90th percentile: 87

CV (Class A): 6.3%
CV (Class B): 29.1%
Higher CV = more relative variability

What happened here: both classes average exactly 85.0, yet their spreads are worlds apart. Class A has a variance of 29.0 and a standard deviation of 5.4, so a typical score sits about 5 points from the mean. Class B has a variance of 612.5 and a standard deviation of 24.7, almost five times wider. The standard deviation is the friendlier of the two because it is back in the original units (points), while variance is in points-squared.

The range (max minus min) is the crudest spread measure: one freak score blows it up. The IQR, the gap between the 25th and 75th percentiles, ignores the extremes entirely, which is why Class B’s IQR of 25 is a more honest “everyday spread” than its range of 65. Finally the coefficient of variation rescales the spread against the mean so you can compare datasets measured on different scales: 6.3% versus 29.1% says Class B is far more variable in relative terms.

One important Pandas note: .var() and .std() use the sample formula (dividing by n minus 1) by default, which is why these numbers are slightly larger than the textbook population values. More on that in the Common Mistakes section.

Shape: Skewness and Kurtosis

Center and spread still leave one question open: is the data lopsided? Think of a seesaw in a playground: if riders sit evenly on both sides it balances, but if a few heavy riders pile onto one end it tips hard that way. Skewness measures that lean. A skewness near zero means the data is roughly symmetric, like a normal bell curve. Positive skew means a long tail stretching to the right (think incomes: most people earn modest amounts, a few earn enormous ones).

Negative skew means a long tail to the left (think exam scores capped at 100, where most cluster high and a few stragglers drag the tail down). Kurtosis measures the tails: high kurtosis means heavy tails with more extreme outliers than a normal curve, low kurtosis means thin tails. Here is the quick rule of thumb you will actually use: if the mean sits noticeably above the median, the data is right-skewed, and the median is the safer summary.

📄 shape_measures.py: is the data symmetric or heavy-tailed?

import numpy as np
import pandas as pd

rng = np.random.default_rng(42)

# Symmetric (normal)
normal = pd.Series(rng.normal(100, 15, 10000))

# Right-skewed (income-like)
right_skewed = pd.Series(rng.exponential(50000, 10000))

# Left-skewed (exam scores with ceiling)
left_skewed = pd.Series(100 - rng.exponential(15, 10000))

for name, data in [("Normal", normal), ("Right-skewed", right_skewed), ("Left-skewed", left_skewed)]:
    print(f"{name}:")
    print(f"  Skewness: {data.skew():.3f}")
    print(f"  Kurtosis: {data.kurtosis():.3f}")
    print(f"  Mean vs Median: {data.mean():.1f} vs {data.median():.1f}")
    print()

print("--- Interpretation ---")
print("Skewness: 0 = symmetric, > 0 = right tail, < 0 = left tail")
print("Kurtosis: 0 = normal, > 0 = heavy tails, < 0 = light tails")
print("If mean > median -> right-skewed (use median)")
print("If mean < median -> left-skewed (use median)")

▶ Output

Normal:
  Skewness: -0.003
  Kurtosis: 0.053
  Mean vs Median: 99.8 vs 99.8

Right-skewed:
  Skewness: 2.043
  Kurtosis: 6.295
  Mean vs Median: 50238.0 vs 34859.8

Left-skewed:
  Skewness: -2.099
  Kurtosis: 7.017
  Mean vs Median: 84.9 vs 89.7

--- Interpretation ---
Skewness: 0 = symmetric, > 0 = right tail, < 0 = left tail
Kurtosis: 0 = normal, > 0 = heavy tails, < 0 = light tails
If mean > median -> right-skewed (use median)
If mean < median -> left-skewed (use median)

What happened here: the normal dataset has skewness near zero (-0.003) and kurtosis near zero (0.053), and its mean and median are basically identical at 99.8. That is the signature of symmetric data. The right-skewed income data has a strong positive skewness of 2.043, and notice the mean (50,238) sits well above the median (34,860). That gap is the long right tail of high earners pulling the average up, the exact effect that made the CEO salary so misleading earlier.

The left-skewed data mirrors it: negative skewness of -2.099, with the mean (84.9) dragged below the median (89.7) by a few low stragglers. Both skewed datasets also show kurtosis above 6, meaning fatter tails and more outliers than a normal curve. Your own numbers will land very close to these because the random generator is seeded with 42. Drop the seed and the digits past the first decimal will wander, but the story stays the same.

The Power of df.describe()

Doing each measure one at a time is great for learning, but in real work you want all of them at once. Pandas gives you that in a single method: df.describe(). It is the data scientist’s equivalent of glancing at a dashboard, you run it the moment a new dataset lands so you know what you are dealing with before writing another line.

📄 describe_plus.py: a one-line statistical overview with Pandas

import pandas as pd
import numpy as np

rng = np.random.default_rng(42)
df = pd.DataFrame({
    "age": rng.integers(22, 34, 100),
    "salary": rng.normal(75000, 12000, 100).astype(int),
    "experience": rng.integers(1, 10, 100),
    "department": rng.choice(["Eng", "DS", "Mkt", "Sales"], 100)
})

# Numeric summary
print(f"Numeric describe:\n{df.describe().round(0)}\n")

# Categorical summary (text columns are the 'object' dtype in Pandas 2.3.3)
print(f"Categorical describe:\n{df.describe(include='object')}\n")

# Custom percentiles
print(f"Custom percentiles:\n{df.describe(percentiles=[.1, .25, .5, .75, .9]).round(0)}")

▶ Output

Numeric describe:
         age    salary  experience
count  100.0     100.0       100.0
mean    28.0   73484.0         5.0
std      3.0   10643.0         3.0
min     22.0   49415.0         1.0
25%     25.0   66603.0         3.0
50%     28.0   72434.0         4.0
75%     31.0   80553.0         7.0
max     33.0  109966.0         9.0

Categorical describe:
       department
count         100
unique          4
top         Sales
freq           28

Custom percentiles:
         age    salary  experience
count  100.0     100.0       100.0
mean    28.0   73484.0         5.0
std      3.0   10643.0         3.0
min     22.0   49415.0         1.0
10%     23.0   59635.0         1.0
25%     25.0   66603.0         3.0
50%     28.0   72434.0         4.0
75%     31.0   80553.0         7.0
90%     32.0   85060.0         9.0
max     33.0  109966.0         9.0

Common Mistakes

Mistake 1: Trusting the mean on skewed data

“The average income in our city is 90,000” sounds reassuring until you realize a handful of millionaires dragged that mean up while most people earn far less. Income, house prices, and web page load times are almost always right-skewed, so the mean overstates the typical value. Check the skewness (or just compare mean against median) before you pick your summary number. When they disagree, the median is usually the honest one.

📄 skew_check.py: when the mean lies, the median tells the truth

import pandas as pd

# Yearly incomes (thousands) for a small neighbourhood
incomes = pd.Series([32, 38, 41, 45, 49, 52, 58, 61, 70, 950])

print(f"Mean income:   {incomes.mean():.1f}K")
print(f"Median income: {incomes.median():.1f}K")
print(f"Skewness:      {incomes.skew():.2f}")

if incomes.mean() > incomes.median():
    print("Right-skewed: report the MEDIAN, not the mean")

▶ Output

Mean income:   139.6K
Median income: 50.5K
Skewness:      3.15
Right-skewed: report the MEDIAN, not the mean

One income of 950K shoved the mean up to 139.6K, a figure nobody in the list actually earns. The median, 50.5K, describes a real neighbour. Whenever skewness climbs past about 1 in size, treat the mean with suspicion.

Mistake 2: Confusing population and sample standard deviation

This one bites people who switch between NumPy and Pandas. There are two standard deviation formulas. The population version (ddof=0) divides by n and is correct when your data is the entire group. The sample version (ddof=1) divides by n minus 1 and is correct when your data is a sample standing in for a bigger population, which is almost always the real situation. The catch: NumPy defaults to population, Pandas defaults to sample. Same data, two different answers, depending on which library you called.

📄 ddof_trap.py: NumPy and Pandas disagree by default

import numpy as np
import pandas as pd

data = [10, 20, 30]
arr = np.array(data)
series = pd.Series(data)

# NumPy default is population (ddof=0)
print(f"np.std default (ddof=0): {arr.std():.4f}")
# Pandas default is sample (ddof=1)
print(f"pd.Series.std default (ddof=1): {series.std():.4f}")

# Make them agree by being explicit about which formula you want
print(f"np.std(ddof=1): {arr.std(ddof=1):.4f}")
print(f"pd.Series.std(ddof=0): {series.std(ddof=0):.4f}")

▶ Output

np.std default (ddof=0): 8.1650
pd.Series.std default (ddof=1): 10.0000
np.std(ddof=1): 10.0000
pd.Series.std(ddof=0): 8.1650

The same three numbers give 8.16 from NumPy and 10.00 from Pandas, purely because of the default ddof. Neither is wrong, they just answer different questions. The fix is simple: pass ddof explicitly whenever the answer matters, so you and the next reader both know which formula you meant.

Try It Yourself

Time to point your Python descriptive statistics toolkit at a tiny real problem. Here is a dataset of monthly rent prices (in thousands) for ten flats near a tech park: [18, 19, 20, 21, 22, 23, 24, 25, 26, 95]. That last flat is a luxury penthouse. Write a short script that prints the mean, the median, the standard deviation, and the IQR, then decides on its own whether to recommend the mean or the median as the “typical rent”. Your script should compare the mean against the median (or check the skewness) and print its recommendation.

Before you run it, predict which number it will recommend. The penthouse is doing the same thing the CEO salary did earlier, so trust your gut. Then confirm with the code.

Conclusion

You now have the full Python descriptive statistics toolkit: central tendency (mean, median, mode) to find the center, dispersion (variance, standard deviation, range, IQR) to measure the scatter, and shape (skewness, kurtosis) to catch a lopsided or heavy-tailed distribution. You also saw the two traps that catch working analysts: trusting the mean on skewed data, and the ddof mismatch between NumPy and Pandas. Most importantly, df.describe() hands you almost all of this in a single line the moment a fresh dataset lands on your desk.

Next up is probability distributions, where you meet the normal and binomial curves that these summary numbers are quietly assuming. From there the series moves into inferential statistics and then machine learning, where every model leans on the measures you just mastered.

New here, or want the full path from scratch? Start at the Python + AI/ML tutorial series home for the complete roadmap, from Python basics all the way to deployable models.

Frequently Asked Questions

How do I calculate descriptive statistics in Python?

To compute Python descriptive statistics on a Pandas Series or DataFrame, call .mean(), .median(), .std(), .var(), and .quantile() for individual measures, or df.describe() to get count, mean, std, min, the quartiles, and max all at once. For skewness and kurtosis use .skew() and .kurtosis(). NumPy offers np.mean, np.median, and np.std for plain arrays. The stdlib statistics module covers the basics with no extra install.

What is the difference between variance and standard deviation?

Variance is the average of the squared distances from the mean. Standard deviation is the square root of variance. Standard deviation is the more readable of the two because it is back in the original units (dollars, centimetres), while variance is in squared units. You compute variance first, then take its square root to get the standard deviation.

When should I use IQR instead of standard deviation?

Use the IQR when your data is skewed or has outliers. The IQR measures spread using the 25th and 75th percentiles, so a single extreme value cannot blow it up. Standard deviation is built from the mean, so one outlier inflates it. For symmetric, outlier-free data, standard deviation is fine and more familiar.

What does the 68-95-99.7 rule mean?

For normally distributed data, about 68 percent of values fall within 1 standard deviation of the mean, about 95 percent within 2, and about 99.7 percent within 3. That is why a value more than 3 standard deviations from the mean is usually flagged as an outlier: in a normal distribution it shows up less than 0.3 percent of the time.

Why does Pandas use ddof=1 and NumPy use ddof=0 by default?

Pandas assumes your data is a sample of a larger population, so it applies Bessel’s correction and divides by n minus 1 (ddof=1). NumPy assumes you have the whole population and divides by n (ddof=0). For most real analysis ddof=1 is correct, but the safest habit is to pass ddof explicitly so the two libraries always agree.

Interview Questions on Python Descriptive Statistics

Scenario questions, not trivia: this is the form this topic takes in a real interview.

Q: What is the difference between the mean and the median, and when does the gap between them matter?

The mean is the arithmetic average of all values; the median is the middle value once the data is sorted. On symmetric data they nearly coincide, but on skewed data they pull apart. With right-skewed data like incomes or house prices, a few large values drag the mean above the median, so the median is the more honest summary of a typical value.

Q: Your monitoring dashboard shows an average Application Programming Interface (API) response time of 200 ms, but users keep complaining the app feels slow. What do you check first?

Response times are almost always right-skewed, so I stop trusting the mean and look at the median plus the high percentiles: p90, p95, and p99. A handful of very slow requests can inflate the average while most users experience something else entirely. Those tail percentiles expose the real user experience that a single average number hides.

Q: You call df.describe() on a DataFrame and a column you expected is missing from the output. Why, and how do you include it?

By default describe() summarizes only numeric columns, so a column stored as strings, object, or category (for example numbers that were loaded as text) gets skipped. Convert it with pd.to_numeric or astype if it should be numeric, or call df.describe(include='all') to also summarize categorical columns with count, unique, top, and freq.

Q: Why do we divide by n minus 1 for sample variance instead of n?

That is Bessel’s correction. When you estimate a population’s variance from a sample, dividing by n underestimates it, because the sample points sit closer to the sample mean than to the true population mean. Dividing by n minus 1 corrects that bias and gives an unbiased estimate. This is exactly why Pandas defaults to ddof=1 and NumPy to ddof=0.

Q: When is the mode actually the right measure of central tendency?

The mode, the most frequent value, is the right choice for categorical or discrete repeated data: shirt sizes, star ratings, the most common product ordered. For continuous numeric data where nearly every value is unique it is almost useless, because everything ties as “most frequent”. For those, reach for the mean or median instead.

Q: A colleague named Aditi reports “average customer rating is 4.2 out of 5” and wants to ship. What one follow-up statistic do you ask for, and why?

I would ask for the distribution, or at minimum the standard deviation and the mode. A 4.2 average can hide a polarized split where most people rate 5 or 1 and almost nobody rates 4, which means 4.2 describes a customer who does not exist. The spread and shape tell you whether the average reflects a real, typical customer or is just a midpoint between two unhappy camps.

Reference: the complete, always-current details live in the official Python documentation.

Previous: Python: Pandas vs Polars vs Dask, DataFrames Compared

Next: Statistics: Probability Distributions, Normal and Binomial

Series Home: Python + AI/ML Tutorial Series

RahulAuthor posts

Avatar for Rahul

Rahul is a passionate IT professional who loves to sharing his knowledge with others and inspiring them to expand their technical knowledge. Rahul's current objective is to write informative and easy-to-understand articles to help people avoid day-to-day technical issues altogether. Follow Rahul's blog to stay informed on the latest trends in IT and gain insights into how to tackle complex technical issues. Whether you're a beginner or an expert in the field, Rahul's articles are sure to leave you feeling inspired and informed.

No comment

Leave a Reply

Your email address will not be published. Required fields are marked *