Skip to content

Commit ba62da9

Browse files
authored
Merge pull request #57 from githubnext/autoloop/build-tsb-pandas-typescript-migration-32862b917c67b1cd
[Autoloop] [Autoloop: build-tsb-pandas-typescript-migration] Iteration 72: value_counts + elem_ops exports
2 parents e855a3b + c10914c commit ba62da9

76 files changed

Lines changed: 22715 additions & 3 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

playground/cat_accessor.html

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>tsb — Categorical Accessor</title>
7+
<script src="playground-runtime.js"></script>
8+
<style>
9+
body { font-family: system-ui, sans-serif; max-width: 860px; margin: 2rem auto; padding: 0 1rem; color: #1a1a1a; }
10+
h1 { font-size: 2rem; margin-bottom: .25rem; }
11+
.subtitle { color: #555; margin-bottom: 2rem; }
12+
section { margin-bottom: 2.5rem; }
13+
h2 { font-size: 1.25rem; border-bottom: 2px solid #e0e0e0; padding-bottom: .35rem; margin-bottom: 1rem; }
14+
pre { background: #f5f5f5; border-radius: 6px; padding: 1rem; overflow-x: auto; font-size: .875rem; }
15+
code { font-family: "JetBrains Mono", "Fira Code", monospace; }
16+
.output { background: #eaf7ea; border-left: 4px solid #4caf50; padding: .75rem 1rem; border-radius: 0 6px 6px 0; margin-top: .5rem; font-size: .875rem; white-space: pre; font-family: monospace; }
17+
.note { background: #fff8e1; border-left: 4px solid #ffc107; padding: .6rem 1rem; border-radius: 0 6px 6px 0; font-size: .9rem; margin: .75rem 0; }
18+
nav { margin-bottom: 1.5rem; font-size: .9rem; color: #555; }
19+
nav a { color: #0366d6; text-decoration: none; }
20+
nav a:hover { text-decoration: underline; }
21+
</style>
22+
</head>
23+
<body>
24+
<nav><a href="index.html">← tsb playground</a></nav>
25+
<h1>Categorical Accessor</h1>
26+
<p class="subtitle">Manage categorical data — mirrors <code>pandas.Categorical</code> and <code>Series.cat</code>.</p>
27+
28+
<section>
29+
<h2>1 — Categories and codes</h2>
30+
<p>Access <code>series.cat.categories</code> for the sorted unique labels and <code>series.cat.codes</code> for the integer encoding.</p>
31+
<pre><code id="ex1-code">import { Series } from "tsb";
32+
33+
const size = new Series({
34+
data: ["M", "S", "L", "S", "M", "XL"],
35+
name: "size",
36+
});
37+
38+
// Sorted unique categories
39+
console.log("categories:", [...size.cat.categories.values]);
40+
// → ["L", "M", "S", "XL"]
41+
42+
// Integer codes (position in categories array; -1 for null)
43+
console.log("codes:", size.cat.codes.toArray());
44+
// → [1, 2, 0, 2, 1, 3]
45+
46+
console.log("nCategories:", size.cat.nCategories); // 4
47+
console.log("ordered:", size.cat.ordered); // false
48+
</code></pre>
49+
<div class="output" id="ex1-out">▶ run</div>
50+
</section>
51+
52+
<section>
53+
<h2>2 — Nulls are encoded as -1</h2>
54+
<p>Missing values (<code>null</code>) are not counted as categories and get a code of <code>-1</code>.</p>
55+
<pre><code id="ex2-code">import { Series } from "tsb";
56+
57+
const s = new Series({ data: ["a", null, "b", null, "a"] });
58+
59+
console.log("categories:", [...s.cat.categories.values]); // ["a", "b"]
60+
console.log("codes:", s.cat.codes.toArray()); // [0, -1, 1, -1, 0]
61+
console.log("nCategories:", s.cat.nCategories); // 2
62+
</code></pre>
63+
<div class="output" id="ex2-out">▶ run</div>
64+
</section>
65+
66+
<section>
67+
<h2>3 — Add and remove categories</h2>
68+
<p>Use <code>addCategories()</code> to register new labels (without needing them in the data yet)
69+
and <code>removeCategories()</code> to drop labels (values become null).</p>
70+
<pre><code id="ex3-code">import { Series } from "tsb";
71+
72+
const s = new Series({ data: ["red", "blue", "red"] });
73+
74+
// Add a new category (not yet in data)
75+
const s2 = s.cat.addCategories(["green"]);
76+
console.log("after add:", [...s2.cat.categories.values]);
77+
// → ["blue", "green", "red"]
78+
79+
// Remove a category — matching values become null
80+
const s3 = s.cat.removeCategories(["red"]);
81+
console.log("after remove values:", s3.toArray());
82+
// → [null, "blue", null]
83+
console.log("after remove cats:", [...s3.cat.categories.values]);
84+
// → ["blue"]
85+
</code></pre>
86+
<div class="output" id="ex3-out">▶ run</div>
87+
</section>
88+
89+
<section>
90+
<h2>4 — Remove unused categories</h2>
91+
<p><code>removeUnusedCategories()</code> drops any categories not present in the data.</p>
92+
<pre><code id="ex4-code">import { Series } from "tsb";
93+
94+
const s = new Series({ data: ["a", "b"] });
95+
// manually add extra categories
96+
const s2 = s.cat.addCategories(["c", "d", "e"]);
97+
console.log("before:", s2.cat.nCategories); // 5
98+
99+
const s3 = s2.cat.removeUnusedCategories();
100+
console.log("after:", s3.cat.nCategories); // 2
101+
console.log("cats:", [...s3.cat.categories.values]); // ["a", "b"]
102+
</code></pre>
103+
<div class="output" id="ex4-out">▶ run</div>
104+
</section>
105+
106+
<section>
107+
<h2>5 — Rename categories</h2>
108+
<p>Pass an object mapping old names → new names, or an array of replacement names.</p>
109+
<pre><code id="ex5-code">import { Series } from "tsb";
110+
111+
const s = new Series({ data: ["low", "mid", "high", "mid"] });
112+
113+
// Object mapping
114+
const s2 = s.cat.renameCategories({ low: "L", mid: "M", high: "H" });
115+
console.log("renamed values:", s2.toArray());
116+
// → ["L", "M", "H", "M"]
117+
console.log("renamed cats:", [...s2.cat.categories.values]);
118+
// → ["H", "L", "M"]
119+
120+
// Array replacement (same order as categories)
121+
const s3 = s.cat.renameCategories(["H", "L", "M"]); // cats are [high, low, mid]
122+
console.log("array rename:", s3.toArray());
123+
</code></pre>
124+
<div class="output" id="ex5-out">▶ run</div>
125+
</section>
126+
127+
<section>
128+
<h2>6 — Set and reorder categories</h2>
129+
<p><code>setCategories()</code> replaces the entire category list (values not in the new list become null).
130+
<code>reorderCategories()</code> changes the order without adding or removing.</p>
131+
<pre><code id="ex6-code">import { Series } from "tsb";
132+
133+
const s = new Series({ data: ["XS", "S", "M", "L", "XL"] });
134+
135+
// setCategories: restrict to a subset
136+
const s2 = s.cat.setCategories(["S", "M", "L"]);
137+
console.log("set cats:", s2.toArray());
138+
// → [null, "S", "M", "L", null]
139+
140+
// reorderCategories: custom ordering (e.g., by size not alphabetically)
141+
const s3 = s.cat.reorderCategories(["XS", "S", "M", "L", "XL"], true);
142+
console.log("ordered:", s3.cat.ordered); // true
143+
console.log("custom order:", [...s3.cat.categories.values]);
144+
</code></pre>
145+
<div class="output" id="ex6-out">▶ run</div>
146+
</section>
147+
148+
<section>
149+
<h2>7 — Value counts per category</h2>
150+
<p><code>valueCounts()</code> returns a Series with count of each category (zero for unused ones).</p>
151+
<pre><code id="ex7-code">import { Series } from "tsb";
152+
153+
const grades = new Series({ data: ["A", "B", "A", "C", "B", "A"] });
154+
const gradesFull = grades.cat.addCategories(["D", "F"]);
155+
156+
const counts = gradesFull.cat.valueCounts();
157+
console.log("categories:", [...gradesFull.cat.categories.values]);
158+
// → ["A", "B", "C", "D", "F"]
159+
console.log("counts:", counts.toArray());
160+
// → [3, 2, 1, 0, 0]
161+
</code></pre>
162+
<div class="output" id="ex7-out">▶ run</div>
163+
</section>
164+
165+
<section>
166+
<h2>8 — Ordered categories</h2>
167+
<p><code>asOrdered()</code> marks a categorical as ordered (enabling comparisons).
168+
The order is determined by the categories array index.</p>
169+
<pre><code id="ex8-code">import { Series } from "tsb";
170+
171+
const rating = new Series({ data: ["good", "bad", "excellent", "good"] });
172+
173+
// Establish a meaningful order
174+
const ordered = rating.cat
175+
.reorderCategories(["bad", "good", "excellent"], true);
176+
177+
console.log("ordered:", ordered.cat.ordered); // true
178+
console.log("categories:", [...ordered.cat.categories.values]);
179+
// → ["bad", "good", "excellent"]
180+
181+
// bad=0, good=1, excellent=2
182+
console.log("codes:", ordered.cat.codes.toArray());
183+
// → [1, 0, 2, 1]
184+
</code></pre>
185+
<div class="output" id="ex8-out">▶ run</div>
186+
</section>
187+
</body>
188+
</html>

0 commit comments

Comments
 (0)