## trend_test()


Test for linear trend across ordered groups using the log-rank test family.


Usage

``` python
trend_test(
    surv,
    group,
    *,
    scores=None,
    rho=0.0,
    gamma=0.0,
    strata=None,
)
```


A trend test is a one-degree-of-freedom test for whether survival changes linearly across ordered groups (e.g., disease stages I, II, III, IV or dose levels: low, medium, high). It's more powerful than the multi-degree-of-freedom log-rank test when groups are naturally ordered.

The test assigns numeric scores to each group (default: 0, 1, 2, … for sorted order) and tests whether a linear relationship exists between group score and survival. It can be combined with Fleming-Harrington weights and stratification, just like [logrank_test](logrank_test.md#greenwood.logrank_test).

**When to use trend tests**: Use when groups are naturally ordered and you want a higher-power test for a linear trend, rather than testing all possible differences. For exploratory analysis without assuming order, use [logrank_test](logrank_test.md#greenwood.logrank_test) instead.


## Parameters


`surv: Surv`  
A [Surv](Surv.md#greenwood.Surv) response object representing censored survival times. Supports right-censored data or counting-process format.

`group: Any`  
Group labels (typically ordered categories like 0, 1, 2, 3 for dose levels or stages). Can be a Narwhals series, 1-D array, or Python sequence. Must have at least 2 groups. Must have the same length as `surv`.

`scores: Array | None = None`  
Numeric scores assigned to each group to define the linear trend. If `None` (default), groups are sorted lexicographically and assigned scores 0, 1, 2, …, (k-1) where k is the number of groups. Provide custom scores as a dictionary mapping group labels to numeric values (e.g., `{1: 0, 2: 1, 3: 2}` for stage labels 1,2,3) to use different scoring (e.g., unequal spacing). Scores can be any real numbers (including negative).

`rho: float = ``0.0`  
Fleming-Harrington weight exponent applied to the pooled survival probability. The default of `0` gives a standard trend test with equal weight across all times.

`gamma: float = ``0.0`  
Fleming-Harrington weight exponent applied to (1 - pooled survival probability). The default of `0`; combined with `rho=1` gives Peto-Peto (Wilcoxon) trend test emphasizing early events. See [logrank_test](logrank_test.md#greenwood.logrank_test) for more details on Fleming-Harrington weighting.

`strata: Any = None`  
Optional stratifying factor. When provided, the trend test is computed separately within each stratum, then combined (stratified trend test). Use to control for confounding while testing a linear trend.


## Returns


`TestResult`  
A result object with attributes:

- `statistic`: chi-square test statistic (always 1 degree of freedom).
- `df`: always `1` for trend tests.
- `p_value`: upper-tail chi-square p-value.
- `method`: description of the test, e.g., "Linear trend test", "Stratified linear trend test", "G-rho trend test (rho=1, gamma=0)".
- `observed`: dictionary mapping each group to observed event count (unweighted).
- `expected`: dictionary mapping each group to expected event count under null.


## Details

The test uses a linear contrast with assigned scores:

- \\U = \sum_i \text{score}\[i\] \cdot (O\[i\] - E\[i\])\\
- \\V = \sum_i \text{score}\[i\]^2 \cdot \text{Var}\[i\]\\
- \\\chi^2 = U^2 / V \sim \chi^2(1)\\

This is equivalent to fitting a Cox model with group encoded as the numeric score and testing whether the coefficient is zero using a score test.


## Examples

Test for linear trend in survival across ordered cell types:


``` python
import greenwood as gw

vet = gw.load_dataset("veteran", backend="polars")
y = gw.Surv.right(vet["time"], event=vet["status"])

# Default: cell types are sorted and assigned scores 0,1,2,3
result = gw.trend_test(y, group=vet["celltype"])
result
```


    TestResult(method='Linear trend test', statistic=2.3681, df=1, p_value=0.1238)


Use custom scores to give different weight to cell type severity:


``` python
# Scores: adeno and large are low-risk (0,1), smallcell and squamous are high-risk (3,4)
scores = {"adeno": 0, "large": 1, "smallcell": 3, "squamous": 4}
gw.trend_test(y, group=vet["celltype"], scores=scores)
```


    TestResult(method='Linear trend test', statistic=1.4479, df=1, p_value=0.2289)


Use Peto-Peto weighting to emphasize early differences:


``` python
# Peto-Peto: rho=1 gives more weight to early event times
gw.trend_test(y, group=vet["celltype"], rho=1, gamma=0)
```


    TestResult(method='G-rho trend test (rho=1, gamma=0)', statistic=0.6858, df=1, p_value=0.4076)


Use Tarone-Ware weighting to emphasize late differences (gamma=1):


``` python
# Tarone-Ware: gamma=1 gives more weight to late event times
gw.trend_test(y, group=vet["celltype"], rho=0, gamma=1)
```


    TestResult(method='G-rho trend test (rho=0, gamma=1)', statistic=3.7526, df=1, p_value=0.05273)


Stratified by treatment to control for treatment effects:


``` python
gw.trend_test(y, group=vet["celltype"], strata=vet["trt"])
```


    TestResult(method='Stratified linear trend test', statistic=1.7525, df=1, p_value=0.1856)
