dataframe-toolkit 0.11.2__tar.gz → 0.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/PKG-INFO +113 -39
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/README.md +111 -38
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/pyproject.toml +2 -1
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/pyproject.toml.orig +2 -1
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/__init__.py +1 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/annotate_cmd.py +1 -1
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/binx_cmd.py +4 -4
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/chi_cmd.py +4 -4
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/cleannames_cmd.py +3 -3
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/concat_cmd.py +3 -3
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/corr_cmd.py +6 -6
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/describe_cmd.py +4 -4
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/eval_cmd.py +25 -7
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/explode_cmd.py +4 -4
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/fit_cmd.py +6 -6
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/func_cmd.py +5 -5
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/hist_cmd.py +10 -10
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/implode_cmd.py +6 -6
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/info_cmd.py +2 -2
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/interp_cmd.py +6 -6
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/line_cmd.py +14 -14
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/melt_cmd.py +1 -1
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/merge_cmd.py +32 -35
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/pivot_cmd.py +8 -8
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/query_cmd.py +33 -11
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/randvar_cmd.py +3 -3
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/sample_cmd.py +9 -9
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/scale_cmd.py +11 -11
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/scat_cmd.py +12 -12
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/segid_cmd.py +2 -2
- dataframe_toolkit-0.12.0/src/dftk/commands/skill_cmd.py +146 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/split_cmd.py +10 -7
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/stat_cmd.py +4 -4
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/test_cmd.py +3 -3
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/transpose_cmd.py +2 -2
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/wstat_cmd.py +4 -4
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/common/io.py +61 -29
- dataframe_toolkit-0.12.0/src/dftk/skills/dftk/SKILL.md +196 -0
- dataframe_toolkit-0.12.0/src/dftk/skills/dftk/references/snakemake.md +167 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/__init__.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/cli.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/base.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/clean_cmd.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/dataset_cmd.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/help.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/commands/print_cmd.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/common/__init__.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/common/copula.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/common/evalfuncs.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/common/plot.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/common/seed.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/common/seq.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/common/stats.py +0 -0
- {dataframe_toolkit-0.11.2 → dataframe_toolkit-0.12.0}/src/dftk/io.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: dataframe-toolkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: A command-line toolkit for DataFrame analysis and manipulation
|
|
5
5
|
Keywords: dataframe,statistics,data analysis,CLI,TSV,pandas
|
|
6
6
|
Author: Gunnar Pálsson
|
|
@@ -20,6 +20,7 @@ Requires-Dist: statsmodels>=0.14
|
|
|
20
20
|
Requires-Dist: patsy>=0.5.6
|
|
21
21
|
Requires-Dist: duckdb>=0.8
|
|
22
22
|
Requires-Dist: matplotlib>=3.7
|
|
23
|
+
Requires-Dist: pillow>=13.0
|
|
23
24
|
Requires-Dist: seaborn>=0.12
|
|
24
25
|
Requires-Dist: tqdm>=4.65
|
|
25
26
|
Requires-Python: >=3.12
|
|
@@ -76,17 +77,20 @@ uv tool install .
|
|
|
76
77
|
|
|
77
78
|
### Skill for coding agents
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
dftk ships an agent skill: a short guide that coding agents such as Codex
|
|
81
|
+
and Claude Code load when a task involves dftk. It covers the piping
|
|
81
82
|
conventions, which command to use for what, and patterns for Snakemake and
|
|
82
|
-
Make.
|
|
83
|
+
Make. Install it with:
|
|
83
84
|
|
|
84
85
|
```bash
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
dftk skill install # every agent found: ~/.claude and/or ~/.codex
|
|
87
|
+
dftk skill install --codex # only one (--claude or --codex; creates the folder)
|
|
88
|
+
dftk skill install --dir DIR # another agent's skills folder
|
|
87
89
|
```
|
|
88
90
|
|
|
89
|
-
|
|
91
|
+
It prints where it installed the skill. Run it again after upgrading dftk
|
|
92
|
+
so the skill matches the installed version; it replaces only the earlier
|
|
93
|
+
dftk skill. The source is in `src/dftk/skills/dftk/`.
|
|
90
94
|
|
|
91
95
|
## Quick example
|
|
92
96
|
|
|
@@ -94,15 +98,15 @@ Copy it again after upgrading dftk so it matches the installed version.
|
|
|
94
98
|
dftk dataset tips | dftk stat - -c tip total_bill -g day
|
|
95
99
|
```
|
|
96
100
|
|
|
97
|
-
Chain commands with `-o` (write
|
|
98
|
-
|
|
99
|
-
for large data,
|
|
100
|
-
step:
|
|
101
|
+
Chain commands with a bare `-o` (write a temp parquet, print its path)
|
|
102
|
+
instead of piping TSV text: the next command sees the path on stdin and reads
|
|
103
|
+
that file. It's faster for large data, keeps column types exact, and is the
|
|
104
|
+
recommended pattern once a pipeline has more than one step:
|
|
101
105
|
|
|
102
106
|
```bash
|
|
103
107
|
dftk dataset tips -o \
|
|
104
|
-
| dftk pivot
|
|
105
|
-
| dftk print
|
|
108
|
+
| dftk pivot -i day -v tip -f mean -o \
|
|
109
|
+
| dftk print
|
|
106
110
|
```
|
|
107
111
|
|
|
108
112
|
## Subcommands
|
|
@@ -162,7 +166,7 @@ publication-quality output.
|
|
|
162
166
|
| `sample` | Random row sampling (with or without replacement, by count or fraction) |
|
|
163
167
|
| `split` | Split a dataframe into one file per group |
|
|
164
168
|
| `annotate` | Read and write provenance metadata (genome, source, …) in parquet files |
|
|
165
|
-
| `print` | Read any dftk input (TSV,
|
|
169
|
+
| `print` | Read any dftk input (TSV, parquet, stdin) and write TSV |
|
|
166
170
|
| `clean` | Remove leftover temp parquet pipe files from interrupted pipelines |
|
|
167
171
|
| `help` | List all subcommands or show full help for one: `dftk help stat` |
|
|
168
172
|
|
|
@@ -173,8 +177,8 @@ publication-quality output.
|
|
|
173
177
|
```bash
|
|
174
178
|
# z-score sepal_length within species, then fit against petal_length
|
|
175
179
|
dftk dataset iris -o \
|
|
176
|
-
| dftk scale
|
|
177
|
-
| dftk fit
|
|
180
|
+
| dftk scale -c sepal_length -g species -o \
|
|
181
|
+
| dftk fit -f "sepal_length_scaled ~ petal_length" -g species
|
|
178
182
|
```
|
|
179
183
|
|
|
180
184
|
### Clean up spreadsheet headers
|
|
@@ -183,8 +187,8 @@ Headers such as `Country Name` or `1960` need quoting in SQL. `cleannames` turns
|
|
|
183
187
|
|
|
184
188
|
```bash
|
|
185
189
|
dftk dataset fertility -o \
|
|
186
|
-
| dftk cleannames
|
|
187
|
-
| dftk query
|
|
190
|
+
| dftk cleannames -o \
|
|
191
|
+
| dftk query --sql "SELECT country_name, x1960, x2000 FROM data LIMIT 3"
|
|
188
192
|
```
|
|
189
193
|
|
|
190
194
|
For your own export, `dftk cleannames data.tsv --backend duckdb -o data.parquet` also keeps integer columns with empty cells as integers.
|
|
@@ -195,7 +199,7 @@ With tens of thousands of points a scatter plot is a solid blob. `--hexbin` coun
|
|
|
195
199
|
|
|
196
200
|
```bash
|
|
197
201
|
dftk dataset diamonds -o \
|
|
198
|
-
| dftk scat
|
|
202
|
+
| dftk scat -x carat -y price --hexbin --hexlog --logx --logy -f diamonds.png
|
|
199
203
|
```
|
|
200
204
|
|
|
201
205
|
`--colorcol COL` colours each hexagon by the mean of `COL` instead of the count; with `--subgraphcol` all panels share one colour scale.
|
|
@@ -204,8 +208,8 @@ dftk dataset diamonds -o \
|
|
|
204
208
|
|
|
205
209
|
```bash
|
|
206
210
|
dftk dataset tips -o \
|
|
207
|
-
| dftk stat
|
|
208
|
-
| dftk line
|
|
211
|
+
| dftk stat -c tip -g day -o \
|
|
212
|
+
| dftk line -x day -y mean --yerr sem -f fig.png
|
|
209
213
|
```
|
|
210
214
|
|
|
211
215
|
### Wide-to-long then plot overlaid histograms
|
|
@@ -249,18 +253,18 @@ suffix `_r` from `merge`; fill from it, then drop it. Here the defaults are
|
|
|
249
253
|
each species' median body mass:
|
|
250
254
|
|
|
251
255
|
```bash
|
|
252
|
-
dftk dataset penguins -o | dftk pivot
|
|
256
|
+
dftk dataset penguins -o | dftk pivot -i species -v body_mass_g \
|
|
253
257
|
-f median --move median_body_mass_g:body_mass_g -o defaults.parquet
|
|
254
258
|
dftk dataset penguins -o \
|
|
255
|
-
| dftk merge
|
|
256
|
-
| dftk eval
|
|
259
|
+
| dftk merge -r defaults.parquet -k species -t left -o \
|
|
260
|
+
| dftk eval -f "body_mass_g = body_mass_g.fillna(body_mass_g_r)" \
|
|
257
261
|
--drop body_mass_g_r
|
|
258
262
|
```
|
|
259
263
|
|
|
260
264
|
**From neighbouring rows** (`co2` is a weekly series with gaps):
|
|
261
265
|
|
|
262
266
|
```bash
|
|
263
|
-
dftk dataset co2 -o | dftk eval
|
|
267
|
+
dftk dataset co2 -o | dftk eval -f "ffill = co2.ffill()" \
|
|
264
268
|
-f "bfill = co2.bfill()" -f "linear = co2.interpolate()"
|
|
265
269
|
```
|
|
266
270
|
|
|
@@ -278,9 +282,9 @@ to be next to each other, but within each group they must be in order:
|
|
|
278
282
|
|
|
279
283
|
```bash
|
|
280
284
|
dftk dataset healthexp -o \
|
|
281
|
-
| dftk eval
|
|
285
|
+
| dftk eval -f "le = Life_Expectancy.where(Year % 10 != 5)" \
|
|
282
286
|
--sortasc Country Year -o \
|
|
283
|
-
| dftk eval
|
|
287
|
+
| dftk eval -f "le_filled = le.groupby(Country).ffill()"
|
|
284
288
|
```
|
|
285
289
|
|
|
286
290
|
`interpolate()` has no grouped form. Once each group's rows are together,
|
|
@@ -290,14 +294,78 @@ with something before and after them in the same group:
|
|
|
290
294
|
|
|
291
295
|
```bash
|
|
292
296
|
dftk dataset healthexp -o \
|
|
293
|
-
| dftk eval
|
|
297
|
+
| dftk eval -f "le = Life_Expectancy.where(Year % 10 != 5)" \
|
|
294
298
|
--sortasc Country Year -o \
|
|
295
|
-
| dftk eval
|
|
299
|
+
| dftk eval -f "before = le.groupby(Country).ffill().notna()" \
|
|
296
300
|
-f "after = le.groupby(Country).bfill().notna()" \
|
|
297
301
|
-f "le_linear = le.interpolate().where(before & after)" \
|
|
298
302
|
--drop before after
|
|
299
303
|
```
|
|
300
304
|
|
|
305
|
+
### Differences between rows
|
|
306
|
+
|
|
307
|
+
For the change in a column from one row to the next, `eval -f` takes
|
|
308
|
+
pandas `diff()` and `pct_change()`, also within groups. They use the rows
|
|
309
|
+
in their order, so sort first, in a step of its own:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
dftk dataset healthexp -o | dftk eval --sortasc Country Year -o \
|
|
313
|
+
| dftk eval -f "change = Spending_USD.groupby(Country).diff().round(1)" \
|
|
314
|
+
-f "pct = (Spending_USD.groupby(Country).pct_change() * 100).round(1)" \
|
|
315
|
+
-f "years = Year.groupby(Country).diff()"
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
```text
|
|
319
|
+
Year Country Spending_USD Life_Expectancy change pct years
|
|
320
|
+
1971 Canada 313.391 72.8
|
|
321
|
+
1976 Canada 543.337 73.8 229.9 73.4 5.0
|
|
322
|
+
1979 Canada 692.269 75.1 148.9 27.4 3.0
|
|
323
|
+
1980 Canada 791.812 75.2 99.5 14.4 1.0
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
The first row of each country gets an empty cell. Without
|
|
327
|
+
`groupby(Country)`, it would be compared with the last row of the
|
|
328
|
+
previous country.
|
|
329
|
+
|
|
330
|
+
To compare a value with one in another column of the previous or next row, for example the
|
|
331
|
+
gap between segments given by `Chr`, `Begin`, `End`, use SQL's `LAG()` /
|
|
332
|
+
`LEAD()` in `query --sql`:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
dftk query segments.tsv --sql \
|
|
336
|
+
'SELECT *, "Begin" - LAG("End") OVER (PARTITION BY Chr ORDER BY "Begin")
|
|
337
|
+
AS gap
|
|
338
|
+
FROM data ORDER BY Chr, "Begin"'
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
```text
|
|
342
|
+
Chr Begin End Id gap
|
|
343
|
+
chr1 100 200 a
|
|
344
|
+
chr1 250 400 b 50
|
|
345
|
+
chr1 390 500 c -10
|
|
346
|
+
chr2 50 80 d
|
|
347
|
+
chr2 100 300 e 20
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
A negative gap is an overlap, and the first segment on each chromosome
|
|
351
|
+
gets an empty cell. `lead("Begin") OVER (...) - "End"` gives the gap to
|
|
352
|
+
the next segment instead.
|
|
353
|
+
|
|
354
|
+
- `Begin` and `End` are SQL keywords: quote such column names with double
|
|
355
|
+
quotes and the whole statement with single quotes.
|
|
356
|
+
- No sorting is needed first; `ORDER BY` inside `OVER` sets the order.
|
|
357
|
+
- Integers stay integers.
|
|
358
|
+
|
|
359
|
+
`eval -f` can do the same with pandas `shift`, but it goes by row order, so
|
|
360
|
+
sort by `Chr` and `Begin` first (results are floats):
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
dftk eval segments.tsv -f 'gap = Begin - End.groupby(Chr).shift()'
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Without `groupby(Chr)` the first segment of a chromosome is compared with
|
|
367
|
+
the last one of the previous chromosome.
|
|
368
|
+
|
|
301
369
|
### Bootstrap confidence intervals
|
|
302
370
|
|
|
303
371
|
Bootstrap mode repeats the full stat computation N times on resampled data
|
|
@@ -307,9 +375,9 @@ confidence interval:
|
|
|
307
375
|
|
|
308
376
|
```bash
|
|
309
377
|
dftk dataset tips -o \
|
|
310
|
-
| dftk stat
|
|
311
|
-
| dftk pivot
|
|
312
|
-
| dftk print
|
|
378
|
+
| dftk stat -c tip -g day --bootstrap 1000 --randomseed 42 -o \
|
|
379
|
+
| dftk pivot -i day -v mean -f mean cilo cihi -o \
|
|
380
|
+
| dftk print
|
|
313
381
|
```
|
|
314
382
|
|
|
315
383
|
## Input/output
|
|
@@ -317,15 +385,21 @@ dftk dataset tips -o \
|
|
|
317
385
|
All commands accept:
|
|
318
386
|
|
|
319
387
|
- A TSV filename as a positional argument
|
|
320
|
-
- `-` to read TSV from stdin
|
|
321
|
-
- `...` to receive a parquet path from stdin (written by a previous `-o` command)
|
|
322
388
|
- A `.parquet` filename to read a named parquet file directly
|
|
389
|
+
- Nothing, or `-`, to read stdin: either TSV, or the parquet path printed by
|
|
390
|
+
a previous command's bare `-o` (that temp file is then read and deleted)
|
|
391
|
+
- A pipe as the filename, e.g. `<(grep -v '^#' data.tsv)` or `<(dftk … -o)`,
|
|
392
|
+
read the same way as stdin
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
dftk dataset tips -o | dftk stat -c tip -g day # parquet path on stdin
|
|
396
|
+
dftk dataset tips | dftk stat -c tip -g day # TSV on stdin
|
|
397
|
+
dftk merge -l tips.tsv -r <(dftk pivot tips.tsv -i day -v tip -f mean -o) -k day
|
|
398
|
+
```
|
|
323
399
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
> parquet and prints *its path* to stdout — `-` would try to parse that path
|
|
328
|
-
> as TSV and fail.
|
|
400
|
+
Older scripts give `...` as the file to read a parquet path from stdin; that
|
|
401
|
+
still works. In zsh with Oh My Zsh an unquoted `...` becomes `../..`, so
|
|
402
|
+
leave it out (or use `-`) in scripts you share.
|
|
329
403
|
|
|
330
404
|
### Comment lines and preambles
|
|
331
405
|
|
|
@@ -47,17 +47,20 @@ uv tool install .
|
|
|
47
47
|
|
|
48
48
|
### Skill for coding agents
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
dftk ships an agent skill: a short guide that coding agents such as Codex
|
|
51
|
+
and Claude Code load when a task involves dftk. It covers the piping
|
|
52
52
|
conventions, which command to use for what, and patterns for Snakemake and
|
|
53
|
-
Make.
|
|
53
|
+
Make. Install it with:
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
dftk skill install # every agent found: ~/.claude and/or ~/.codex
|
|
57
|
+
dftk skill install --codex # only one (--claude or --codex; creates the folder)
|
|
58
|
+
dftk skill install --dir DIR # another agent's skills folder
|
|
58
59
|
```
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
It prints where it installed the skill. Run it again after upgrading dftk
|
|
62
|
+
so the skill matches the installed version; it replaces only the earlier
|
|
63
|
+
dftk skill. The source is in `src/dftk/skills/dftk/`.
|
|
61
64
|
|
|
62
65
|
## Quick example
|
|
63
66
|
|
|
@@ -65,15 +68,15 @@ Copy it again after upgrading dftk so it matches the installed version.
|
|
|
65
68
|
dftk dataset tips | dftk stat - -c tip total_bill -g day
|
|
66
69
|
```
|
|
67
70
|
|
|
68
|
-
Chain commands with `-o` (write
|
|
69
|
-
|
|
70
|
-
for large data,
|
|
71
|
-
step:
|
|
71
|
+
Chain commands with a bare `-o` (write a temp parquet, print its path)
|
|
72
|
+
instead of piping TSV text: the next command sees the path on stdin and reads
|
|
73
|
+
that file. It's faster for large data, keeps column types exact, and is the
|
|
74
|
+
recommended pattern once a pipeline has more than one step:
|
|
72
75
|
|
|
73
76
|
```bash
|
|
74
77
|
dftk dataset tips -o \
|
|
75
|
-
| dftk pivot
|
|
76
|
-
| dftk print
|
|
78
|
+
| dftk pivot -i day -v tip -f mean -o \
|
|
79
|
+
| dftk print
|
|
77
80
|
```
|
|
78
81
|
|
|
79
82
|
## Subcommands
|
|
@@ -133,7 +136,7 @@ publication-quality output.
|
|
|
133
136
|
| `sample` | Random row sampling (with or without replacement, by count or fraction) |
|
|
134
137
|
| `split` | Split a dataframe into one file per group |
|
|
135
138
|
| `annotate` | Read and write provenance metadata (genome, source, …) in parquet files |
|
|
136
|
-
| `print` | Read any dftk input (TSV,
|
|
139
|
+
| `print` | Read any dftk input (TSV, parquet, stdin) and write TSV |
|
|
137
140
|
| `clean` | Remove leftover temp parquet pipe files from interrupted pipelines |
|
|
138
141
|
| `help` | List all subcommands or show full help for one: `dftk help stat` |
|
|
139
142
|
|
|
@@ -144,8 +147,8 @@ publication-quality output.
|
|
|
144
147
|
```bash
|
|
145
148
|
# z-score sepal_length within species, then fit against petal_length
|
|
146
149
|
dftk dataset iris -o \
|
|
147
|
-
| dftk scale
|
|
148
|
-
| dftk fit
|
|
150
|
+
| dftk scale -c sepal_length -g species -o \
|
|
151
|
+
| dftk fit -f "sepal_length_scaled ~ petal_length" -g species
|
|
149
152
|
```
|
|
150
153
|
|
|
151
154
|
### Clean up spreadsheet headers
|
|
@@ -154,8 +157,8 @@ Headers such as `Country Name` or `1960` need quoting in SQL. `cleannames` turns
|
|
|
154
157
|
|
|
155
158
|
```bash
|
|
156
159
|
dftk dataset fertility -o \
|
|
157
|
-
| dftk cleannames
|
|
158
|
-
| dftk query
|
|
160
|
+
| dftk cleannames -o \
|
|
161
|
+
| dftk query --sql "SELECT country_name, x1960, x2000 FROM data LIMIT 3"
|
|
159
162
|
```
|
|
160
163
|
|
|
161
164
|
For your own export, `dftk cleannames data.tsv --backend duckdb -o data.parquet` also keeps integer columns with empty cells as integers.
|
|
@@ -166,7 +169,7 @@ With tens of thousands of points a scatter plot is a solid blob. `--hexbin` coun
|
|
|
166
169
|
|
|
167
170
|
```bash
|
|
168
171
|
dftk dataset diamonds -o \
|
|
169
|
-
| dftk scat
|
|
172
|
+
| dftk scat -x carat -y price --hexbin --hexlog --logx --logy -f diamonds.png
|
|
170
173
|
```
|
|
171
174
|
|
|
172
175
|
`--colorcol COL` colours each hexagon by the mean of `COL` instead of the count; with `--subgraphcol` all panels share one colour scale.
|
|
@@ -175,8 +178,8 @@ dftk dataset diamonds -o \
|
|
|
175
178
|
|
|
176
179
|
```bash
|
|
177
180
|
dftk dataset tips -o \
|
|
178
|
-
| dftk stat
|
|
179
|
-
| dftk line
|
|
181
|
+
| dftk stat -c tip -g day -o \
|
|
182
|
+
| dftk line -x day -y mean --yerr sem -f fig.png
|
|
180
183
|
```
|
|
181
184
|
|
|
182
185
|
### Wide-to-long then plot overlaid histograms
|
|
@@ -220,18 +223,18 @@ suffix `_r` from `merge`; fill from it, then drop it. Here the defaults are
|
|
|
220
223
|
each species' median body mass:
|
|
221
224
|
|
|
222
225
|
```bash
|
|
223
|
-
dftk dataset penguins -o | dftk pivot
|
|
226
|
+
dftk dataset penguins -o | dftk pivot -i species -v body_mass_g \
|
|
224
227
|
-f median --move median_body_mass_g:body_mass_g -o defaults.parquet
|
|
225
228
|
dftk dataset penguins -o \
|
|
226
|
-
| dftk merge
|
|
227
|
-
| dftk eval
|
|
229
|
+
| dftk merge -r defaults.parquet -k species -t left -o \
|
|
230
|
+
| dftk eval -f "body_mass_g = body_mass_g.fillna(body_mass_g_r)" \
|
|
228
231
|
--drop body_mass_g_r
|
|
229
232
|
```
|
|
230
233
|
|
|
231
234
|
**From neighbouring rows** (`co2` is a weekly series with gaps):
|
|
232
235
|
|
|
233
236
|
```bash
|
|
234
|
-
dftk dataset co2 -o | dftk eval
|
|
237
|
+
dftk dataset co2 -o | dftk eval -f "ffill = co2.ffill()" \
|
|
235
238
|
-f "bfill = co2.bfill()" -f "linear = co2.interpolate()"
|
|
236
239
|
```
|
|
237
240
|
|
|
@@ -249,9 +252,9 @@ to be next to each other, but within each group they must be in order:
|
|
|
249
252
|
|
|
250
253
|
```bash
|
|
251
254
|
dftk dataset healthexp -o \
|
|
252
|
-
| dftk eval
|
|
255
|
+
| dftk eval -f "le = Life_Expectancy.where(Year % 10 != 5)" \
|
|
253
256
|
--sortasc Country Year -o \
|
|
254
|
-
| dftk eval
|
|
257
|
+
| dftk eval -f "le_filled = le.groupby(Country).ffill()"
|
|
255
258
|
```
|
|
256
259
|
|
|
257
260
|
`interpolate()` has no grouped form. Once each group's rows are together,
|
|
@@ -261,14 +264,78 @@ with something before and after them in the same group:
|
|
|
261
264
|
|
|
262
265
|
```bash
|
|
263
266
|
dftk dataset healthexp -o \
|
|
264
|
-
| dftk eval
|
|
267
|
+
| dftk eval -f "le = Life_Expectancy.where(Year % 10 != 5)" \
|
|
265
268
|
--sortasc Country Year -o \
|
|
266
|
-
| dftk eval
|
|
269
|
+
| dftk eval -f "before = le.groupby(Country).ffill().notna()" \
|
|
267
270
|
-f "after = le.groupby(Country).bfill().notna()" \
|
|
268
271
|
-f "le_linear = le.interpolate().where(before & after)" \
|
|
269
272
|
--drop before after
|
|
270
273
|
```
|
|
271
274
|
|
|
275
|
+
### Differences between rows
|
|
276
|
+
|
|
277
|
+
For the change in a column from one row to the next, `eval -f` takes
|
|
278
|
+
pandas `diff()` and `pct_change()`, also within groups. They use the rows
|
|
279
|
+
in their order, so sort first, in a step of its own:
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
dftk dataset healthexp -o | dftk eval --sortasc Country Year -o \
|
|
283
|
+
| dftk eval -f "change = Spending_USD.groupby(Country).diff().round(1)" \
|
|
284
|
+
-f "pct = (Spending_USD.groupby(Country).pct_change() * 100).round(1)" \
|
|
285
|
+
-f "years = Year.groupby(Country).diff()"
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
```text
|
|
289
|
+
Year Country Spending_USD Life_Expectancy change pct years
|
|
290
|
+
1971 Canada 313.391 72.8
|
|
291
|
+
1976 Canada 543.337 73.8 229.9 73.4 5.0
|
|
292
|
+
1979 Canada 692.269 75.1 148.9 27.4 3.0
|
|
293
|
+
1980 Canada 791.812 75.2 99.5 14.4 1.0
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
The first row of each country gets an empty cell. Without
|
|
297
|
+
`groupby(Country)`, it would be compared with the last row of the
|
|
298
|
+
previous country.
|
|
299
|
+
|
|
300
|
+
To compare a value with one in another column of the previous or next row, for example the
|
|
301
|
+
gap between segments given by `Chr`, `Begin`, `End`, use SQL's `LAG()` /
|
|
302
|
+
`LEAD()` in `query --sql`:
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
dftk query segments.tsv --sql \
|
|
306
|
+
'SELECT *, "Begin" - LAG("End") OVER (PARTITION BY Chr ORDER BY "Begin")
|
|
307
|
+
AS gap
|
|
308
|
+
FROM data ORDER BY Chr, "Begin"'
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
```text
|
|
312
|
+
Chr Begin End Id gap
|
|
313
|
+
chr1 100 200 a
|
|
314
|
+
chr1 250 400 b 50
|
|
315
|
+
chr1 390 500 c -10
|
|
316
|
+
chr2 50 80 d
|
|
317
|
+
chr2 100 300 e 20
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
A negative gap is an overlap, and the first segment on each chromosome
|
|
321
|
+
gets an empty cell. `lead("Begin") OVER (...) - "End"` gives the gap to
|
|
322
|
+
the next segment instead.
|
|
323
|
+
|
|
324
|
+
- `Begin` and `End` are SQL keywords: quote such column names with double
|
|
325
|
+
quotes and the whole statement with single quotes.
|
|
326
|
+
- No sorting is needed first; `ORDER BY` inside `OVER` sets the order.
|
|
327
|
+
- Integers stay integers.
|
|
328
|
+
|
|
329
|
+
`eval -f` can do the same with pandas `shift`, but it goes by row order, so
|
|
330
|
+
sort by `Chr` and `Begin` first (results are floats):
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
dftk eval segments.tsv -f 'gap = Begin - End.groupby(Chr).shift()'
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Without `groupby(Chr)` the first segment of a chromosome is compared with
|
|
337
|
+
the last one of the previous chromosome.
|
|
338
|
+
|
|
272
339
|
### Bootstrap confidence intervals
|
|
273
340
|
|
|
274
341
|
Bootstrap mode repeats the full stat computation N times on resampled data
|
|
@@ -278,9 +345,9 @@ confidence interval:
|
|
|
278
345
|
|
|
279
346
|
```bash
|
|
280
347
|
dftk dataset tips -o \
|
|
281
|
-
| dftk stat
|
|
282
|
-
| dftk pivot
|
|
283
|
-
| dftk print
|
|
348
|
+
| dftk stat -c tip -g day --bootstrap 1000 --randomseed 42 -o \
|
|
349
|
+
| dftk pivot -i day -v mean -f mean cilo cihi -o \
|
|
350
|
+
| dftk print
|
|
284
351
|
```
|
|
285
352
|
|
|
286
353
|
## Input/output
|
|
@@ -288,15 +355,21 @@ dftk dataset tips -o \
|
|
|
288
355
|
All commands accept:
|
|
289
356
|
|
|
290
357
|
- A TSV filename as a positional argument
|
|
291
|
-
- `-` to read TSV from stdin
|
|
292
|
-
- `...` to receive a parquet path from stdin (written by a previous `-o` command)
|
|
293
358
|
- A `.parquet` filename to read a named parquet file directly
|
|
359
|
+
- Nothing, or `-`, to read stdin: either TSV, or the parquet path printed by
|
|
360
|
+
a previous command's bare `-o` (that temp file is then read and deleted)
|
|
361
|
+
- A pipe as the filename, e.g. `<(grep -v '^#' data.tsv)` or `<(dftk … -o)`,
|
|
362
|
+
read the same way as stdin
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
dftk dataset tips -o | dftk stat -c tip -g day # parquet path on stdin
|
|
366
|
+
dftk dataset tips | dftk stat -c tip -g day # TSV on stdin
|
|
367
|
+
dftk merge -l tips.tsv -r <(dftk pivot tips.tsv -i day -v tip -f mean -o) -k day
|
|
368
|
+
```
|
|
294
369
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
> parquet and prints *its path* to stdout — `-` would try to parse that path
|
|
299
|
-
> as TSV and fail.
|
|
370
|
+
Older scripts give `...` as the file to read a parquet path from stdin; that
|
|
371
|
+
still works. In zsh with Oh My Zsh an unquoted `...` becomes `../..`, so
|
|
372
|
+
leave it out (or use `-`) in scripts you share.
|
|
300
373
|
|
|
301
374
|
### Comment lines and preambles
|
|
302
375
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dataframe-toolkit"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.12.0"
|
|
4
4
|
description = "A command-line toolkit for DataFrame analysis and manipulation"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
keywords = [
|
|
@@ -29,6 +29,7 @@ dependencies = [
|
|
|
29
29
|
"patsy>=0.5.6",
|
|
30
30
|
"duckdb>=0.8",
|
|
31
31
|
"matplotlib>=3.7",
|
|
32
|
+
"pillow>=13.0",
|
|
32
33
|
"seaborn>=0.12",
|
|
33
34
|
"tqdm>=4.65",
|
|
34
35
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dataframe-toolkit"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.12.0"
|
|
4
4
|
description = "A command-line toolkit for DataFrame analysis and manipulation"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -26,6 +26,7 @@ dependencies = [
|
|
|
26
26
|
"patsy>=0.5.6",
|
|
27
27
|
"duckdb>=0.8",
|
|
28
28
|
"matplotlib>=3.7",
|
|
29
|
+
"pillow>=13.0", # not used directly (matplotlib needs it); floor for security fixes
|
|
29
30
|
"seaborn>=0.12",
|
|
30
31
|
"tqdm>=4.65",
|
|
31
32
|
]
|
|
@@ -26,7 +26,7 @@ Usage examples:
|
|
|
26
26
|
--meta genome=hg38 --meta source=my_pipeline
|
|
27
27
|
|
|
28
28
|
# Same, built from a bundled dataset:
|
|
29
|
-
dftk dataset iris -o | dftk eval
|
|
29
|
+
dftk dataset iris -o | dftk eval -f "z = sepal_length + petal_length" \\
|
|
30
30
|
-o result.parquet --meta genome=hg38 --meta source=my_pipeline
|
|
31
31
|
|
|
32
32
|
Annotations propagate through the parquet pipe: a file annotated at
|
|
@@ -74,10 +74,10 @@ USEVALUE (--usevalue)
|
|
|
74
74
|
EXAMPLES
|
|
75
75
|
--------
|
|
76
76
|
dftk binx data.tsv -c age -b 0:100:10
|
|
77
|
-
dftk dataset tips -o | dftk binx
|
|
78
|
-
dftk dataset tips -o | dftk binx
|
|
79
|
-
dftk dataset tips -o | dftk binx
|
|
80
|
-
| dftk stat
|
|
77
|
+
dftk dataset tips -o | dftk binx -c total_bill -b 0:60:10
|
|
78
|
+
dftk dataset tips -o | dftk binx -c tip -b 0,2,4,6,10 -d tip_bracket --usevalue m
|
|
79
|
+
dftk dataset tips -o | dftk binx -c total_bill -b 0:60:10 -d bill_bin -o \\
|
|
80
|
+
| dftk stat -c tip -g bill_bin
|
|
81
81
|
"""
|
|
82
82
|
|
|
83
83
|
|
|
@@ -116,21 +116,21 @@ EXAMPLES
|
|
|
116
116
|
Basic chi-plot:
|
|
117
117
|
|
|
118
118
|
dftk chi data.tsv -x recomb_rate -y gc_content
|
|
119
|
-
dftk dataset tips -o | dftk chi
|
|
119
|
+
dftk dataset tips -o | dftk chi -x total_bill -y tip
|
|
120
120
|
|
|
121
121
|
Split into a subplot grid by category, to check whether tail dependence is
|
|
122
122
|
consistent across the whole dataset or driven by a few subgroups (e.g.
|
|
123
123
|
chromosome, sector, region — here, diamond cut quality):
|
|
124
124
|
|
|
125
|
-
dftk dataset diamonds -o | dftk chi
|
|
125
|
+
dftk dataset diamonds -o | dftk chi -x carat -y price --subgraphcol cut
|
|
126
126
|
|
|
127
127
|
Colour-code by group instead of splitting into subplots:
|
|
128
128
|
|
|
129
|
-
dftk dataset diamonds -o | dftk chi
|
|
129
|
+
dftk dataset diamonds -o | dftk chi -x carat -y price -g cut
|
|
130
130
|
|
|
131
131
|
Publication figure (Nature single column, PDF):
|
|
132
132
|
|
|
133
|
-
dftk dataset tips -o | dftk chi
|
|
133
|
+
dftk dataset tips -o | dftk chi -x total_bill -y tip \\
|
|
134
134
|
--size single --fontsize publication -f fig.pdf
|
|
135
135
|
"""
|
|
136
136
|
|
|
@@ -57,13 +57,13 @@ column per year (1960, 1961, ...); after cleaning they can be used
|
|
|
57
57
|
unquoted in SQL:
|
|
58
58
|
|
|
59
59
|
dftk dataset fertility -o \\
|
|
60
|
-
| dftk cleannames
|
|
61
|
-
| dftk query
|
|
60
|
+
| dftk cleannames -o \\
|
|
61
|
+
| dftk query --sql "SELECT country_name, x1960, x2000 FROM data LIMIT 3"
|
|
62
62
|
|
|
63
63
|
Write the old and new names to a TSV file, e.g. for a data dictionary:
|
|
64
64
|
|
|
65
65
|
dftk dataset fertility -o \\
|
|
66
|
-
| dftk cleannames
|
|
66
|
+
| dftk cleannames --mapping names.tsv -o fertility.parquet
|
|
67
67
|
"""
|
|
68
68
|
|
|
69
69
|
# Letters that Unicode does not decompose into ASCII letter + accent
|
|
@@ -12,7 +12,7 @@ Examples
|
|
|
12
12
|
dftk concat penguins.tsv penguins.tsv --sourcecol source
|
|
13
13
|
dftk dataset penguins -o penguins.parquet
|
|
14
14
|
dftk concat penguins.parquet penguins.parquet -o
|
|
15
|
-
dftk dataset penguins -o | dftk eval
|
|
15
|
+
dftk dataset penguins -o | dftk eval -f "x=1" -o | dftk concat - penguins.tsv
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
import argparse
|
|
@@ -51,7 +51,7 @@ EXAMPLES
|
|
|
51
51
|
dftk concat penguins.tsv penguins.tsv --sourcecol source
|
|
52
52
|
dftk dataset penguins -o penguins.parquet
|
|
53
53
|
dftk concat penguins.parquet penguins.parquet -o result.parquet
|
|
54
|
-
dftk dataset penguins -o | dftk eval
|
|
54
|
+
dftk dataset penguins -o | dftk eval -f "x=1" -o | dftk concat - penguins.tsv
|
|
55
55
|
|
|
56
56
|
Mismatched columns are outer-joined and filled (NaN by default, or --fill):
|
|
57
57
|
|
|
@@ -65,7 +65,7 @@ Mismatched columns are outer-joined and filled (NaN by default, or --fill):
|
|
|
65
65
|
metavar="FILE",
|
|
66
66
|
help=(
|
|
67
67
|
"Input files to concatenate (TSV or .parquet). "
|
|
68
|
-
"Use - for TSV
|
|
68
|
+
"Use - for stdin (TSV, or a parquet path from -o). "
|
|
69
69
|
"At most one stdin source is allowed."
|
|
70
70
|
),
|
|
71
71
|
)
|