cassionData Analysis

Back to the lessonLesson 1 of 8A model is a comparison

The coefficient is the difference

The same deck as the downloads, rendered as a page. Start the slideshow to present it full screen — arrow keys or a click advance one slide, Escape leaves.

Slides · PDFSlides · PowerPoint

  1. Slide 1 / 25

    What this lesson covers

    • The same comparison, written twice
    • What every term means
    • Where the two routes differ, and by how much
    • Three predictors, three readings
    • What the model does not say
    • Report it whole
    • What comes next
    Speaker notes
    Fit attendance against a single feeding dummy. The intercept is 85.21% — the mean of schools with no programme. The coefficient is 4.94 points — the difference between the two means, to four decimal places. A regression with one dummy is a two-group comparison and nothing more.
  2. Slide 2 / 25

    The same comparison, written twice — In Python (cont.)

    import pandas as pd
    import numpy as np
    import statsmodels.formula.api as smf
    
    attendance = pd.read_csv("school-attendance-2024.v1.csv")
    roster = pd.read_csv("school-roster-2024.v1.csv").drop_duplicates(
        "student_id", keep="last")          # two never-de-registered transfers
    
    MARKS = {"true": True, "Y": True, "false": False, "N": False}
    marked = attendance[attendance["present"].isin(MARKS)].copy()
    marked["attended"] = marked["present"].map(MARKS)
    
    per_student = (marked.groupby("student_id")["attended"].mean()
                   .rename("rate").reset_index()
                   .merge(roster, on="student_id"))
    
    Speaker notes
    The statistics course compared attendance in schools with a feeding programme against schools without one, and got 90.15% against 85.21%. Fit that as a regression and look at what comes back.
  3. Slide 3 / 25

    The same comparison, written twice — In Python (cont.)

    model = smf.ols("rate ~ feeding_programme", data=per_student).fit()
    print(model.summary().tables[1])
  4. Slide 4 / 25

    The same comparison, written twice — In R

    library(dplyr)
    
    per_student |> lm(rate ~ feeding_programme, data = _) |> summary()
  5. Slide 5 / 25

    The same comparison, written twice

    TermCoefficientSEt
    Intercept0.85210.0070121.30
    feeding_programme[True]0.04940.00885.63
  6. Slide 6 / 25

    The same comparison, written twice — In Python

    means = per_student.groupby("feeding_programme")["rate"].mean()
    print(means)
    print(f"difference: {means[True] - means[False]:.4f}")
  7. Slide 7 / 25

    The same comparison, written twice — In R

    per_student |> summarise(rate = mean(rate), .by = feeding_programme)
  8. Slide 8 / 25

    The same comparison, written twice

    • Mean without a programme: 0.8521. Mean with: 0.9015. Difference: 0.0494
    Speaker notes
    Mean without a programme: 0.8521. Mean with: 0.9015. Difference: 0.0494. The intercept is the first number and the coefficient is the third, exactly. This is not an approximation or a coincidence — with one binary predictor and nothing else, least squares has no freedom to do anything but reproduce the two group means.
  9. Slide 9 / 25

    What every term means

    • The intercept is the fitted value when every predictor is zero — Here that is feeding_programme = False, so the…
    • A coefficient is the change in the outcome for a one-unit change in that predictor, with the others held fixed — For a…
    • A standard error is the same standard error the last course computed — The t column is coefficient over standard…
    Speaker notes
    Three sentences cover the whole of reading a coefficient table, and they hold for every model in this course. The intercept is the fitted value when every predictor is zero. Here that is feeding_programme = False, so the intercept is the mean of schools with no programme. It is not "the average attendance" and it is not a baseline in any programme sense — it is a specific group's mean, and which group depends entirely on how the predictors were coded. A coefficient is the change in the outcome for a one-unit change in that predictor, with the others held fixed. For a dummy, "one unit" is False → True, so the coefficient is a difference between two groups. A standard error is the same standard error the last course computed. The t column is coefficient over standard error, and the interval is the coefficient plus or minus about two standard errors. Nothing new is being introduced.
  10. Slide 10 / 25

    What every term means — In Python

    coef = model.params["feeding_programme[T.True]"]
    se = model.bse["feeding_programme[T.True]"]
    print(f"{coef:+.4f}  95% CI [{coef - 1.96*se:+.4f}, {coef + 1.96*se:+.4f}]")
  11. Slide 11 / 25

    What every term means — In R

    confint(model)
  12. Slide 12 / 25

    What every term means

    • +0.0494, 95% CI +0.0322 to +0.0665 — the same interval, arrived at from the same data by a different route
    Speaker notes
    +0.0494, 95% CI +0.0322 to +0.0665 — the same interval, arrived at from the same data by a different route.
  13. Slide 13 / 25

    Where the two routes differ, and by how much

    • Ordinary least squares assumes one residual variance for both groups — It is the pooled-variance t-test written in…
    Speaker notes
    The regression t is 5.63 and the Welch t-test in the statistics course gave 5.41. That difference is not an error in either. Ordinary least squares assumes one residual variance for both groups. It is the pooled-variance t-test written in matrix form. Welch's test does not assume it, which is why the last course recommended Welch by default.
  14. Slide 14 / 25

    Where the two routes differ, and by how much — In Python

    from scipy import stats
    
    fed = per_student[per_student["feeding_programme"]]["rate"]
    unfed = per_student[~per_student["feeding_programme"]]["rate"]
    print(f"variances: {fed.var():.5f} and {unfed.var():.5f}")
    print("pooled t:", stats.ttest_ind(fed, unfed).statistic.round(2))
    print("Welch  t:", stats.ttest_ind(fed, unfed, equal_var=False).statistic.round(2))
  15. Slide 15 / 25

    Where the two routes differ, and by how much — In R

    t.test(rate ~ feeding_programme, data = per_student, var.equal = TRUE)
    t.test(rate ~ feeding_programme, data = per_student)
  16. Slide 16 / 25

    Where the two routes differ, and by how much

    • Regression reproduces the pooled t exactly — When the group variances are close the two barely differ; here they are…
    Speaker notes
    Regression reproduces the pooled t exactly. When the group variances are close the two barely differ; here they are 0.019 and 0.025, and the gap is the reason Welch exists. A regression cannot be told "use Welch" — the fix is a robust standard error, which lesson 6 introduces for a related reason.
  17. Slide 17 / 25

    Three predictors, three readings

    PredictorCoefficient reads as
    Binary (feeding_programme)The difference between the two groups
    Continuous (age_years)The change per one year
    Categorical with k levelsk−1 coefficients, each a difference against the omitted level
    Speaker notes
    A regression's usefulness starts when the predictor is not binary. Each type reads differently and each is a comparison.
  18. Slide 18 / 25

    Three predictors, three readings — In Python

    enrolment = pd.read_csv("school-enrolment-2024.v1.csv")
    current = enrolment[enrolment["school_year"] == 2024]
    joined = per_student.merge(
        current[["student_id", "sex", "age_years", "admin2"]], on="student_id")
    
    print(smf.ols("rate ~ admin2", data=joined).fit().params.round(4))
    print(joined.groupby("admin2")["rate"].mean().round(4))
  19. Slide 19 / 25

    Three predictors, three readings — In R

    lm(rate ~ admin2, data = joined) |> coef()
    joined |> summarise(rate = mean(rate), .by = admin2)
  20. Slide 20 / 25

    Three predictors, three readings

    • A categorical predictor produces one coefficient per level except one — and every coefficient is a comparison against…
    • Say the reference level in the table caption — "Against Artibonite" is four words and it is the difference between a…
    Speaker notes
    A categorical predictor produces one coefficient per level except one, and every coefficient is a comparison against that omitted level. Change which level is omitted and every number in the column changes while the model is identical — which is the first sign that a coefficient means nothing without knowing what it is being compared against. Say the reference level in the table caption. "Against Artibonite" is four words and it is the difference between a readable table and one a reader has to guess at.
  21. Slide 21 / 25

    What the model does not say

    • It is not an effect — The 4.9-point coefficient is the difference between two sets of schools that were not randomised…
    • It is not a prediction worth making — Regression is taught elsewhere as a prediction machine, and for programme data…
    Speaker notes
    Two things a coefficient never carries, both of which readers supply for themselves. It is not an effect. The 4.9-point coefficient is the difference between two sets of schools that were not randomised into having a feeding programme. Every regression in this course is a comparison of groups that already differed; lesson 5 is about which of those differences you can and cannot remove. It is not a prediction worth making. Regression is taught elsewhere as a prediction machine, and for programme data that framing does damage: it invites model comparison by fit rather than by whether the comparison is the one the report needs. Fit the model your question implies, then read the coefficient it was fitted for, and treat R² as a diagnostic rather than a score — lesson 8 is about a model with an R² of 0.03 that is the most useful result in its report.
  22. Slide 22 / 25

    Report it whole — Example

    Attendance and school feeding, February to April 2024
    
      Linear model, one predictor, 1,200 students.
    
      Intercept (no programme)   85.21%
      Feeding programme          +4.94 points   95% CI +3.22 to +6.65
    
      The coefficient is the difference between the two group means and is
      reported as such. Schools were not randomised into the programme; the
      comparison is observational.
    
      The standard error assumes independent students. It is not, and lesson 6
      gives the corrected version.
  23. Slide 23 / 25

    Report it whole

    • The last line is a promissory note the course pays off — and writing it is better than not knowing it is owed
    Speaker notes
    The last line is a promissory note the course pays off, and writing it is better than not knowing it is owed. A model reported with a caveat you can name is in better shape than one reported without.
  24. Slide 24 / 25

    What comes next

    • One predictor reproduces a comparison you could have made without a model.
    Speaker notes
    One predictor reproduces a comparison you could have made without a model. The next lesson adds the second predictor, which is where a regression starts earning its keep — and where "adjusting for" gets a precise meaning that is narrower than most reports assume.
  25. Slide 25 / 25

    Where this goes next

    Read the full lesson, with runnable code Back to the lesson