# Choose a Response Family

The `family` argument tells Whittaker which probability distribution governs the response and which link function connects the linear predictor to the mean. Choosing the right family is the single most important modeling decision. A mismatched family produces biased smooths and unreliable standard errors.


# The family table

| Family | Class | Link | Use when |
|----|----|----|----|
| Gaussian | `wk.Gaussian()` | identity | Continuous, unbounded, roughly symmetric |
| Poisson | `wk.Poisson()` | log | Non-negative integer counts |
| Binomial | `wk.Binomial()` | logit | Binary (0/1) or proportion |
| Gamma | `wk.Gamma()` | log | Positive, right-skewed (costs, durations) |
| Negative Binomial | `wk.NegativeBinomial()` | log | Overdispersed counts |
| Beta | `wk.Beta()` | logit | Proportions strictly in (0, 1) |
| Tweedie | `wk.Tweedie()` | log | Zero-inflated positive (insurance) |
| Inverse Gaussian | `wk.InverseGaussian()` | log | Positive, heavy right tail |

Pass any family as a keyword argument: `wk.GAM("y ~ s(x)", family=wk.Poisson())`.


# Gaussian (default)

Gaussian is appropriate when the response is continuous and can take any real value. The `mcycle` head-acceleration data fits this description.


``` python
import whittaker as wk

data = wk.load_dataset("mcycle")
```


``` python
# Fit default Gaussian GAM
model_g = wk.GAM("accel ~ s(times)").fit(data)
model_g.summary()
```


    GAM fit summary
    ============================================================
    Formula:    accel ~ s(times)
    Family:     Gaussian(link='identity')
    Inference:  GCV
    Observations: 133
    Coefficients: 10

    Parametric coefficients:
      Term                       Estimate    Std.Err    t value    p-value
      ------------------------ ---------- ---------- ---------- ----------
      (Intercept)                -45.6924     1.8364    -24.882    < 1e-16

    Approximate significance of smooth terms:
      Term                        EDF Ref.df     Chi.sq    p-value
      ------------------------ ------ ------ ---------- ----------
      s(times)                   7.92      8    663.396    < 1e-16

    Total EDF:  8.92
    Scale est:  448.517253
    Deviance:   55653.7152
    Null dev:   357878.4929
    Dev. expl:  84.4%
    GCV score:  480.746119
    AIC:        1198.44
    BIC:        1224.22


# Poisson

Use Poisson when the response is a non-negative integer count. The `fish` dataset records the number of fish caught at different water temperatures and depths.


``` python
data = wk.load_dataset("fish")
```


``` python
# Fit Poisson GAM for count response
model_p = wk.GAM(
    "count ~ s(temperature) + depth",
    family=wk.Poisson(),
).fit(data)
model_p.summary()
```


    GAM fit summary
    ============================================================
    Formula:    count ~ s(temperature) + depth
    Family:     Poisson(link='log')
    Inference:  GCV
    Observations: 300
    Coefficients: 11

    Parametric coefficients:
      Term                       Estimate    Std.Err    z value    p-value
      ------------------------ ---------- ---------- ---------- ----------
      (Intercept)                  2.1998     0.0479     45.901    < 1e-16
      depth                       -0.0249     0.0018    -13.916    < 1e-16

    Approximate significance of smooth terms:
      Term                        EDF Ref.df     Chi.sq    p-value
      ------------------------ ------ ------ ---------- ----------
      s(temperature)             4.24      5    294.821    < 1e-16

    Total EDF:  6.24
    Scale est:  1.000000
    Deviance:   321.0387
    Null dev:   843.4578
    Dev. expl:  61.9%
    GCV score:  1.116056
    AIC:        1304.77
    BIC:        1327.88


The log link keeps predicted counts positive. Deviance explained replaces R² as the fit statistic.


# Binomial

Use Binomial for binary (0/1) outcomes or proportions formed from counts. The `credit` dataset has a binary `default` column and continuous predictors `income` and `debt_ratio`.


``` python
data = wk.load_dataset("credit")
```


``` python
# Fit Binomial GAM for binary outcome
model_b = wk.GAM(
    "default ~ s(income) + s(debt_ratio)",
    family=wk.Binomial(),
).fit(data)
model_b.summary()
```


    GAM fit summary
    ============================================================
    Formula:    default ~ s(income) + s(debt_ratio)
    Family:     Binomial(link='logit')
    Inference:  GCV
    Observations: 1000
    Coefficients: 19

    Parametric coefficients:
      Term                       Estimate    Std.Err    z value    p-value
      ------------------------ ---------- ---------- ---------- ----------
      (Intercept)                 -0.3591     0.0725     -4.954  7.258e-07

    Approximate significance of smooth terms:
      Term                        EDF Ref.df     Chi.sq    p-value
      ------------------------ ------ ------ ---------- ----------
      s(income)                  2.90      3    113.502    < 1e-16
      s(debt_ratio)              1.75      2    100.420    < 1e-16

    Total EDF:  5.65
    Scale est:  1.000000
    Deviance:   1144.6940
    Null dev:   1364.9020
    Dev. expl:  16.1%
    GCV score:  1.157741
    AIC:        1156.00
    BIC:        1183.73


The logit link maps predicted probabilities into the real line. Predictions from `model_b.predict()` are on the probability scale by default.


# Other families

Every family in the table follows the same pattern (pass an instance to `family=`). No other part of the API changes. For overdispersed counts try `wk.NegativeBinomial()` and for strictly bounded proportions try out `wk.Beta()`.
