Reference
Vector helpers
Vector helpers are evaluated once per group on whole columns. Use them as mutate(), filter(), and summarize() arguments. They follow R’s NA rules: a summary returns NA when its input has an NA unless naRm: true, ranks keep NA, and cumulative functions stay NA after the first NA.
The first argument is the input column. A string there is a column name. It can also be col('x'), another helper, or a row closure. Later arguments are values. ->map(fn ($value, $r) => ...) transforms a helper’s result row by row.
Summaries
| Helper | Value |
|---|---|
n() |
Rows in the group |
n_distinct('x', 'y') |
Distinct values or combinations |
sum, mean, median |
As in R |
sd, var_ (alias variance) |
Sample statistics (n − 1) |
quantile('x', 0.9), iqr('x') |
Type 7 quantiles, R’s default |
min, max |
Smallest and largest values |
first, last, nth('x', 2) |
Values by position, with default: |
any, all |
Logical summaries with NA logic |
With the phit extension loaded, mean, sd, var_, median, and quantile use it. Without it, they run in PHP. The test suite checks both against R.
Window functions
| Helper | Value |
|---|---|
lag('x', n:, default:, orderBy:), lead(...) |
Shifted values |
row_number(), row_number('x') |
Row numbers, or ranks with ties broken by position |
min_rank, dense_rank |
Ranks; wrap the column in desc() to reverse |
percent_rank, cume_dist |
Ranks scaled to [0, 1] |
ntile('x', 4) |
Buckets of near-equal size |
cumsum, cumprod, cummin, cummax, cummean |
Running values |
cumall, cumany |
Running logical values |
consecutive_id('x') |
A new id each time the value changes |
order_by('t', cumsum('x')) |
A window function evaluated in another order |
echo DataFrame::fromCsv('schools.csv') |>
filter(fn ($r) => $r->school === 'school-01') |>
arrange('study_hours') |>
mutate(
prev: lag('score'),
change: lag('score')->map(fn ($prev, $r) => $prev === null ? null : round($r->score - $prev, 2)),
running_mean: cummean('score'),
rank: min_rank(desc('score')),
pct: percent_rank('score'),
quartile: ntile('score', 4),
) |>
select('study_hours', 'score', 'prev', 'change', 'running_mean', 'rank', 'pct', 'quartile') |>
head(8);echo phplyr(DataFrame::fromCsv('schools.csv'))
->filter(fn ($r) => $r->school === 'school-01')
->arrange('study_hours')
->mutate(
prev: lag('score'),
change: lag('score')->map(fn ($prev, $r) => $prev === null ? null : round($r->score - $prev, 2)),
running_mean: cummean('score'),
rank: min_rank(desc('score')),
pct: percent_rank('score'),
quartile: ntile('score', 4),
)
->select('study_hours', 'score', 'prev', 'change', 'running_mean', 'rank', 'pct', 'quartile')
->head(8);# A tibble: 8 × 8
study_hours score prev change running_mean rank pct quartile
<dbl> <dbl> <dbl> <dbl> <dbl> <int> <dbl> <int>
1 1.31 63.7 NA NA 63.7 15 0.176 1
2 2.7 67.2 63.7 3.54 65.5 14 0.235 1
3 2.74 60.4 67.2 -6.89 63.8 17 0.0588 1
4 3.71 68.5 60.4 8.19 65.0 13 0.294 2
5 4.38 60.1 68.5 -8.41 64.0 18 0 1
6 4.89 72.8 60.1 12.6 65.5 9 0.529 2
7 5.21 69.7 72.8 -3.09 66.1 12 0.353 2
8 5.51 72.1 69.7 2.48 66.8 10 0.471 2
Conditionals and NA
| Helper | Use |
|---|---|
if_else(cond, yes, no, missing:) |
Vectorized if/else |
case_when([cond, value], ..., default:) |
The first true condition wins |
replace_when('x', [cond, value], ...) |
case_when() that keeps x where nothing matches |
recode_values('x', [from, to], ..., default:) |
Map values; also from: / to: lookup lists |
replace_values('x', [from, to], ...) |
recode_values() that keeps unmatched values |
case_match('x', [from, to], ..., default:) |
dplyr’s deprecated form of recode_values() |
recode('x', a: 'A', _default:, _missing:) |
dplyr’s superseded recoder, matching values by name |
when_any(...), when_all(...) |
Elementwise OR and AND across conditions |
coalesce('x', 0) |
The first non-NA value |
na_if('x', value) |
NA where x equals the value |
between('x', lo, hi) |
Inclusive range test |
near('x', y) |
Equality within floating-point tolerance |
echo DataFrame::fromRows([
['state' => 'NC', 'visits' => 3],
['state' => 'NYC', 'visits' => null],
['state' => 'CA', 'visits' => 12],
['state' => null, 'visits' => 0],
]) |>
mutate(
name: recode_values('state', ['NC', 'North Carolina'], [['NY', 'NYC'], 'New York'], default: 'other'),
visits: coalesce('visits', 0),
busy: if_else(fn ($r) => $r->visits > 5, 'yes', 'no'),
capped: replace_when('visits', [fn ($r) => $r->visits > 10, 10]),
any_flag: when_any(fn ($r) => $r->state === 'CA', fn ($r) => $r->visits === 0),
);echo phplyr(DataFrame::fromRows([
['state' => 'NC', 'visits' => 3],
['state' => 'NYC', 'visits' => null],
['state' => 'CA', 'visits' => 12],
['state' => null, 'visits' => 0],
]))
->mutate(
name: recode_values('state', ['NC', 'North Carolina'], [['NY', 'NYC'], 'New York'], default: 'other'),
visits: coalesce('visits', 0),
busy: if_else(fn ($r) => $r->visits > 5, 'yes', 'no'),
capped: replace_when('visits', [fn ($r) => $r->visits > 10, 10]),
any_flag: when_any(fn ($r) => $r->state === 'CA', fn ($r) => $r->visits === 0),
);# A tibble: 4 × 6
state visits name busy capped any_flag
<chr> <int> <chr> <chr> <int> <lgl>
1 NC 3 North Carolina no 3 FALSE
2 NYC 0 New York no 0 TRUE
3 CA 12 other yes 10 TRUE
4 <NA> 0 other no 0 TRUE
From phpstats/phplyr@d319dc5.