✅ Complete
+
+
+
Insert and remove DataFrame columns at precise positions. insertColumn(df, loc, col, values) inserts at integer position, popColumn(df, col) returns { series, df }. Also includes reorderColumns and moveColumn. Mirrors pandas.DataFrame.insert() and .pop().
+
✅ Complete
+
+
+
+
Bin continuous numeric data into discrete intervals. cut() uses fixed-width or explicit bin edges; qcut() uses quantile-based bins of equal population. Both return codes, labels, and bin edges. Mirrors pandas.cut and pandas.qcut.
+
✅ Complete
+
+
+
+
Higher-order rolling window statistics: rollingSem (standard error of mean), rollingSkew (Fisher-Pearson skewness), rollingKurt (excess kurtosis), and rollingQuantile (arbitrary percentile with 5 interpolation methods). Mirrors pandas.Series.rolling().sem/skew/kurt/quantile().
+
✅ Complete
+
+
+
+
Standalone custom rolling-window functions: rollingApply (custom fn per window), rollingAgg (multiple named aggregations → DataFrame), dataFrameRollingApply, dataFrameRollingAgg. Supports minPeriods, center, and raw mode. Mirrors pandas.Rolling.apply() and Rolling.agg().
+
✅ Complete
+
+
+
+
Element-wise conditional selection: seriesWhere / seriesMask and dataFrameWhere / dataFrameMask. Accepts boolean arrays, label-aligned boolean Series/DataFrame, or callables. Mirrors pandas.Series.where, pandas.DataFrame.where, and their .mask() inverses.
+
✅ Complete
+
+
+
+
Module-level missing-value detection: isna, notna, isnull, notnull work on scalars, arrays, Series, and DataFrames. Plus standalone fillna, dropna, countna, and countValid. Mirrors pandas.isna, pandas.notna, pandas.isnull, pandas.notnull.
+
✅ Complete
+
+
+
+
Attach arbitrary key→value metadata to any Series or DataFrame via a WeakMap registry. Provides getAttrs, setAttrs, updateAttrs, copyAttrs, withAttrs, mergeAttrs, clearAttrs, getAttr, setAttr, deleteAttr, attrsCount, attrsKeys. Mirrors pandas.DataFrame.attrs / pandas.Series.attrs.
+
✅ Complete
+
+
+
+
Module-level string utilities: strNormalize (Unicode NFC/NFD/NFKC/NFKD), strGetDummies (one-hot DataFrame), strExtractAll (all regex matches), strRemovePrefix, strRemoveSuffix, strTranslate (char-level substitution), strCharWidth (CJK-aware display width), strByteLength. Works on Series, arrays, or scalars.
+
✅ Complete
+
+
+
+
Advanced string utilities: strSplitExpand (split → DataFrame columns), strExtractGroups (regex capture groups → DataFrame), strPartition / strRPartition (split into before/sep/after), strMultiReplace (batch replacements), strIndent / strDedent (line-level indentation). Works on Series, arrays, or scalars.
+
✅ Complete
+
+
+
+
Standalone equivalents of pandas' pipe() / apply() / applymap(): pipe (variadic type-safe pipeline), seriesApply (element-wise with label/pos context), seriesTransform, dataFrameApply (axis 0/1), dataFrameApplyMap (cell-wise), dataFrameTransform (column-wise), dataFrameTransformRows (row-wise).
+
✅ Complete
+
+
+
+
numpy/scipy-style numeric utilities: digitize (bin values), histogram (frequency counts with density option), linspace / arange (number sequences), percentileOfScore (percentile rank of a score), zscore (z-score standardisation), minMaxNormalize (scale to [0,1] or custom range), coefficientOfVariation (std/mean). Series-aware variants included.
+
✅ Complete
+
+
+
+
+
+
Standalone categorical helpers: catFromCodes (from integer codes), set operations (catUnionCategories, catIntersectCategories, catDiffCategories, catEqualCategories), catSortByFreq, catToOrdinal, catFreqTable, catCrossTab, catRecode.
+
✅ Complete
+
+
+
+
+
+
Number-formatting helpers for Series and DataFrame. Scalar formatters: formatFloat, formatPercent, formatScientific, formatEngineering, formatThousands, formatCurrency, formatCompact. Formatter factories: makeFloatFormatter, makePercentFormatter, makeCurrencyFormatter. Apply to collections: applySeriesFormatter, applyDataFrameFormatter. Render to string: seriesToString, dataFrameToString.
+
✅ Complete
+
+
+
+
+
+ Performance
+
+
+
+
Side-by-side performance comparison of tsb (TypeScript/Bun) vs pandas (Python). Timing metrics for each function.
+
🏗️ In Progress
+
diff --git a/playground/pct_change.html b/playground/pct_change.html
index 3576797a..ec1b4e3b 100644
--- a/playground/pct_change.html
+++ b/playground/pct_change.html
@@ -288,8 +288,10 @@ 3 · Handling missing values
prices = pd.Series([100, None, None, 130])
-with_fill = prices.pct_change(fill_method="pad")
-no_fill = prices.pct_change(fill_method=None)
+# In pandas 3.x, fill_method was removed from pct_change.
+# Use fillna + pct_change instead.
+with_fill = prices.ffill().pct_change()
+no_fill = prices.pct_change()
print("pad-fill: ", with_fill.tolist())
print("no fill: ", no_fill.tolist())
@@ -327,7 +329,9 @@ 4 · Limit consecutive fills
# 1-gap: filled; 2-gap: not filled (exceeds limit=1)
data = pd.Series([100, None, 110, None, None, 130])
-limited = data.pct_change(fill_method="pad", limit=1)
+# In pandas 3.x, fill_method/limit were removed from pct_change.
+# Use fillna with limit before pct_change instead.
+limited = data.ffill(limit=1).pct_change()
print("input: ", data.tolist())
print("limited: ", limited.tolist())
@@ -408,7 +412,7 @@ 6 · Negative periods (look-forward change)
# If you buy today, what return do you get in the next 2 days?
prices = pd.Series([100, 105, 98, 110, 115])
-fwd2 = prices.pct_change(periods=-2, fill_method=None)
+fwd2 = prices.pct_change(periods=-2)
print("prices: ", prices.tolist())
print("2-day fwd rtn: ", fwd2.tolist())
diff --git a/src/index.ts b/src/index.ts
index 9fdf097a..22723aa2 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -3,6 +3,7 @@
*
* @packageDocumentation
*/
+// merged: 2026-04-09T19:37Z (re-merge main into PR branch, barrel-export conflicts resolved by keeping PR superset)
// Core exports will be added here as features are implemented.
// Each module is imported and re-exported from its feature file in src/.
@@ -45,12 +46,16 @@ export { DatetimeAccessor } from "./core/index.ts";
export type { DatetimeSeriesLike } from "./core/index.ts";
export { DataFrameGroupBy, SeriesGroupBy } from "./groupby/index.ts";
export type { AggFn, AggName, AggSpec } from "./groupby/index.ts";
+export { NamedAgg, namedAgg, isNamedAggSpec } from "./groupby/index.ts";
+export type { NamedAggSpec } from "./groupby/index.ts";
export { describe, quantile } from "./stats/index.ts";
export type { DescribeOptions } from "./stats/index.ts";
export { readCsv, toCsv } from "./io/index.ts";
export type { ReadCsvOptions, ToCsvOptions } from "./io/index.ts";
export { readJson, toJson } from "./io/index.ts";
export type { ReadJsonOptions, ToJsonOptions, JsonOrient } from "./io/index.ts";
+export { jsonNormalize } from "./io/index.ts";
+export type { JsonNormalizeOptions, JsonPath } from "./io/index.ts";
export { pearsonCorr, dataFrameCorr, dataFrameCov } from "./stats/index.ts";
export type { CorrMethod, CorrOptions, CovOptions } from "./stats/index.ts";
export { Rolling } from "./window/index.ts";
@@ -61,6 +66,13 @@ export type { ExpandingOptions, ExpandingSeriesLike } from "./window/index.ts";
export { DataFrameExpanding } from "./core/index.ts";
export { EWM } from "./window/index.ts";
export type { EwmOptions, EwmSeriesLike } from "./window/index.ts";
+export {
+ rollingApply,
+ rollingAgg,
+ dataFrameRollingApply,
+ dataFrameRollingAgg,
+} from "./window/index.ts";
+export type { RollingApplyOptions, RollingAggOptions, AggFunctions } from "./window/index.ts";
export { DataFrameEwm } from "./core/index.ts";
export { CategoricalAccessor } from "./core/index.ts";
export type { CatSeriesLike } from "./core/index.ts";
@@ -74,6 +86,10 @@ export type {
} from "./reshape/index.ts";
export { stack, unstack, STACK_DEFAULT_SEP } from "./reshape/index.ts";
export type { StackOptions, UnstackOptions } from "./reshape/index.ts";
+export { wideToLong } from "./reshape/index.ts";
+export type { WideToLongOptions } from "./reshape/index.ts";
+export { pivotTableFull } from "./reshape/index.ts";
+export type { PivotTableFullOptions } from "./reshape/index.ts";
export { MultiIndex } from "./core/index.ts";
export type { MultiIndexOptions } from "./core/index.ts";
export { rankSeries, rankDataFrame } from "./stats/index.ts";
@@ -107,20 +123,418 @@ export {
export type { ClipOptions, RoundOptions, DataFrameElemOptions } from "./stats/index.ts";
export { valueCounts, dataFrameValueCounts } from "./stats/index.ts";
export type { ValueCountsOptions, DataFrameValueCountsOptions } from "./stats/index.ts";
+export { whereSeries, maskSeries, whereDataFrame, maskDataFrame } from "./stats/index.ts";
+export type {
+ WherePredicate,
+ SeriesCond,
+ DataFrameCond,
+ WhereMaskOptions,
+} from "./stats/index.ts";
export {
- isna,
- notna,
- isnull,
- notnull,
- ffillSeries,
- bfillSeries,
- dataFrameFfill,
- dataFrameBfill,
+ seriesEq,
+ seriesNe,
+ seriesLt,
+ seriesGt,
+ seriesLe,
+ seriesGe,
+ dataFrameEq,
+ dataFrameNe,
+ dataFrameLt,
+ dataFrameGt,
+ dataFrameLe,
+ dataFrameGe,
+} from "./stats/index.ts";
+export type { CompareOp, SeriesOther, DataFrameOther } from "./stats/index.ts";
+export { shiftSeries, diffSeries, dataFrameShift, dataFrameDiff } from "./stats/index.ts";
+export type { ShiftDiffDataFrameOptions } from "./stats/index.ts";
+export { interpolateSeries, dataFrameInterpolate } from "./stats/index.ts";
+export type {
+ InterpolateMethod,
+ LimitDirection,
+ InterpolateOptions,
+ DataFrameInterpolateOptions,
+} from "./stats/index.ts";
+export { fillnaSeries, fillnaDataFrame } from "./stats/index.ts";
+export type {
+ FillnaMethod,
+ FillnaSeriesOptions,
+ ColumnFillMap,
+ FillnaDataFrameOptions,
+} from "./stats/index.ts";
+export { Interval, IntervalIndex } from "./core/index.ts";
+export type { IntervalClosed, IntervalIndexOptions } from "./core/index.ts";
+export { cut, qcut, cutIntervalIndex, qcutIntervalIndex } from "./stats/index.ts";
+export type { CutOptions, QCutOptions } from "./stats/index.ts";
+export { sampleSeries, sampleDataFrame } from "./stats/index.ts";
+export type { SampleSeriesOptions, SampleDataFrameOptions } from "./stats/index.ts";
+export { applySeries, applymap, dataFrameApply } from "./stats/index.ts";
+export type { DataFrameApplyOptions } from "./stats/index.ts";
+export { CategoricalIndex } from "./core/index.ts";
+export type { CategoricalIndexOptions } from "./core/index.ts";
+export {
+ pipeSeries,
+ dataFramePipe,
+ pipeTo,
+ dataFramePipeTo,
+ pipeChain,
+ dataFramePipeChain,
+} from "./stats/index.ts";
+
+export { Period, PeriodIndex } from "./core/index.ts";
+export type { PeriodFreq, PeriodIndexOptions } from "./core/index.ts";
+export { Timedelta, TimedeltaIndex } from "./core/index.ts";
+export type { TimedeltaComponents, TimedeltaIndexOptions } from "./core/index.ts";
+export {
+ Day,
+ Hour,
+ Minute,
+ Second,
+ Milli,
+ Week,
+ MonthEnd,
+ MonthBegin,
+ YearEnd,
+ YearBegin,
+ BusinessDay,
+} from "./core/index.ts";
+export type { DateOffset, WeekOptions } from "./core/index.ts";
+export { DatetimeIndex, date_range, bdate_range, resolveFreq } from "./core/index.ts";
+export type { DateRangeFreq, DateRangeOptions, DatetimeIndexOptions } from "./core/index.ts";
+export { TZDatetimeIndex, tz_localize, tz_convert } from "./core/index.ts";
+export {
+ seriesFloor,
+ dataFrameFloor,
+ seriesCeil,
+ dataFrameCeil,
+ seriesTrunc,
+ dataFrameTrunc,
+ seriesSqrt,
+ dataFrameSqrt,
+ seriesExp,
+ dataFrameExp,
+ seriesLog,
+ dataFrameLog,
+ seriesLog2,
+ dataFrameLog2,
+ seriesLog10,
+ dataFrameLog10,
+ seriesSign,
+ dataFrameSign,
+} from "./stats/index.ts";
+export {
+ seriesPow,
+ dataFramePow,
+ seriesMod,
+ dataFrameMod,
+ seriesFloorDiv,
+ dataFrameFloorDiv,
+} from "./stats/index.ts";
+export {
+ seriesAdd,
+ seriesRadd,
+ seriesSub,
+ seriesRsub,
+ seriesMul,
+ seriesRmul,
+ seriesDiv,
+ seriesRdiv,
+ dataFrameAdd,
+ dataFrameRadd,
+ dataFrameSub,
+ dataFrameRsub,
+ dataFrameMul,
+ dataFrameRmul,
+ dataFrameDiv,
+ dataFrameRdiv,
+} from "./stats/index.ts";
+export { getDummies, dataFrameGetDummies } from "./stats/index.ts";
+export type { GetDummiesOptions, DataFrameGetDummiesOptions } from "./stats/index.ts";
+export { factorize, seriesFactorize } from "./stats/index.ts";
+export type { FactorizeOptions, FactorizeResult } from "./stats/index.ts";
+export { crosstab, seriesCrosstab } from "./stats/index.ts";
+export type { AggFunc, Normalize, CrosstabOptions } from "./stats/index.ts";
+export { toNumeric, toNumericArray, toNumericScalar, toNumericSeries } from "./stats/index.ts";
+export type { ToNumericDowncast, ToNumericErrors, ToNumericOptions } from "./stats/index.ts";
+export { seriesMemoryUsage, dataFrameMemoryUsage } from "./stats/index.ts";
+export type { MemoryUsageOptions } from "./stats/index.ts";
+export { selectDtypes } from "./stats/index.ts";
+export type { DtypeSelector, SelectDtypesOptions } from "./stats/index.ts";
+export { clipSeriesWithBounds, clipDataFrameWithBounds } from "./stats/index.ts";
+export type {
+ BoundArg,
+ SeriesClipBoundsOptions,
+ DataFrameClipBoundsOptions,
+} from "./stats/index.ts";
+export { Timestamp } from "./core/index.ts";
+export type { TimestampOptions, TimestampComponents, TimestampUnit } from "./core/index.ts";
+export { dataFrameAssign } from "./core/index.ts";
+export type { AssignColSpec, AssignSpec } from "./core/index.ts";
+export { inferDtype } from "./stats/index.ts";
+export type { InferredDtype, InferDtypeOptions } from "./stats/index.ts";
+export { isna, notna, isnull, notnull } from "./stats/index.ts";
+export { dropna, dropnaSeries, dropnaDataFrame } from "./stats/index.ts";
+export type { DropnaHow, DropnaDataFrameOptions } from "./stats/index.ts";
+export { combineFirstSeries, combineFirstDataFrame } from "./stats/index.ts";
+export { natCompare, natSorted, natSortKey, natArgSort } from "./core/index.ts";
+export type { NatSortOptions, NatSortedOptions } from "./core/index.ts";
+export { searchsorted, searchsortedMany, argsortScalars } from "./core/index.ts";
+export type { SearchSortedSide, SearchSortedOptions } from "./core/index.ts";
+export { valueCountsBinned } from "./stats/index.ts";
+export type { ValueCountsBinnedOptions } from "./stats/index.ts";
+
+export {
+ duplicatedSeries,
+ duplicatedDataFrame,
+ dropDuplicatesSeries,
+ dropDuplicatesDataFrame,
+} from "./stats/index.ts";
+export type {
+ KeepPolicy,
+ DuplicatedDataFrameOptions,
+ DuplicatedSeriesOptions,
+} from "./stats/index.ts";
+export { reindexSeries, reindexDataFrame } from "./core/index.ts";
+export type { ReindexMethod, ReindexSeriesOptions, ReindexDataFrameOptions } from "./core/index.ts";
+
+export { alignSeries, alignDataFrame } from "./core/index.ts";
+export type { AlignSeriesOptions, AlignDataFrameOptions } from "./core/index.ts";
+
+export { explodeSeries, explodeDataFrame } from "./stats/index.ts";
+export type { ExplodeOptions, ExplodeDataFrameOptions } from "./stats/index.ts";
+
+export { isin, dataFrameIsin } from "./stats/index.ts";
+export type { IsinValues, IsinDict, DataFrameIsinValues } from "./stats/index.ts";
+
+export {
+ insertColumn,
+ popColumn,
+ reorderColumns,
+ moveColumn,
+ dataFrameFromPairs,
+} from "./core/index.ts";
+export type { PopResult } from "./core/index.ts";
+export { toDictOriented, fromDictOriented } from "./core/index.ts";
+export type {
+ ToDictOrient,
+ FromDictOrient,
+ DictSplit,
+ DictTight,
+ SplitInput,
+} from "./core/index.ts";
+export { rollingSem, rollingSkew, rollingKurt, rollingQuantile } from "./stats/index.ts";
+export type { WindowExtOptions, RollingQuantileOptions } from "./stats/index.ts";
+export { fillna, countna, countValid } from "./stats/index.ts";
+export type { IsnaInput, FillnaOptions, DropnaOptions } from "./stats/index.ts";
+export {
+ getAttrs,
+ setAttrs,
+ updateAttrs,
+ copyAttrs,
+ withAttrs,
+ clearAttrs,
+ hasAttrs,
+ getAttr,
+ setAttr,
+ deleteAttr,
+ attrsCount,
+ attrsKeys,
+ mergeAttrs,
+} from "./core/index.ts";
+export type { Attrs } from "./core/index.ts";
+export {
+ pipe,
+ seriesApply,
+ seriesTransform,
+ dataFrameApplyMap,
+ dataFrameTransform,
+ dataFrameTransformRows,
+} from "./core/index.ts";
+export {
+ isScalar,
+ isListLike,
+ isArrayLike,
+ isDictLike,
+ isIterator,
+ isNumber,
+ isBool,
+ isStringValue,
+ isFloat,
+ isInteger,
+ isBigInt,
+ isRegExp,
+ isReCompilable,
+ isMissing,
+ isHashable,
+ isDate,
+ isNumericDtype,
+ isIntegerDtype,
+ isSignedIntegerDtype,
+ isUnsignedIntegerDtype,
+ isFloatDtype,
+ isBoolDtype,
+ isStringDtype,
+ isDatetimeDtype,
+ isTimedeltaDtype,
+ isCategoricalDtype,
+ isObjectDtype,
+ isComplexDtype,
+ isExtensionArrayDtype,
+ isPeriodDtype,
+ isIntervalDtype,
+} from "./core/index.ts";
+export {
+ strNormalize,
+ strGetDummies,
+ strExtractAll,
+ strRemovePrefix,
+ strRemoveSuffix,
+ strTranslate,
+ strCharWidth,
+ strByteLength,
+ strSplitExpand,
+ strExtractGroups,
+ strPartition,
+ strRPartition,
+ strMultiReplace,
+ strIndent,
+ strDedent,
+} from "./stats/index.ts";
+export type {
+ NormalizeForm,
+ StrInput,
+ ExtractAllOptions,
+ SplitExpandOptions,
+ ExtractGroupsOptions,
+ PartitionResult,
+ ReplacePair,
+ IndentOptions,
+} from "./stats/index.ts";
+export {
+ digitize,
+ histogram,
+ linspace,
+ arange,
+ percentileOfScore,
+ zscore,
+ minMaxNormalize,
+ coefficientOfVariation,
+ seriesDigitize,
+} from "./stats/index.ts";
+export type {
+ HistogramOptions,
+ HistogramResult,
+ ZscoreOptions,
+ MinMaxOptions,
+ CvOptions,
+} from "./stats/index.ts";
+export {
+ catFromCodes,
+ catUnionCategories,
+ catIntersectCategories,
+ catDiffCategories,
+ catEqualCategories,
+ catSortByFreq,
+ catToOrdinal,
+ catFreqTable,
+ catCrossTab,
+ catRecode,
+} from "./stats/index.ts";
+export type {
+ CatFromCodesOptions,
+ CatSortByFreqOptions,
+ CatCrossTabOptions,
+} from "./stats/index.ts";
+export {
+ formatFloat,
+ formatPercent,
+ formatScientific,
+ formatEngineering,
+ formatThousands,
+ formatCurrency,
+ formatCompact,
+ makeFloatFormatter,
+ makePercentFormatter,
+ makeCurrencyFormatter,
+ applySeriesFormatter,
+ applyDataFrameFormatter,
+ seriesToString,
+ dataFrameToString,
+} from "./stats/index.ts";
+export type {
+ Formatter,
+ SeriesToStringOptions,
+ DataFrameToStringOptions,
+} from "./stats/index.ts";
+
+// PR #120 unique modules — re-exported from sub-barrels
+export { astypeSeries, astype, castScalar } from "./core/index.ts";
+export type { AstypeOptions, DataFrameAstypeOptions } from "./core/index.ts";
+// readExcel / xlsxSheetNames use node:zlib — import from "tsb/io/read_excel" directly
+export { clipAdvancedSeries, clipAdvancedDataFrame } from "./stats/index.ts";
+export type {
+ SeriesBound,
+ DataFrameBound,
+ ClipAdvancedSeriesOptions,
+ ClipAdvancedDataFrameOptions,
+} from "./stats/index.ts";
+export { idxminSeries, idxmaxSeries, idxminDataFrame, idxmaxDataFrame } from "./stats/index.ts";
+export type { IdxOptions, IdxDataFrameOptions } from "./stats/index.ts";
+export { modeSeries, modeDataFrame } from "./stats/index.ts";
+export type { ModeSeriesOptions, ModeDataFrameOptions } from "./stats/index.ts";
+export {
+ nancount,
+ nansum,
+ nanmean,
+ nanmedian,
+ nanvar,
+ nanstd,
+ nanmin,
+ nanmax,
+ nanprod,
+} from "./stats/index.ts";
+export type { NanInput, NanAggOptions } from "./stats/index.ts";
+export {
+ nuniqueSeries,
+ nuniqueDataFrame,
+ anySeries,
+ allSeries,
+ anyDataFrame,
+ allDataFrame,
+} from "./stats/index.ts";
+export type {
+ NuniqueSeriesOptions,
+ NuniqueDataFrameOptions,
+ AnyAllSeriesOptions,
+ AnyAllDataFrameOptions,
} from "./stats/index.ts";
-export type { FillDirectionOptions, DataFrameFillOptions } from "./stats/index.ts";
export { pctChangeSeries, pctChangeDataFrame } from "./stats/index.ts";
export type {
PctChangeFillMethod,
PctChangeOptions,
DataFramePctChangeOptions,
} from "./stats/index.ts";
+export { quantileSeries, quantileDataFrame } from "./stats/index.ts";
+export type {
+ QuantileInterpolation,
+ QuantileSeriesOptions,
+ QuantileDataFrameOptions,
+} from "./stats/index.ts";
+export { replaceSeries, replaceDataFrame } from "./stats/index.ts";
+export type {
+ ReplaceMapping,
+ ReplaceSpec,
+ ReplaceOptions,
+ DataFrameReplaceOptions,
+} from "./stats/index.ts";
+export { varSeries, semSeries, varDataFrame, semDataFrame } from "./stats/index.ts";
+export type { VarSemSeriesOptions, VarSemDataFrameOptions } from "./stats/index.ts";
+export { skewSeries, kurtSeries, skewDataFrame, kurtDataFrame } from "./stats/index.ts";
+export type {
+ SkewKurtSeriesOptions,
+ SkewKurtDataFrameOptions,
+} from "./stats/index.ts";
+export { toDatetime } from "./stats/index.ts";
+export type { DatetimeUnit, DatetimeErrors, ToDatetimeOptions } from "./stats/index.ts";
+
+export { ffillSeries, bfillSeries, dataFrameFfill, dataFrameBfill } from "./stats/index.ts";
+export type { FillDirectionOptions, DataFrameFillOptions } from "./stats/index.ts";
diff --git a/src/stats/index.ts b/src/stats/index.ts
index dec48e60..3e580371 100644
--- a/src/stats/index.ts
+++ b/src/stats/index.ts
@@ -39,20 +39,327 @@ export {
nsmallestDataFrame,
} from "./nlargest.ts";
export type { NKeep, NTopOptions, NTopDataFrameOptions } from "./nlargest.ts";
+export { whereSeries, maskSeries, whereDataFrame, maskDataFrame } from "./where_mask.ts";
+export type {
+ WherePredicate,
+ SeriesCond,
+ DataFrameCond,
+ WhereMaskOptions,
+} from "./where_mask.ts";
export {
- isna,
- notna,
- isnull,
- notnull,
- ffillSeries,
- bfillSeries,
- dataFrameFfill,
- dataFrameBfill,
-} from "./na_ops.ts";
-export type { FillDirectionOptions, DataFrameFillOptions } from "./na_ops.ts";
+ seriesEq,
+ seriesNe,
+ seriesLt,
+ seriesGt,
+ seriesLe,
+ seriesGe,
+ dataFrameEq,
+ dataFrameNe,
+ dataFrameLt,
+ dataFrameGt,
+ dataFrameLe,
+ dataFrameGe,
+} from "./compare.ts";
+export type { CompareOp, SeriesOther, DataFrameOther } from "./compare.ts";
+export { shiftSeries, diffSeries, dataFrameShift, dataFrameDiff } from "./shift_diff.ts";
+export type { ShiftDiffDataFrameOptions } from "./shift_diff.ts";
+export { interpolateSeries, dataFrameInterpolate } from "./interpolate.ts";
+export type {
+ InterpolateMethod,
+ LimitDirection,
+ InterpolateOptions,
+ DataFrameInterpolateOptions,
+} from "./interpolate.ts";
+export { fillnaSeries, fillnaDataFrame } from "./fillna.ts";
+export type {
+ FillnaMethod,
+ FillnaSeriesOptions,
+ ColumnFillMap,
+ FillnaDataFrameOptions,
+} from "./fillna.ts";
+export { cut, qcut, cutIntervalIndex, qcutIntervalIndex } from "./cut.ts";
+export type { CutOptions, QCutOptions } from "./cut.ts";
+export { sampleSeries, sampleDataFrame } from "./sample.ts";
+export type { SampleSeriesOptions, SampleDataFrameOptions } from "./sample.ts";
+export { applySeries, applymap, dataFrameApply } from "./apply.ts";
+export type { DataFrameApplyOptions } from "./apply.ts";
+
+export {
+ pipeSeries,
+ dataFramePipe,
+ pipeTo,
+ dataFramePipeTo,
+ pipeChain,
+ dataFramePipeChain,
+} from "./pipe.ts";
+export {
+ seriesFloor,
+ dataFrameFloor,
+ seriesCeil,
+ dataFrameCeil,
+ seriesTrunc,
+ dataFrameTrunc,
+ seriesSqrt,
+ dataFrameSqrt,
+ seriesExp,
+ dataFrameExp,
+ seriesLog,
+ dataFrameLog,
+ seriesLog2,
+ dataFrameLog2,
+ seriesLog10,
+ dataFrameLog10,
+ seriesSign,
+ dataFrameSign,
+} from "./numeric_ops.ts";
+
+export {
+ seriesPow,
+ dataFramePow,
+ seriesMod,
+ dataFrameMod,
+ seriesFloorDiv,
+ dataFrameFloorDiv,
+} from "./pow_mod.ts";
+
+export {
+ seriesAdd,
+ seriesRadd,
+ seriesSub,
+ seriesRsub,
+ seriesMul,
+ seriesRmul,
+ seriesDiv,
+ seriesRdiv,
+ dataFrameAdd,
+ dataFrameRadd,
+ dataFrameSub,
+ dataFrameRsub,
+ dataFrameMul,
+ dataFrameRmul,
+ dataFrameDiv,
+ dataFrameRdiv,
+} from "./add_sub_mul_div.ts";
+
+export { getDummies, dataFrameGetDummies } from "./get_dummies.ts";
+export type { GetDummiesOptions, DataFrameGetDummiesOptions } from "./get_dummies.ts";
+
+export { factorize, seriesFactorize } from "./factorize.ts";
+export type { FactorizeOptions, FactorizeResult } from "./factorize.ts";
+
+export { crosstab, seriesCrosstab } from "./crosstab.ts";
+export type { AggFunc, Normalize, CrosstabOptions } from "./crosstab.ts";
+
+export { toNumeric, toNumericArray, toNumericScalar, toNumericSeries } from "./to_numeric.ts";
+export type { ToNumericDowncast, ToNumericErrors, ToNumericOptions } from "./to_numeric.ts";
+
+export { seriesMemoryUsage, dataFrameMemoryUsage } from "./memory_usage.ts";
+export type { MemoryUsageOptions } from "./memory_usage.ts";
+
+export { selectDtypes } from "./select_dtypes.ts";
+export type { DtypeSelector, SelectDtypesOptions } from "./select_dtypes.ts";
+
+export { clipSeriesWithBounds, clipDataFrameWithBounds } from "./clip_with_bounds.ts";
+export type {
+ BoundArg,
+ SeriesClipBoundsOptions,
+ DataFrameClipBoundsOptions,
+} from "./clip_with_bounds.ts";
+
+export { inferDtype } from "./infer_dtype.ts";
+export type { InferredDtype, InferDtypeOptions } from "./infer_dtype.ts";
+
+export { isna, notna, isnull, notnull } from "./notna.ts";
+
+export { dropna, dropnaSeries, dropnaDataFrame } from "./dropna.ts";
+export type { DropnaHow, DropnaDataFrameOptions } from "./dropna.ts";
+
+export { combineFirstSeries, combineFirstDataFrame } from "./combine_first.ts";
+
+export { valueCountsBinned } from "./value_counts_full.ts";
+export type { ValueCountsBinnedOptions } from "./value_counts_full.ts";
+
+export {
+ duplicatedSeries,
+ duplicatedDataFrame,
+ dropDuplicatesSeries,
+ dropDuplicatesDataFrame,
+} from "./duplicated.ts";
+export type {
+ KeepPolicy,
+ DuplicatedDataFrameOptions,
+ DuplicatedSeriesOptions,
+} from "./duplicated.ts";
+
+export { explodeSeries, explodeDataFrame } from "./explode.ts";
+export type { ExplodeOptions, ExplodeDataFrameOptions } from "./explode.ts";
+
+export { isin, dataFrameIsin } from "./isin.ts";
+export type { IsinValues, IsinDict, DataFrameIsinValues } from "./isin.ts";
+
+export { rollingSem, rollingSkew, rollingKurt, rollingQuantile } from "./window_extended.ts";
+export type { WindowExtOptions, RollingQuantileOptions } from "./window_extended.ts";
+export { fillna, countna, countValid } from "./notna_isna.ts";
+export type { IsnaInput, FillnaOptions, DropnaOptions } from "./notna_isna.ts";
+export {
+ strNormalize,
+ strGetDummies,
+ strExtractAll,
+ strRemovePrefix,
+ strRemoveSuffix,
+ strTranslate,
+ strCharWidth,
+ strByteLength,
+} from "./string_ops.ts";
+export type { NormalizeForm, StrInput, ExtractAllOptions } from "./string_ops.ts";
+export {
+ strSplitExpand,
+ strExtractGroups,
+ strPartition,
+ strRPartition,
+ strMultiReplace,
+ strIndent,
+ strDedent,
+} from "./string_ops_extended.ts";
+export type {
+ SplitExpandOptions,
+ ExtractGroupsOptions,
+ PartitionResult,
+ ReplacePair,
+ IndentOptions,
+} from "./string_ops_extended.ts";
+export {
+ digitize,
+ histogram,
+ linspace,
+ arange,
+ percentileOfScore,
+ zscore,
+ minMaxNormalize,
+ coefficientOfVariation,
+ seriesDigitize,
+} from "./numeric_extended.ts";
+export type {
+ HistogramOptions,
+ HistogramResult,
+ ZscoreOptions,
+ MinMaxOptions,
+ CvOptions,
+} from "./numeric_extended.ts";
+export {
+ catFromCodes,
+ catUnionCategories,
+ catIntersectCategories,
+ catDiffCategories,
+ catEqualCategories,
+ catSortByFreq,
+ catToOrdinal,
+ catFreqTable,
+ catCrossTab,
+ catRecode,
+} from "./categorical_ops.ts";
+export type {
+ CatFromCodesOptions,
+ CatSortByFreqOptions,
+ CatCrossTabOptions,
+} from "./categorical_ops.ts";
+export {
+ formatFloat,
+ formatPercent,
+ formatScientific,
+ formatEngineering,
+ formatThousands,
+ formatCurrency,
+ formatCompact,
+ makeFloatFormatter,
+ makePercentFormatter,
+ makeCurrencyFormatter,
+ applySeriesFormatter,
+ applyDataFrameFormatter,
+ seriesToString,
+ dataFrameToString,
+} from "./format_ops.ts";
+export type {
+ Formatter,
+ SeriesToStringOptions,
+ DataFrameToStringOptions,
+} from "./format_ops.ts";
+
+export { clipAdvancedSeries, clipAdvancedDataFrame } from "./clip_advanced.ts";
+export type {
+ SeriesBound,
+ DataFrameBound,
+ ClipAdvancedSeriesOptions,
+ ClipAdvancedDataFrameOptions,
+} from "./clip_advanced.ts";
+
+export { idxminSeries, idxmaxSeries, idxminDataFrame, idxmaxDataFrame } from "./idxmin_idxmax.ts";
+export type { IdxOptions, IdxDataFrameOptions } from "./idxmin_idxmax.ts";
+
+export { modeSeries, modeDataFrame } from "./mode.ts";
+export type { ModeSeriesOptions, ModeDataFrameOptions } from "./mode.ts";
+
+export {
+ nancount,
+ nansum,
+ nanmean,
+ nanmedian,
+ nanvar,
+ nanstd,
+ nanmin,
+ nanmax,
+ nanprod,
+} from "./nancumops.ts";
+export type { NanInput, NanAggOptions } from "./nancumops.ts";
+
+export {
+ nuniqueSeries,
+ nuniqueDataFrame,
+ anySeries,
+ allSeries,
+ anyDataFrame,
+ allDataFrame,
+} from "./nunique.ts";
+export type {
+ NuniqueSeriesOptions,
+ NuniqueDataFrameOptions,
+ AnyAllSeriesOptions,
+ AnyAllDataFrameOptions,
+} from "./nunique.ts";
+
export { pctChangeSeries, pctChangeDataFrame } from "./pct_change.ts";
export type {
PctChangeFillMethod,
PctChangeOptions,
DataFramePctChangeOptions,
} from "./pct_change.ts";
+
+export { quantileSeries, quantileDataFrame } from "./quantile.ts";
+export type {
+ QuantileInterpolation,
+ QuantileSeriesOptions,
+ QuantileDataFrameOptions,
+} from "./quantile.ts";
+
+export { replaceSeries, replaceDataFrame } from "./replace.ts";
+export type {
+ ReplaceMapping,
+ ReplaceSpec,
+ ReplaceOptions,
+ DataFrameReplaceOptions,
+} from "./replace.ts";
+
+export { varSeries, semSeries, varDataFrame, semDataFrame } from "./sem_var.ts";
+export type { VarSemSeriesOptions, VarSemDataFrameOptions } from "./sem_var.ts";
+
+export { skewSeries, kurtSeries, skewDataFrame, kurtDataFrame } from "./skew_kurt.ts";
+export type {
+ SkewKurtSeriesOptions,
+ SkewKurtDataFrameOptions,
+} from "./skew_kurt.ts";
+
+export { toDatetime } from "./to_datetime.ts";
+export type { DatetimeUnit, DatetimeErrors, ToDatetimeOptions } from "./to_datetime.ts";
+
+export { ffillSeries, bfillSeries, dataFrameFfill, dataFrameBfill } from "./na_ops.ts";
+export type { FillDirectionOptions, DataFrameFillOptions } from "./na_ops.ts";
diff --git a/src/stats/pct_change.ts b/src/stats/pct_change.ts
index c46c9e84..10e527ec 100644
--- a/src/stats/pct_change.ts
+++ b/src/stats/pct_change.ts
@@ -97,7 +97,9 @@ function applyFill(
method: PctChangeFillMethod | null | undefined,
limit: number | null | undefined,
): Scalar[] {
- if (!method) return [...vals];
+ if (!method) {
+ return [...vals];
+ }
return method === "pad" ? padFill(vals, limit) : bfillFill(vals, limit);
}
@@ -114,7 +116,8 @@ function computePct(vals: readonly Scalar[], periods: number): Scalar[] {
out[i] = curr / prev - 1;
} else if (isNum(curr) && isNum(prev) && prev === 0) {
// 0 denominator → Infinity (same as pandas)
- out[i] = curr === 0 ? Number.NaN : curr > 0 ? Infinity : -Infinity;
+ out[i] =
+ curr === 0 ? Number.NaN : curr > 0 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
} else {
out[i] = null;
}
@@ -128,7 +131,8 @@ function computePct(vals: readonly Scalar[], periods: number): Scalar[] {
if (isNum(curr) && isNum(fwd) && curr !== 0) {
out[i] = fwd / curr - 1;
} else if (isNum(curr) && isNum(fwd) && curr === 0) {
- out[i] = fwd === 0 ? Number.NaN : fwd > 0 ? Infinity : -Infinity;
+ out[i] =
+ fwd === 0 ? Number.NaN : fwd > 0 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
} else {
out[i] = null;
}
@@ -151,7 +155,10 @@ function computePct(vals: readonly Scalar[], periods: number): Scalar[] {
* pctChangeSeries(s); // [null, 0.1, -0.1, 0.2222…]
* ```
*/
-export function pctChangeSeries(series: Series, options: PctChangeOptions = {}): Series {
+export function pctChangeSeries(
+ series: Series,
+ options: PctChangeOptions = {},
+): Series {
const periods = options.periods ?? 1;
const fillMethod = options.fillMethod !== undefined ? options.fillMethod : "pad";
const limit = options.limit ?? null;
@@ -162,7 +169,7 @@ export function pctChangeSeries(series: Series, options: PctChangeOption
return new Series({
data: result,
index: series.index,
- name: series.name ?? undefined,
+ name: series.name,
});
}
@@ -199,7 +206,7 @@ export function pctChangeDataFrame(
const periods = options.periods ?? 1;
const fillMethod = options.fillMethod !== undefined ? options.fillMethod : "pad";
const limit = options.limit ?? null;
- const nRows = df.index.length;
+ const nRows = df.index.size;
const cols = df.columns.values;
const nCols = cols.length;
diff --git a/tests/stats/pct_change.test.ts b/tests/stats/pct_change.test.ts
index 98966e8c..f7015e4a 100644
--- a/tests/stats/pct_change.test.ts
+++ b/tests/stats/pct_change.test.ts
@@ -3,12 +3,7 @@
*/
import { describe, expect, it } from "bun:test";
import fc from "fast-check";
-import {
- DataFrame,
- Series,
- pctChangeDataFrame,
- pctChangeSeries,
-} from "../../src/index.ts";
+import { DataFrame, Series, pctChangeDataFrame, pctChangeSeries } from "../../src/index.ts";
import type { Scalar } from "../../src/index.ts";
// ─── helpers ─────────────────────────────────────────────────────────────────
@@ -25,24 +20,38 @@ function nanEq(a: Scalar, b: Scalar): boolean {
}
function arrEq(a: readonly Scalar[], b: readonly Scalar[]): boolean {
- if (a.length !== b.length) return false;
+ if (a.length !== b.length) {
+ return false;
+ }
for (let i = 0; i < a.length; i++) {
- if (!nanEq(a[i] as Scalar, b[i] as Scalar)) return false;
+ if (!nanEq(a[i] as Scalar, b[i] as Scalar)) {
+ return false;
+ }
}
return true;
}
function close(a: Scalar, b: Scalar, eps = 1e-9): boolean {
- if (a === null && b === null) return true;
- if (typeof a !== "number" || typeof b !== "number") return false;
- if (Number.isNaN(a) && Number.isNaN(b)) return true;
+ if (a === null && b === null) {
+ return true;
+ }
+ if (typeof a !== "number" || typeof b !== "number") {
+ return false;
+ }
+ if (Number.isNaN(a) && Number.isNaN(b)) {
+ return true;
+ }
return Math.abs(a - b) < eps;
}
function arrClose(a: readonly Scalar[], b: readonly Scalar[], eps = 1e-9): boolean {
- if (a.length !== b.length) return false;
+ if (a.length !== b.length) {
+ return false;
+ }
for (let i = 0; i < a.length; i++) {
- if (!close(a[i] as Scalar, b[i] as Scalar, eps)) return false;
+ if (!close(a[i] as Scalar, b[i] as Scalar, eps)) {
+ return false;
+ }
}
return true;
}
@@ -121,7 +130,7 @@ describe("pctChangeSeries", () => {
it("zero denominator returns Infinity", () => {
const result = pctChangeSeries(s([0, 10]), { fillMethod: null });
- expect(result.values[1]).toBe(Infinity);
+ expect(result.values[1]).toBe(Number.POSITIVE_INFINITY);
});
it("zero/zero denominator returns NaN", () => {
@@ -133,7 +142,7 @@ describe("pctChangeSeries", () => {
const src = new Series({ data: [10, 20, 30], name: "price" });
const result = pctChangeSeries(src);
expect(result.name).toBe("price");
- expect(result.index.length).toBe(3);
+ expect(result.index.size).toBe(3);
});
it("empty series returns empty", () => {
@@ -151,12 +160,10 @@ describe("pctChangeSeries", () => {
describe("pctChangeDataFrame", () => {
it("column-wise (default)", () => {
- const df = new DataFrame(
- new Map([
- ["a", new Series({ data: [100, 110, 121] })],
- ["b", new Series({ data: [200, 180, 198] })],
- ]),
- );
+ const df = DataFrame.fromColumns({
+ a: [100, 110, 121],
+ b: [200, 180, 198],
+ });
const result = pctChangeDataFrame(df);
const colA = result.col("a").values;
const colB = result.col("b").values;
@@ -169,13 +176,11 @@ describe("pctChangeDataFrame", () => {
});
it("row-wise (axis=1)", () => {
- const df = new DataFrame(
- new Map([
- ["a", new Series({ data: [100, 200] })],
- ["b", new Series({ data: [110, 220] })],
- ["c", new Series({ data: [121, 242] })],
- ]),
- );
+ const df = DataFrame.fromColumns({
+ a: [100, 200],
+ b: [110, 220],
+ c: [121, 242],
+ });
const result = pctChangeDataFrame(df, { axis: 1 });
// row 0: [100, 110, 121] → [null, 0.1, 0.1]
// row 1: [200, 220, 242] → [null, 0.1, 0.1]
@@ -192,12 +197,10 @@ describe("pctChangeDataFrame", () => {
});
it("preserves column order", () => {
- const df = new DataFrame(
- new Map([
- ["x", new Series({ data: [1, 2] })],
- ["y", new Series({ data: [3, 6] })],
- ]),
- );
+ const df = DataFrame.fromColumns({
+ x: [1, 2],
+ y: [3, 6],
+ });
const result = pctChangeDataFrame(df);
expect(result.columns.values).toEqual(["x", "y"]);
});
@@ -217,13 +220,10 @@ describe("pctChangeSeries — property tests", () => {
it("first element is always null for periods=1", () => {
fc.assert(
- fc.property(
- fc.array(fc.float({ noNaN: true }), { minLength: 1, maxLength: 50 }),
- (arr) => {
- const result = pctChangeSeries(s(arr));
- return result.values[0] === null;
- },
- ),
+ fc.property(fc.array(fc.float({ noNaN: true }), { minLength: 1, maxLength: 50 }), (arr) => {
+ const result = pctChangeSeries(s(arr));
+ return result.values[0] === null;
+ }),
);
});