0.3 Data, Measured - JulTob/Data GitHub Wiki
We study the territory (reality) by making a map (data). Every mistake in analysis is either (a) a bad map or (b) using the map for the wrong terrain.
- Unit of analysis (u): the “who/what” you measure (a person, a transaction, a day).
- Variable (X): a measurable attribute on units.
- Population (𝒫): all units of interest.
- Sample (S ⊂ 𝒫): the units observed.
- Measurement scale: nominal / ordinal / interval / ratio.
- Study design: observational vs experimental; cross-sectional vs longitudinal.
Before you compute anything:
- Name the unit, the variable, and its scale.
- Declare allowed operations for that scale.
- Check if the sample represents the population you’ll generalize to.
A variable is a function from units to values:
- Nominal: just labels (e.g., browser ∈ {Chrome, Firefox,…}).
- Ordinal: labels with order (e.g., Likert 1–5), no guaranteed spacing.
- Interval: equal steps, no true zero (°C). Differences make sense; ratios do not.
- Ratio: equal steps with true zero (kg, €, time). Differences and ratios make sense.
Signal vs symbol. If you numerically encode labels, you’ve changed the symbols, not the signal. The signal lives in the scale.
Classify each:
- “city”
- satisfaction 1–5
- temperature °C
- income €.
:
Answers
1. nominal 2. ordinal 3. interval 4. ratioYou’re allowed to do only what the scale permits.
| Scale | Valid comparisons | Legit summaries | Misuse to avoid | Safe visuals |
|---|---|---|---|---|
| Nominal | = / ≠ | counts, proportions, mode | mean/SD, correlations on codes | bar/mosaic |
| Ordinal | order, percentiles | median, IQR, rank stats (Spearman) | arithmetic on codes; unqualified mean | ordered bar; box/violin by group |
| Interval | differences | mean, SD, z-scores | ratio talk (“twice as hot” in °C) | histogram/KDE; line |
| Ratio | differences, ratios | mean, SD, geometric mean (>0) | — | histogram (log-x if skew), scatter |
Statistic contracts (preconditions).
- Mean( X ) requires interval or ratio.
- Correlation(X,Y) requires both at least interval (Pearson). For ordinal, use Spearman.
- Geometric mean requires positive ratio data.
Let (S\subset\mathcal P). If selection ≠ random w.r.t. (X), estimates are biased. Common gremlins: convenience samples, survivorship bias, nonresponse bias.
Measured (X) = true score (T) + error (E).
- Reliability ↑ when (\text{Var}(E)) ↓.
- Validity = measuring the right construct (map aligns with terrain).
For a numeric variable (X) on ratio/interval scales:
Center.
Spread.
When to prefer median/IQR: heavy tails or outliers; ordinal scale.
10-second diagnostic. Plot histogram (or ECDF), eyeball skew/outliers, then choose center/spread accordingly.
- Nominal: bar/mosaic; order by frequency to reduce cognitive load.
- Ordinal: ordered bars; box by group (on ranks).
- Interval/Ratio: histogram/KDE; scatter; line for time; consider log-axis for multiplicative spread.
Micro-lab (5 min, code). Honor the scale in code.
import pandas as pd
from pandas.api.types import CategoricalDtype
df = pd.DataFrame({
"browser": ["Chrome","Firefox","Safari","Chrome","Edge","Chrome"],
"satisf": ["bad","ok","good","ok","good","good"],
"temp_C": [20,22,19,23,21,26],
"income": [30_000,50_000,45_000,70_000,60_000,120_000],
})
# Nominal → categorical
df["browser"] = df["browser"].astype("category")
# Ordinal → ordered categorical
Likert = CategoricalDtype(["bad","ok","good"], ordered=True)
df["satisf"] = df["satisf"].astype(Likert)
# Interval / Ratio → numeric
df["temp_C"] = pd.to_numeric(df["temp_C"], errors="coerce")
df["income"] = pd.to_numeric(df["income"], errors="coerce")
# Safe summaries
browser_share = df["browser"].value_counts(normalize=True) # nominal
satisf_median = df["satisf"].cat.codes.median() # ordinal (on ranks)
temp_mean, temp_sd = df["temp_C"].mean(), df["temp_C"].std() # interval
inc_mean = df["income"].mean() # ratio-
The Encoded Trap. If you relabel categories as 1,2,3, the numbers change but the facts don’t. Should correlation change? → Only if you wrongly treat labels as interval. Correct move: use counts or rank-based methods.
-
The “Twice as Hot” Illusion. 40 °C vs 20 °C: twice as large? → Not on interval scales. In Kelvin (ratio scale), 313 K vs 293 K is not 2× either.
-
Aggregation vs Truth. Two hospitals: A (small) has lower mortality than B (large) in every condition subgroup, but higher overall. → Simpson’s paradox. Condition on subgroups before global statements.
Lab A — Scale-aware pipeline.
- Pick one variable of each scale from any dataset.
- Enforce dtype (category/ordered/numeric).
- Produce exactly one valid summary + one valid plot per variable. Deliverable: a 1-page “Data Dictionary with Contracts”.
Lab B — Outlier ethics. Compute mean/median with and without top 1% incomes. Report the decision rule for which summary you will publish and why.
- Why does mean require interval/ratio? — Because it assumes equal spacing; ordinal spacing is unknown.
- Define independence in probability and in plain language. — (P(A\cap B)=P(A)P(B)); knowing one doesn’t change odds of the other.
- Name three biases that break generalization. — Selection, survivorship, nonresponse (many others exist).
10.1 Scale → Method
- Nominal → counts/props; bar; χ² tests; one-hot for models.
- Ordinal → median/IQR; ordered bar; Mann–Whitney / Spearman; ordinal encodings.
- Interval → mean/SD; hist/KDE; careful with ratios.
- Ratio → mean/SD/geomean; log plots if skew; parametrics OK if assumptions hold.
10.2 Statistic Preconditions (as code comments)
# Mean(X): requires interval or ratio
# GeometricMean(X): requires X > 0 (ratio)
# PearsonCorr(X,Y): both interval/ratio, roughly linear, few extreme outliers
# Spearman(X,Y): ordinal or monotone relations
10.3 Minimal dtype enforcement (reusable snippet)
def EnforceScales(df, plan):
# plan: {"var": {"scale": "nominal|ordinal|interval|ratio", "order": [...]}}
from pandas.api.types import CategoricalDtype
for var, spec in plan.items():
s = spec["scale"]
if s == "nominal":
df[var] = df[var].astype("category")
elif s == "ordinal":
df[var] = df[var].astype(CategoricalDtype(spec["order"], ordered=True))
else:
df[var] = pd.to_numeric(df[var], errors="coerce")
return df- Episode 2: Probability as the Language of Uncertainty. Events, conditional probability, total probability, Bayes—why the denominator matters.
- Episode 3: Descriptive Statistics, Seriously. Expectation, variance, covariance; when the median outperforms the mean.
- Episode 4: Visualization Grammar. Marks, encodings, and how to choose plots by question, not habit.
- Episode 5: Cleaning & Types. Missingness, coercion, and making your data dictionary executable.
A. Choosing the center under skew Given (x = (10, 12, 11, 13, 500)):
Inference: publish median + IQR; show a histogram with logged x-axis if you must show 500.
B. Ordinal safely
Likert scores