pgx
PGX — Lightweight Postgres for AI agents. Written in Rust. Thousands of isolated databases in one runtime. 🐘
Translation pending
Fits and compares representations of time-varying data against a prediction target. Given a table of targets and a table of time-stamped series belonging to them, it builds each candidate representati
Translation pending
DataR · PythonGitHub @gcol33OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Learn predictive representations of time-varying data (R package + Python twin)
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
timesift fits and compares representations of time-varying data against a prediction target.
Give it one row per thing to predict and a long table of time-stamped readings belonging to those
rows. It builds each candidate representation, fits the learners you name on every one they can
read, and scores them all on one set of held-out folds. Inside each training fold it chooses a
candidate and fits the stack's weights on an inner split, so the score it reports for the chosen
candidate and for the ensemble covers the choosing.Read the full README ↗choosing the time scale of a sensor record
timesift compares time scales to find which gives the best predictions from a sensor record. For example, you can use three years of hourly soil temperature to predict which plant species grow at a plot, and compare models trained on daily, weekly or monthly summaries.
A grain is the time interval used to summarise the readings, such as a day, week or month. timesift groups readings into these calendar intervals and calculates a summary, such as the mean, for each one. It fits each model at each compatible grain and evaluates them on the same held-out observations. You can compare their predictions, select a grain using the training data, or combine predictions from several models in an ensemble.
timesift lets you:
lookback()
to summarise a period ending at each observation date.tss_inflation()
estimates this bias for your design, while
implied_skill()
helps interpret the reported score.The model implementations are based on published methods and tested against reference packages including glmnet, MASS, rpart, earth, mda, mgcv, nnet, maxnet and biomod2. R and Python are tested against the same stored results, so they produce identical binned arrays. Cite the timesift version to identify the implementations and defaults used in an analysis.
timesift needs R 4.1 or later. The CRAN release installs from a binary on Windows and macOS and needs no build tools there:
install.packages("timesift")
The development version compiles C++ code, so it needs a compiler:
| Operating system | Build tools |
|---|---|
| Windows | Rtools matching your R version |
| macOS | xcode-select --install |
| Debian / Ubuntu | r-base-dev |
Check that R finds them:
pkgbuild::has_build_tools(debug = TRUE)
Then install from GitHub:
# install.packages("pak")
pak::pak("gcol33/timesift")
The C++ code needs no system library: it uses only the C++ standard library, including its threads, and cpp11 headers at build time.
cnn(), rescnn() and mlp() run on
torch; every other learner runs without
it. torch is an R package plus the LibTorch library, which it downloads
once:
install.packages("torch")
torch::install_torch(timeout = 600)
Check that it loads, and whether it found a graphics processor:
torch::torch_is_installed()
torch::cuda_is_available() # NVIDIA
torch::backends_mps_is_available() # Apple Silicon
This installs the processor build on Windows and Linux and the Apple
Silicon build on macOS, where torch uses the graphics processor through
MPS. An NVIDIA graphics processor needs the CUDA build, set up in
Installing
torch.
train_control(device = "auto"), the default, takes a graphics
processor wherever torch finds one and the processor otherwise.
The Python package has wheels for Linux, Windows and macOS and needs Python 3.11 or later:
pip install timesift
# with the torch encoders, the grain contrasts and the plots
pip install "timesift[torch,contrasts,plot]"
On Linux the torch this installs carries CUDA; on Windows it runs on the processor only, and the CUDA build comes from PyTorch’s own index, also in Installing torch. Check it with:
python -c "import torch; print(torch.cuda.is_available())"
targets, with one row per sampling unit and
its responses, and series, with the time-stamped readings for
those units.timesift() with the response columns, the identifier shared
by both tables, the time column and the grains to compare.predict() for new sampling units.This example uses simulate_records() to generate a year of readings
from 150 sensors, sampled every three hours. The four responses depend
on seasonal values in the simulated record.
library(timesift)
sim <- simulate_records(n = 150, mechanism = "season", variables = 4,
prevalence = 0.3, auc = 0.9)
targets <- data.frame(unit = rownames(sim$y), sim$y)
fit <- timesift(targets, sim$readings, y = -unit, id = unit, time = time,
sift = grains("day", "week", "month", "season"))
fit
#> timesift 150 targets, 4 responses, 10-fold random CV, roc_auc
#>
#> candidates, scored on the outer folds
#> candidate mean won responses
#> elasticnet / day 0.553 0 separate
#> elasticnet / season 0.571 0 separate
#> elasticnet / week 0.612 0 separate
#> elasticnet / month 0.712 4 separate
#>
#> procedure, chosen and weighted inside each outer training fold
#> selected 0.712 se 0.077
#> ensemble 0.712 se 0.077
#> selected elasticnet / month in 10 of 10 folds
#>
#> choice on every target elasticnet / month
#> weights on every target elasticnet / month 1.00
targets contains one 0/1 column per response and the identifier, here
unit; series contains that identifier, a date-time column and the
values, one row per reading. y takes tidyselect expressions such as
starts_with("sp_"). A table with a missing reading in a bin is
refused, and coverage() shows which unit and bin lack readings.
A candidate is a model fitted at one grain. The default model is
elasticnet(). The candidate rows show how each pairing performed in
cross-validation: each fold is held out in turn for evaluation.
Selecting the highest score from these rows uses the evaluation data to
choose a candidate.
Use the selected and ensemble rows to report predictive performance.
For these rows, candidate selection and ensemble weighting happen within
each training fold. The held-out fold then evaluates the resulting
predictions.
predict(fit, new_targets, new_series) summarises the new readings at
each required grain and predicts with the ensemble trained on all
targets. Use type = "binary" to convert predicted probabilities to
presence or absence. The threshold for each response is estimated from
out-of-fold predictions.
The same run in Python:
import timesift as ts
sim = ts.simulate_records(n=150, mechanism="season", variables=4,
prevalence=0.3, auc=0.9)
targets = {"unit": sim.y.units}
targets.update(zip(sim.y.variables, sim.y.values.T))
fit = ts.timesift(targets, sim.readings, y=list(sim.y.variables),
id="unit", time="time",
sift=ts.grains("day", "week", "month", "season"))
print(fit)
grains("day", "week", "month") names a set of grains to compare, and
grains("auto") takes every named grain that gives the record at least
two bins. A learner runs across the whole set, or at one grain when it
is given one, as in cnn(data = grain("week")).
Bins follow the calendar: months have 28 to 31 days, and weeks start on
Monday. year_start sets the start of the year, for example for a
hydrological year. You can define a custom calendar with a function of
the reading times, such as seasons beginning at the equinoxes.
min and max give the lowest and highest individual reading in each
bin. cold_day and warm_day first calculate daily means, then return
the lowest and highest daily mean within the bin.
grain_matrix() and lookback_matrix() return the binned arrays,
[unit, bin, channel], without fitting anything. Representing a
record
covers every grain and statistic.
grain_ladder() fits one learner at every grain and shows where skill
levels off. grain_contrasts() compares every grain with a learner’s
best one, and paired_contrast() compares two candidates on matched
cells. select_grain() chooses the grain inside the training data and
scores the whole procedure. Finding the
grain
runs them on a record with a known answer.
ensemble() stacks the candidates with non-negative weights summing to
one, fitted on their out-of-fold predictions alone. project() maps a
fit onto rasters and range_change() compares two projections.
Ensembles, thresholds and
maps goes
from a scored run to maps.
The true skill statistic (TSS) is overestimated when the threshold is chosen to maximise TSS on the same held-out observations used to report the score. The fewer presences there are in the held-out data, the more TSS tends to overestimate population skill. For the sampling design of the Schrankogel study, a record of hourly soil temperature from alpine plots, the estimated inflation is 0.110 on average when the true skill is 0.60.
tss_inflation() estimates the TSS that a given sampling design would
report for a known population skill. implied_skill() reverses this
calculation: given a reported TSS, it estimates the population skill
that would yield that score on average under the same sampling design
and assumed prediction distribution. This simulation-based matching
follows the principle of indirect inference (Gouriéroux et al.,
1993).
By default, runs are scored by the area under the receiver operating
characteristic curve (AUC), with TSS also reported. Scores, thresholds
and their
inflation
works through both functions.
Start with Choosing how a record is read: one path from two tables to a scored comparison and predictions. Every code block has an R and a Python version, and the Python view of Get started opens with Python selected.
Questions and bug reports go to the issue tracker. With a bug report, include a small reproducible example made with reprex.
Building from a checkout, the test suites and the rules for the shared fixtures are in CONTRIBUTING.md.
“Software is like sex: it’s better when it’s free.” — Linus Torvalds
I’m a PhD student who builds R packages in my free time because I believe good tools should be free and open. I started these projects for my own work and figured others might find them useful too.
If this package saved you some time, buying me a coffee is a nice way to say thanks. It helps with my coffee addiction.
timesift is licensed under MIT (see the LICENSE file).
To cite timesift in publications use:
Colling G (2026). _timesift: Learn Predictive Representations of
Time-Varying Data_. doi:10.32614/CRAN.package.timesift
<https://doi.org/10.32614/CRAN.package.timesift>. R package version
0.6.0, <https://gillescolling.com/timesift/>.
BibTeX:
@Manual{colling2026timesift,
title = {timesift: Learn Predictive Representations of Time-Varying Data},
author = {Gilles Colling},
year = {2026},
note = {R package version 0.6.0},
doi = {10.32614/CRAN.package.timesift},
url = {https://gillescolling.com/timesift/},
}