Skip to content

datajure 2.6.0

Latest

Choose a tag to compare

@buehlmaier buehlmaier released this 20 Jun 15:47

Changed

  • Faster moving-window ops (win/mavg/msum/mdev/mdowndev/mmin/mmax). The rolling engine now realises the column once into a primitive double[] + a present-mask and computes each trailing window with primitive arithmetic — no per-window vector allocation or boxing (the previous hot path boxed every value in every window). Results are identical (same nil/NaN/±Inf and :min-periods/:ddof semantics). On a real 2.1M-row × 45k-firm transform (40 moving averages) the window computation dropped ~3× (21 s → 7 s) and the full :set :by pass ~2.1× (27 s → 13 s).
  • BREAKING: :set + :by window mode now preserves input row order. Previously a window-mode :set with :by returned rows reordered into grouped + :within-order-sorted blocks (an artifact of the per-group split + concat). Now the output keeps the original input row order — passthrough columns are untouched and each derivation's per-group results are scattered back to their original positions. :within-order consequently governs only the per-group computation order (so win/lag/win/cumsum/etc. walk in the right order within a group), not the output order; use :order-by to sort output. Both the fast and general :by paths agree. (Window-mode :set without :by is unchanged — it still sorts by :within-order.)

Added

  • prepare-grouping + the :grouping option — amortise grouping across multi-pass :set :by. (prepare-grouping ds [:gvkey] [(asc :datadate)]) computes the grouping + within-order permutation once; pass the result as :grouping to dt (in place of :by/:within-order) and many :set passes reuse it, skipping the per-call grouping + sort. Valid for any dataset with the same rows in the same order (adding columns between passes is fine, since :set :by preserves input row order); dt checks the row count and rejects :grouping alongside :by/:within-order. On a real 2.1M-row × 45k-firm 10-pass transform the grouping was the per-pass bottleneck once the window compute was sped up — reusing it dropped the run from 48.6 s to 18.4 s (~2.6×), identical results. Like coalesce, but skips NaN and ±Inf as well as nil, returning the first finite value (#dt/e (coalesce-finite :a :b 0.0)). This is the right primitive for fallback chains over computed columns, where an arithmetic step can yield NaN/±Inf (e.g. (+ x nil)NaN) that plain coalesce would treat as present — previously expressed verbosely as (coalesce (nonfin2na :a) (nonfin2na :b) …). Non-numeric and non-finite arguments count as absent; if no argument is finite the result is nil. A #dt/e special form like coalesce, so it's also element-wise (works in off-heap :set :by).
  • win/lag / win/lead :fill option. A trailing options map fills the boundary positions (those without enough history/future) with a given value: #dt/e (win/lag :price 1 {:fill 0})[0 …] instead of [nil …]. Collapses the common (coalesce (win/lag …) 0) two-step into one op. Source nils that get shifted stay nil; default (no map) is unchanged.
  • win/ema accepts an options map. Alongside the numeric shorthand (>= 1 → period, < 1 → smoothing factor alpha), win/ema now takes {:alpha 0.18} or {:period 10} — a self-documenting alternative that makes the alpha-vs-period intent explicit at the call site. Same results as the equivalent numeric form.