# Log-Contrast Regression

Can the community predict the soil temperature it lives in, and which taxa carry
that signal?

That is a regression with a constraint. The predictors are compositional:
sequencing depth is arbitrary, so only *ratios* between features mean anything.
Log-contrast regression transforms to log-ratios and requires the coefficients
to sum to zero, so the fit depends on the balance between taxa rather than on
any absolute abundance the sequencing run happened to produce
{cite}`aitchison1984log,lin2014variable`.

This fit uses no taxonomy. [Tree-Aggregated
Regression](02_trac.md) puts it back, and the two are worth comparing.

## Step 1: Transform Features

Apply CLR transformation to the count data:

```bash
qiime classo transform-features \
    --p-transformation clr \
    --p-coef 0.5 \
    --i-features data/atacama-counts.qza \
    --o-x data/xclr
```

## Step 2: Add Covariates

Include environmental metadata with custom weights for each covariate:

```bash
qiime classo add-covariates \
    --i-features data/xclr.qza \
    --m-covariates-file data/atacama-selected-covariates-veg.tsv \
    --p-to-add ph average-soil-relative-humidity elevation average-soil-temperature vegetation \
    --p-w-to-add 1. 0.1 0.1 0.1 1 \
    --o-new-features data/xcovariates_lc \
    --o-new-c data/ccovariates_lc \
    --o-new-w data/wcovariates_lc
```

## Step 3: Split Data

Create training and test sets for regression analysis:

```bash
qiime sample-classifier split-table \
    --i-table data/xcovariates_lc.qza \
    --m-metadata-file data/atacama-selected-covariates-veg.tsv \
    --m-metadata-column average-soil-temperature \
    --p-test-size 0.2 \
    --p-random-state 42 \
    --p-stratify False \
    --o-training-table data/regress-xtraining_lc.qza \
    --o-test-table data/regress-xtest_lc.qza \
    --o-training-targets data/regress-training-targets_lc.qza \
    --o-test-targets data/regress-test-targets_lc.qza
```

## Step 4: Train the Regression Model

Fit the model with stability selection, which scores each feature by how often it survives resampling:

```bash
qiime classo regress \
    --i-features data/regress-xtraining_lc.qza \
    --i-c data/ccovariates_lc.qza \
    --i-weights data/wcovariates_lc.qza \
    --m-y-file data/atacama-selected-covariates-veg.tsv \
    --m-y-column average-soil-temperature \
    --p-concomitant False \
    --p-stabsel \
    --p-cv \
    --p-path \
    --p-lamfixed \
    --p-stabsel-threshold 0.5 \
    --p-cv-seed 1 \
    --p-no-cv-one-se \
    --o-result data/regresstaxa_lc.qza
```

**Key parameters:**
- `--p-stabsel`: Run stability selection alongside the path fit
- `--p-stabsel-threshold 0.5`: Keep features selected in more than 50% of subsamples
- `--p-cv`: Choose the penalty by cross-validation
- `--p-concomitant False`: Hold the noise scale fixed instead of estimating it with the coefficients

## Step 5: Make Predictions

Apply the trained model to test data:

```bash
qiime classo predict \
    --i-features data/regress-xtest_lc.qza \
    --i-problem data/regresstaxa_lc.qza \
    --o-predictions data/regress-predictions_lc.qza
```

## Step 6: Visualize Results

Render the fitted problem and its predictions as a report:

```bash
qiime classo summarize \
    --i-problem data/regresstaxa_lc.qza \
    --i-predictions data/regress-predictions_lc.qza \
    --o-visualization data/regresstaxa_R1_lc.qzv
```

Open it with `qiime tools view` or at [QIIME 2 View](https://view.qiime2.org/).

## Reading the result

```{figure} ../../../images/png/classo_reg.png
:name: fig-classo-regression-panels
:width: 100%

The four panels a `classo summarize` regression report gives you, on the 13-ASV
toy data. **Top left:** predicted against observed soil temperature on held-out
samples. **Top right:** cross-validated $L_2$ error along the $\lambda$ path.
**Bottom left:** every coefficient $\beta_i$ as the penalty relaxes — the order
in which taxa enter is the order of their apparent importance. **Right:**
stability selection, the proportion of subsamples in which each ASV was selected,
against a threshold.
```

Four questions, one panel each.

**Does the model predict anything?** The scatter, not the $R^2$ alone. With
$R^2 = 0.707$ on 10 held-out samples, one influential point moves that number a
lot — look at whether the cloud follows the line or whether two extremes are
carrying it.

**Was the penalty chosen sensibly?** Look for a visible minimum in the CV curve.
Here it descends and flattens rather than turning up, so the cross-validation
does not strongly identify a best $\lambda$. The `--p-cv-one-se` rule exists for
exactly this situation, and this run disabled it (`--p-no-cv-one-se`).

**Which taxa carry the signal?** The coefficient paths. Taxa whose $\beta$ leaves
zero early and stays large contribute consistently along the path. Taxa that
wander near zero do not. Because the coefficients must sum to zero, they come in
opposing groups — a positive $\beta$ is only meaningful relative to the negative
ones.

**Would those taxa be selected again?** Stability selection resamples the data
and counts how often each feature survives {cite}`meinshausen2010stability`.
Trust this panel when the coefficient path looks ambiguous. The threshold is a
choice you make, not a result.

```{note}
The figure comes from a run at a stability threshold of 0.7, while the command
above uses `--p-stabsel-threshold 0.5`. Expect more features above your line
than above the one drawn here. The figure also carries a stray `ASV₁₄` tick
label — the toy table has 13 features, not 14.
```

## Outputs

`data/regresstaxa_lc.qza` holds the fitted problem — the coefficient path, the CV
curve and the stability-selection frequencies. Beside it sit the predictions on
the held-out split and a `.qzv` rendering all four panels above.

The comparison worth making next is [Tree-Aggregated
Regression](02_trac.md): the same outcome, the same samples, but predictors
aggregated up the taxonomy. If a clade predicts better than its member ASVs,
that is evidence the signal is phylogenetically coherent rather than carried by
one organism.
