Skip to content

Commit 0aabe21

Browse files
fix: resolve TypeScript and lint errors in new stats modules
- Add TimedeltaLike interface to Scalar type for stats Timedelta support - Export stats Timedelta (public ctor, totalMs) from src/index.ts instead of core - Fix diffSeries/shiftSeries exports to use new options-based API from diff_shift.ts - Fix sample.ts: use null instead of undefined for name fields; use ** operator - Fix na_ops.ts: use null instead of undefined for name fields - Fix read_excel.ts: handle TimedeltaLike in toLabel switch - Fix explode.ts formatting (biome auto-fix) - Fix SampleDataFrameOptions.axis to accept string forms 'index'/'columns' - Fix tests/stats/interval.test.ts: import Interval/IntervalIndex from stats module - Fix tests/stats/to_timedelta.test.ts: use optional chaining for nullable results - Fix tests/stats/shift_diff.test.ts: update to new options-based API, null expectations - Fix tests/reshape/explode.test.ts: use ignoreIndex instead of ignore_index - Fix tests/core/sample.test.ts: correct index construction and type annotations Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent d016232 commit 0aabe21

15 files changed

Lines changed: 122 additions & 125 deletions

src/core/sample.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
* @module
99
*/
1010

11-
import { DataFrame } from "./frame.ts";
11+
import type { Label, Scalar } from "../types.ts";
1212
import { Index } from "./base-index.ts";
13+
import { DataFrame } from "./frame.ts";
1314
import { Series } from "./series.ts";
14-
import type { Label, Scalar } from "../types.ts";
1515

1616
// ─── public types ─────────────────────────────────────────────────────────────
1717

@@ -139,7 +139,7 @@ function weightedSampleWithoutReplacement(
139139
// Use reservoir sampling with exponential keys: assign key = rand^(1/w), take top-k
140140
const keys: Array<[number, number]> = probs.map((p, i) => {
141141
const r = rng();
142-
const key = p > 0 ? Math.pow(r, 1 / p) : 0;
142+
const key = p > 0 ? r ** (1 / p) : 0;
143143
return [key, i];
144144
});
145145
keys.sort((a, b) => b[0] - a[0]);
@@ -149,11 +149,7 @@ function weightedSampleWithoutReplacement(
149149
/**
150150
* Weighted sample WITH replacement: pick `k` indices based on cumulative probabilities.
151151
*/
152-
function weightedSampleWithReplacement(
153-
k: number,
154-
probs: number[],
155-
rng: () => number,
156-
): number[] {
152+
function weightedSampleWithReplacement(k: number, probs: number[], rng: () => number): number[] {
157153
const cumulative: number[] = [];
158154
let sum = 0;
159155
for (const p of probs) {
@@ -256,13 +252,11 @@ export function sampleSeries(series: Series<Scalar>, options?: SampleOptions): S
256252
return new Series<Scalar>({
257253
data: newValues,
258254
index: new Index<Label>(newLabels),
259-
name: series.name ?? undefined,
255+
name: series.name ?? null,
260256
dtype: series.dtype,
261257
});
262258
}
263259

264-
// ─── DataFrame sample ──────────────────────────────────────────────────────────
265-
266260
/**
267261
* Return a random sample of rows (or columns) from a DataFrame.
268262
*

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ export {
182182

183183
export { Period, PeriodIndex } from "./core/index.ts";
184184
export type { PeriodFreq, PeriodIndexOptions } from "./core/index.ts";
185-
export { Timedelta, TimedeltaIndex } from "./core/index.ts";
185+
export { TimedeltaIndex } from "./core/index.ts";
186186
export type { TimedeltaComponents, TimedeltaIndexOptions } from "./core/index.ts";
187187
export {
188188
Day,
@@ -537,7 +537,7 @@ export { toDatetime } from "./stats/index.ts";
537537
export type { DatetimeUnit, DatetimeErrors, ToDatetimeOptions } from "./stats/index.ts";
538538

539539
// Branch-unique exports not yet in main
540-
export { toTimedelta, parseFrac, formatTimedelta } from "./stats/index.ts";
540+
export { toTimedelta, parseFrac, formatTimedelta, Timedelta } from "./stats/index.ts";
541541
export type { TimedeltaUnit, TimedeltaErrors, ToTimedeltaOptions } from "./stats/index.ts";
542542
export { dateRange, parseFreq, advanceDate, toDateInput } from "./stats/index.ts";
543543
export type { DateRangeInclusive, ParsedFreq } from "./stats/index.ts";

src/io/read_excel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ function buildDataFrame(rows: readonly RawRow[], options: ReadExcelOptions): Dat
517517
colMap.set(colName, new Series({ data: colData, dtype: Dtype.from(dtypeName), name: colName }));
518518
}
519519
const toLabel = (v: Scalar): Label =>
520-
v === undefined || typeof v === "bigint" || v instanceof Date ? null : v;
520+
v === undefined || typeof v === "bigint" || (typeof v === "object" && v !== null) ? null : v;
521521
const rowIndex =
522522
indexColIdx >= 0
523523
? new Index<Label>((data[indexColIdx] ?? []).map(toLabel))

src/reshape/explode.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,7 @@ function expandCell(value: Scalar): Scalar[] {
8888
* explodeSeries(s).toArray(); // [1, 2, 3]
8989
* ```
9090
*/
91-
export function explodeSeries(
92-
series: Series<Scalar>,
93-
options?: ExplodeOptions,
94-
): Series<Scalar> {
91+
export function explodeSeries(series: Series<Scalar>, options?: ExplodeOptions): Series<Scalar> {
9592
const ignoreIndex = options?.ignore_index ?? false;
9693
const outValues: Scalar[] = [];
9794
const outLabels: Label[] = [];
@@ -154,8 +151,7 @@ export function explodeDataFrame(
154151
options?: ExplodeOptions,
155152
): DataFrame {
156153
const ignoreIndex = options?.ignore_index ?? false;
157-
const explodeCols: readonly string[] =
158-
typeof column === "string" ? [column] : column;
154+
const explodeCols: readonly string[] = typeof column === "string" ? [column] : column;
159155

160156
// Validate column names
161157
for (const col of explodeCols) {

src/stats/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export {
6161
dataFrameGe,
6262
} from "./compare.ts";
6363
export type { CompareOp, SeriesOther, DataFrameOther } from "./compare.ts";
64-
export { shiftSeries, diffSeries, dataFrameShift, dataFrameDiff } from "./shift_diff.ts";
64+
export { dataFrameShift, dataFrameDiff } from "./shift_diff.ts";
6565
export type { ShiftDiffDataFrameOptions } from "./shift_diff.ts";
6666
export { interpolateSeries, dataFrameInterpolate } from "./interpolate.ts";
6767
export type {
@@ -361,15 +361,15 @@ export type {
361361
export { toDatetime } from "./to_datetime.ts";
362362
export type { DatetimeUnit, DatetimeErrors, ToDatetimeOptions } from "./to_datetime.ts";
363363

364-
export { toTimedelta, parseFrac, formatTimedelta } from "./to_timedelta.ts";
364+
export { toTimedelta, parseFrac, formatTimedelta, Timedelta } from "./to_timedelta.ts";
365365
export type { TimedeltaUnit, TimedeltaErrors, ToTimedeltaOptions } from "./to_timedelta.ts";
366366
export { dateRange, parseFreq, advanceDate, toDateInput } from "./date_range.ts";
367367
export type {
368368
DateRangeInclusive,
369369
DateRangeOptions,
370370
ParsedFreq,
371371
} from "./date_range.ts";
372-
export { diffDataFrame, shiftDataFrame } from "./diff_shift.ts";
372+
export { diffDataFrame, shiftDataFrame, diffSeries, shiftSeries } from "./diff_shift.ts";
373373
export type {
374374
DiffOptions,
375375
DataFrameDiffOptions,

src/stats/na_ops.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export function ffillSeries<T extends Scalar>(
183183
data: filled,
184184
index: series.index,
185185
dtype: series.dtype,
186-
name: series.name ?? undefined,
186+
name: series.name ?? null,
187187
});
188188
}
189189

@@ -213,7 +213,7 @@ export function bfillSeries<T extends Scalar>(
213213
data: filled,
214214
index: series.index,
215215
dtype: series.dtype,
216-
name: series.name ?? undefined,
216+
name: series.name ?? null,
217217
});
218218
}
219219

src/stats/sample.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ export interface SampleDataFrameOptions {
8989
readonly ignoreIndex?: boolean;
9090
/**
9191
* Axis to sample along.
92-
* - `0` (default): sample rows.
93-
* - `1`: sample columns.
92+
* - `0` or `"index"` (default): sample rows.
93+
* - `1` or `"columns"`: sample columns.
9494
*/
95-
readonly axis?: 0 | 1;
95+
readonly axis?: 0 | 1 | "index" | "columns";
9696
}
9797

9898
// ─── pseudo-random number generator ──────────────────────────────────────────
@@ -384,7 +384,7 @@ export function sampleSeries(
384384
export function sampleDataFrame(df: DataFrame, options: SampleDataFrameOptions = {}): DataFrame {
385385
const { n, frac, replace = false, weights, randomState, ignoreIndex = false, axis = 0 } = options;
386386

387-
if (axis === 1) {
387+
if (axis === 1 || axis === "columns") {
388388
return sampleColumns(df, n, frac, replace, weights, randomState);
389389
}
390390
return sampleRows(df, n, frac, replace, weights, randomState, ignoreIndex);

src/stats/to_timedelta.ts

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ import type { Scalar } from "../types.ts";
2222
// ─── top-level regex constants (biome: useTopLevelRegex) ──────────────────────
2323

2424
/** Pandas-style: "[± ][N day[s][,]] HH:MM:SS[.fraction]" */
25-
const RE_PANDAS =
26-
/^(-)?(?:(\d+)\s+days?,?\s*)?(\d{1,2}):(\d{2}):(\d{2})(?:\.(\d+))?$/i;
25+
const RE_PANDAS = /^(-)?(?:(\d+)\s+days?,?\s*)?(\d{1,2}):(\d{2}):(\d{2})(?:\.(\d+))?$/i;
2726

2827
/** ISO 8601 duration: P[nD][T[nH][nM][nS]] */
2928
const RE_ISO =
@@ -207,10 +206,7 @@ export function toTimedelta(
207206

208207
// ─── series conversion ─────────────────────────────────────────────────────────
209208

210-
function convertSeries(
211-
s: Series<Scalar>,
212-
options: ToTimedeltaOptions,
213-
): Series<Timedelta | null> {
209+
function convertSeries(s: Series<Scalar>, options: ToTimedeltaOptions): Series<Timedelta | null> {
214210
const converted = s.values.map((v) => convertOne(v, options));
215211
return new Series<Timedelta | null>({
216212
data: converted as (Timedelta | null)[],
@@ -353,12 +349,7 @@ function parsePandas(m: RegExpExecArray): Timedelta | null {
353349
/** Parse ISO 8601 duration: P1DT2H3M4.5S */
354350
function parseIso(m: RegExpExecArray): Timedelta | null {
355351
// Reject bare "P" with no components
356-
if (
357-
m[2] === undefined &&
358-
m[3] === undefined &&
359-
m[4] === undefined &&
360-
m[5] === undefined
361-
) {
352+
if (m[2] === undefined && m[3] === undefined && m[4] === undefined && m[5] === undefined) {
362353
return null;
363354
}
364355
const neg = m[1] === "-";
@@ -474,11 +465,7 @@ export function formatTimedelta(td: Timedelta): string {
474465
* - `"coerce"` → returns null
475466
* - `"ignore"` → returns original value unchanged
476467
*/
477-
function applyErrors(
478-
errors: TimedeltaErrors,
479-
original: Scalar,
480-
message: string,
481-
): Timedelta | null {
468+
function applyErrors(errors: TimedeltaErrors, original: Scalar, message: string): Timedelta | null {
482469
if (errors === "raise") {
483470
throw new TypeError(message);
484471
}

src/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77
*/
88

99
/** Scalar value types — the atomic units of data in tsb. */
10-
export type Scalar = number | string | boolean | bigint | null | undefined | Date;
10+
export type Scalar = number | string | boolean | bigint | null | undefined | Date | TimedeltaLike;
11+
12+
/** Timedelta-like object: any value representing a temporal duration (has totalMs). */
13+
export interface TimedeltaLike {
14+
readonly totalMs: number;
15+
}
1116

1217
/** A label used to identify rows or columns (similar to pandas Index). */
1318
export type Label = number | string | boolean | null;

tests/core/sample.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,14 @@ describe("sampleSeries", () => {
9898
});
9999

100100
test("preserves correct index labels", () => {
101-
const s = new Series({ data: [100, 200, 300], index: { values: ["a", "b", "c"] } });
101+
const s = new Series({ data: [100, 200, 300], index: ["a", "b", "c"] });
102102
const r = sampleSeries(s, { n: 2, randomState: 0 });
103103
// Index labels should match the positions sampled
104104
for (let i = 0; i < r.values.length; i++) {
105105
const v = r.values[i] as number;
106106
const label = r.index.at(i);
107107
const origPos = (v - 100) / 100; // 0, 1, or 2
108-
const expectedLabel = ["a", "b", "c"][origPos];
108+
const expectedLabel: string | null = ["a", "b", "c"][origPos] ?? null;
109109
expect(label).toBe(expectedLabel);
110110
}
111111
});

0 commit comments

Comments
 (0)