BlogData Analytics SeriesChapter 13
SERIES · CHAPTER 13Intermediate

Descriptive Statistics for Data Analysts

Mean, median, mode, variance, standard deviation, IQR, skewness, percentiles — every descriptive statistic explained with the formula, when to use it, when not to, and Indian business examples with Python and SQL code.

DATA ANALYTICS SERIES:← Ch 12: Data CleaningCh 13: Statistics ←Ch 14: Correlation & Regression →
df.describe() — WHAT EACH ROW MEANS
           amount_inr  delivery_days     rating
count       87340.0        79240.0      74940.0   ← non-null count (note: rating has nulls)
mean         1148.4            3.8          3.9   ← arithmetic mean
std          1840.2            1.9          0.8   ← standard deviation
min            49.0            1.0          1.0   ← minimum value
25%           450.0            2.0          3.5   ← Q1 (25th percentile)
50%           812.0            3.0          4.0   ← MEDIAN (50th percentile)
75%          1800.0            5.0          4.5   ← Q3 (75th percentile)
max         89999.0           42.0          5.0   ← maximum value

KEY READS:
  amount_inr: mean (1148) >> median (812) → right-skewed → report median
  delivery_days: max = 42 but 75% under 5 → extreme outlier deliveries exist
  rating: count = 74940 vs 87340 rows → 12400 null ratings (customers who did not rate)

Measures of Central Tendency

Where is the centre of the data?

Mean (Average)

Σx / n

Add all values and divide by the count.

✓ USE WHEN

Symmetric distributions with no extreme outliers. Daily temperature, manufacturing process measurements, test scores.

✗ AVOID WHEN

Income data, salary, order values, property prices — all right-skewed with outliers that pull the mean up artificially.

INDIAN EXAMPLE

Mean order value in August: ₹1,148. Calculated as total revenue ÷ total orders.

Python
df['amount_inr'].mean()
# → 1148.4

# Mean by group
df.groupby('category')['amount_inr'].mean().sort_values(ascending=False)
SQL
SELECT AVG(amount_inr) AS mean_order_value FROM orders;
SELECT category, AVG(amount_inr) AS mean_aov
FROM orders GROUP BY category ORDER BY mean_aov DESC;
ANALYST INSIGHT: The mean order value is ₹1,148 but the median is ₹812. The ₹336 gap reveals right skew — a small number of high-value electronics orders pull the mean well above the typical order.

Median (Middle Value)

Middle value when data is sorted. For even n: average of two middle values.

Sort all values; the one in the middle is the median. Half the values are above it, half below.

✓ USE WHEN

Skewed data, income, order values, salaries, property prices. Any time outliers should not dominate the "typical" measure.

✗ AVOID WHEN

When you actually need to track total revenue impact — use mean × count for revenue projections.

INDIAN EXAMPLE

Median order value: ₹812. Half of all orders are below ₹812, half above. This is more representative of a typical order than the mean of ₹1,148.

Python
df['amount_inr'].median()
# → 812.0

# Median by group
df.groupby('city')['amount_inr'].median().sort_values(ascending=False)

# Compare mean vs median to assess skew
print(f"Mean:   ₹{df['amount_inr'].mean():,.0f}")
print(f"Median: ₹{df['amount_inr'].median():,.0f}")
print(f"Skew:   {df['amount_inr'].skew():.2f}")
SQL
-- MySQL (no built-in MEDIAN function)
SELECT AVG(amount_inr) AS median_value
FROM (
    SELECT amount_inr,
        ROW_NUMBER() OVER (ORDER BY amount_inr) AS rn,
        COUNT(*) OVER () AS total_count
    FROM orders
) t
WHERE rn IN (FLOOR((total_count + 1) / 2), CEIL((total_count + 1) / 2));

-- PostgreSQL (simpler)
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY amount_inr) AS median
FROM orders;
ANALYST INSIGHT: When mean > median, the data is right-skewed. When mean < median, it is left-skewed. Equal mean and median suggest symmetry. Use this as a quick skewness check before any analysis.

Mode (Most Frequent Value)

The value that appears most often.

The most common value in a dataset.

✓ USE WHEN

Categorical data (what is the most common city, category, payment method). For numeric data — rarely used in business analysis.

✗ AVOID WHEN

Continuous numeric data — every value may be unique, making the mode meaningless.

INDIAN EXAMPLE

Mode of payment_method: "UPI" (54% of orders). Mode of delivery_days: 3 (most orders arrive on day 3).

Python
# Mode of a categorical column
df['payment_method'].mode()[0]
# → 'UPI'

df['city'].value_counts().index[0]   # top city
df['category'].value_counts()        # full frequency table

# Mode of a numeric column
df['delivery_days'].mode()[0]   # most common delivery time
SQL
SELECT payment_method, COUNT(*) AS frequency
FROM orders
GROUP BY payment_method
ORDER BY frequency DESC
LIMIT 1;  -- mode = most frequent
ANALYST INSIGHT: UPI as the modal payment method in Indian e-commerce is a real-world pattern — digital payment adoption accelerated sharply after 2016 and UPI now dominates across all income segments.

Measures of Spread (Variability)

How spread out is the data?

Range

Maximum − Minimum

The distance from the lowest to the highest value.

✓ USE WHEN

Quick initial understanding of data extent. Useful for catching data errors (negative values, impossibly large values).

✗ AVOID WHEN

As a primary spread measure — one outlier completely defines the range. Use IQR or std instead.

INDIAN EXAMPLE

Order value range: ₹49 (cheapest FMCG item) to ₹89,999 (premium laptop). Range = ₹89,950.

Python
print(f"Min: ₹{df['amount_inr'].min():,.0f}")
print(f"Max: ₹{df['amount_inr'].max():,.0f}")
print(f"Range: ₹{df['amount_inr'].max() - df['amount_inr'].min():,.0f}")
SQL
SELECT MIN(amount_inr) AS min_val, MAX(amount_inr) AS max_val,
    MAX(amount_inr) - MIN(amount_inr) AS range_val
FROM orders;
ANALYST INSIGHT: A wide range does not mean high variability in the central data — it just means at least one very high and one very low value exist. Always check range alongside IQR.

Variance & Standard Deviation

Variance = Σ(x − mean)² / n | Std Dev = √Variance

Average squared distance from the mean. Standard deviation brings it back to the original units (₹, days, kg) by taking the square root.

✓ USE WHEN

Measuring consistency — lower std = more consistent. Required for Z-scores, confidence intervals, t-tests, and machine learning normalisation.

✗ AVOID WHEN

Highly skewed data — std is sensitive to outliers. Use IQR for skewed distributions.

INDIAN EXAMPLE

Order value std dev = ₹1,840. This means orders typically vary about ₹1,840 from the mean of ₹1,148. Delivery days std dev = 1.8 days.

Python
print(f"Variance: {df['amount_inr'].var():,.0f}")
print(f"Std Dev:  ₹{df['amount_inr'].std():,.0f}")

# Compare consistency across cities
df.groupby('city')['delivery_days'].agg(['mean', 'std', 'median']).round(1)

# Z-score: how many std devs from the mean is each value?
df['amount_zscore'] = (df['amount_inr'] - df['amount_inr'].mean()) / df['amount_inr'].std()
outliers = df[df['amount_zscore'].abs() > 3]
print(f"Z-score outliers: {len(outliers)}")
SQL
SELECT
    ROUND(AVG(amount_inr), 0)                  AS mean_val,
    ROUND(STDDEV(amount_inr), 0)               AS std_dev,
    ROUND(VARIANCE(amount_inr), 0)             AS variance
FROM orders;

-- Z-score in SQL
SELECT order_id, amount_inr,
    (amount_inr - AVG(amount_inr) OVER()) / STDDEV(amount_inr) OVER() AS zscore
FROM orders;
ANALYST INSIGHT: For delivery days: Mumbai std dev = 0.9 days (very consistent). Tier-3 cities std dev = 3.4 days (inconsistent). A low mean delivery time with high std dev is worse than a slightly higher mean with low std dev — unpredictability drives customer complaints more than length.

IQR (Interquartile Range)

Q3 (75th percentile) − Q1 (25th percentile)

The spread of the middle 50% of values. Unaffected by outliers at either end.

✓ USE WHEN

Skewed data. Outlier detection (values beyond Q1 − 1.5×IQR or Q3 + 1.5×IQR). Comparing consistency across groups when data is skewed.

✗ AVOID WHEN

When you need to use ALL the data in the spread measure (use std dev). For very small samples (under 10 rows — percentiles are unreliable).

INDIAN EXAMPLE

Order values: Q1 = ₹450, Q3 = ₹1,800. IQR = ₹1,350. The middle 50% of orders fall within a ₹1,350 range.

Python
Q1  = df['amount_inr'].quantile(0.25)
Q3  = df['amount_inr'].quantile(0.75)
IQR = Q3 - Q1

print(f"Q1 (25th):  ₹{Q1:,.0f}")
print(f"Median:     ₹{df['amount_inr'].median():,.0f}")
print(f"Q3 (75th):  ₹{Q3:,.0f}")
print(f"IQR:        ₹{IQR:,.0f}")

# Outlier boundaries
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
print(f"Outlier bounds: below ₹{lower:,.0f} or above ₹{upper:,.0f}")

# Full percentile summary
for p in [10, 25, 50, 75, 90, 95, 99]:
    print(f"P{p:2d}: ₹{df['amount_inr'].quantile(p/100):,.0f}")
SQL
SELECT
    PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY amount_inr) AS Q1,
    PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY amount_inr) AS median,
    PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY amount_inr) AS Q3,
    PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY amount_inr) -
    PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY amount_inr) AS IQR
FROM orders;  -- PostgreSQL

-- MySQL: use subqueries with ROW_NUMBER for each percentile
ANALYST INSIGHT: The Pareto principle (80/20 rule) shows up in IQR analysis: the top 25% of orders (above Q3 = ₹1,800) often account for 60–70% of total revenue. Understanding the distribution structure tells you where revenue leverage is.

Shape of Distribution

How is the data distributed?

Skewness

Σ((x − mean) / std)³ / n | Positive = right tail, Negative = left tail

How asymmetric is the distribution? Right skew = long tail on the right (few very high values). Left skew = long tail on the left (few very low values).

✓ USE WHEN

Deciding whether to use mean or median. Checking assumptions before applying statistical tests. Understanding income or revenue concentration.

✗ AVOID WHEN

As a standalone metric — always visualise the distribution alongside the skewness value.

INDIAN EXAMPLE

Order value skewness = +2.3 (strong right skew). Most orders are small (₹200–₹1,000), but a few very large orders (₹20,000+) pull the distribution to the right.

Python
print(f"Skewness: {df['amount_inr'].skew():.2f}")
# > 1: strong right skew → use median
# 0.5–1: moderate right skew → note but mean is still usable
# -1 to -0.5: moderate left skew
# < -1: strong left skew → use median

# Log-transform to reduce right skew (before modelling)
import numpy as np
df['log_amount'] = np.log1p(df['amount_inr'])
print(f"After log transform, skewness: {df['log_amount'].skew():.2f}")

# Visualise: before and after
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
ax1.hist(df['amount_inr'],  bins=60, color='#1d4ed8', edgecolor='white')
ax1.set_title(f'Original  (skew={df["amount_inr"].skew():.1f})', fontweight='bold')
ax2.hist(df['log_amount'],  bins=60, color='#7c3aed', edgecolor='white')
ax2.set_title(f'Log-transformed (skew={df["log_amount"].skew():.1f})', fontweight='bold')
plt.tight_layout();  plt.show()
SQL
-- No built-in SKEWNESS in most SQL databases
-- Compute manually or use Python/R for this
ANALYST INSIGHT: Right-skewed distributions are the norm in Indian e-commerce: a small number of high-value customers, products, or orders generate most revenue. This is why Pareto analysis (top 20% of customers = 80% of revenue) is a standard analyst tool.

Percentiles & Quartiles

Pₙ = value below which n% of data falls

Divide the sorted data into equal-sized groups. P50 = median. P25 = Q1. P75 = Q3. P90 = the value below which 90% of data falls.

✓ USE WHEN

Understanding data distribution at multiple points. Defining tiers (bottom 25%, middle 50%, top 25%). Setting performance benchmarks.

✗ AVOID WHEN

Very small datasets (under 20 rows) — percentiles become unreliable.

INDIAN EXAMPLE

Salary data: P10 = ₹18K/month, P25 = ₹28K, P50 = ₹45K, P75 = ₹72K, P90 = ₹1.2L. The "top 10%" threshold is ₹1.2L.

Python
# Full percentile profile
percentiles = df['amount_inr'].quantile([0.10, 0.25, 0.50, 0.75, 0.90, 0.95, 0.99])
for p, val in percentiles.items():
    print(f"P{int(p*100):2d}: ₹{val:,.0f}")

# Classify customers into revenue tiers
df['revenue_tier'] = pd.cut(
    df.groupby('customer_id')['amount_inr'].transform('sum'),
    bins=[0,
          df.groupby('customer_id')['amount_inr'].sum().quantile(0.33),
          df.groupby('customer_id')['amount_inr'].sum().quantile(0.67),
          float('inf')],
    labels=['Bronze', 'Silver', 'Gold']
)
SQL
SELECT
    PERCENTILE_CONT(0.10) WITHIN GROUP (ORDER BY amount_inr) AS P10,
    PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY amount_inr) AS P25,
    PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY amount_inr) AS P50,
    PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY amount_inr) AS P75,
    PERCENTILE_CONT(0.90) WITHIN GROUP (ORDER BY amount_inr) AS P90,
    PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY amount_inr) AS P99
FROM orders;
ANALYST INSIGHT: Percentile-based customer segmentation (Bronze / Silver / Gold tiers) is more robust than mean-based segmentation because it is relative — the Gold tier always contains exactly the top 33% of customers regardless of how the distribution shifts over time.

Quick Reference — When to Use Each Statistic

StatisticMeasuresUse whenIndian Example
MeanCentre (sensitive to outliers)Symmetric data, no extreme outliersAverage test score in a batch of 30 students
MedianCentre (robust to outliers)Skewed data: income, order values, pricesMedian salary in a city (more representative)
ModeMost common valueCategorical data; finding the "typical" categoryMost common payment method (UPI)
Std DevSpread (sensitive to outliers)Symmetric data; Z-scores; A/B test analysisConsistency of daily orders at a warehouse
IQRSpread (robust to outliers)Skewed data; outlier detection; box plotsSpread of order values across a city
RangeTotal extentQuick sanity check; catch data errorsVerify no negative order values exist
SkewnessAsymmetry of distributionDeciding mean vs median; pre-modelling checksAmount_inr is right-skewed → use median for "typical"
PercentilesData at specific positionsTiering; benchmarking; outlier thresholdsClassify customers into Bronze/Silver/Gold tiers
Continue the Series
← Ch 12: Data CleaningCh 14: Correlation & Regression →

Frequently Asked Questions

When should you use mean vs median?

Use the median when the data is skewed or contains outliers. Use the mean when the data is roughly symmetric with no extreme outliers. The key difference: the mean uses every value in its calculation, so one very large or very small value can pull it significantly. The median is the middle value when data is sorted — it is insensitive to extremes. In Indian business contexts: always use the median for income data, order values, property prices, and salary data — these are always right-skewed with high-value outliers. The mean salary in India, for example, is heavily pulled up by a small number of very high earners, making it unrepresentative of the typical person. The median salary is more informative. Use the mean for normally distributed data like test scores, daily temperatures, or manufacturing process measurements where the distribution is symmetric.

What is standard deviation and why does it matter for data analysis?

Standard deviation (σ or std) measures the average amount by which values in a dataset differ from the mean. A low standard deviation means values are clustered tightly around the mean. A high standard deviation means values are spread widely. For data analysts, standard deviation matters because: (1) it quantifies variability — knowing average delivery time is 4.2 days is incomplete without knowing the std is 0.8 days (consistent) vs 3.5 days (very inconsistent); (2) it is used in outlier detection — values beyond 2–3 standard deviations from the mean are flagged as unusual; (3) it is required for z-score normalisation in machine learning; (4) it appears in many statistical tests (t-tests, ANOVA) that analysts run for A/B testing and hypothesis testing. In Python: df['column'].std(). In Excel: =STDEV(range).

What does skewness tell you about a dataset?

Skewness measures the asymmetry of a distribution. A skewness of 0 means the distribution is perfectly symmetric (like a normal distribution). Positive skewness (right skew) means the tail extends to the right — most values are low but a few extremely high values exist. Negative skewness (left skew) means the tail extends to the left — most values are high but a few extremely low values exist. Why it matters for analysts: (1) in right-skewed data (common in income, order values, page views), the mean > median. Reporting the mean misrepresents the "typical" value. Use the median. (2) skewness determines which statistical tests are appropriate — many tests assume normal distribution; highly skewed data may require transformation (log transform) or non-parametric tests; (3) right-skewed distributions are nearly universal in Indian business data: a small number of high-value customers, products, or orders drive a disproportionate share of revenue (the Pareto principle).

What is IQR and how is it used in data analysis?

IQR (Interquartile Range) is the difference between the 75th percentile (Q3) and 25th percentile (Q1) of a dataset. It represents the spread of the middle 50% of values. IQR = Q3 − Q1. For a dataset of order values: if Q1 = ₹450 and Q3 = ₹1,800, then IQR = ₹1,350 — meaning the central 50% of orders fall within a ₹1,350 range. IQR is used for: (1) outlier detection — the standard rule flags values below Q1 − 1.5×IQR or above Q3 + 1.5×IQR as outliers (the box plot whisker rule); (2) measuring spread when data is skewed — IQR is a better measure of spread than standard deviation for skewed data because it is resistant to outliers; (3) comparing consistency across groups — a city with IQR = ₹500 is much more consistent in order values than a city with IQR = ₹3,200. In Python: df['col'].quantile(0.75) - df['col'].quantile(0.25). In Excel: =QUARTILE(range,3) - QUARTILE(range,1).

EVIKA ACADEMY · NOIDA SECTOR 51

Apply Statistics on Real Indian Datasets

Our curriculum covers every concept in this chapter — applied to real Indian business data, with interpretation practice and mock interview questions on statistics.

Book Free Demo Class →
🎓 Free Demo Class — Online & Offline · Noida Sector 51