aspect-data 0.0.5__tar.gz → 0.0.7__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.
Files changed (44) hide show
  1. aspect_data-0.0.7/PKG-INFO +1163 -0
  2. aspect_data-0.0.7/README.md +1097 -0
  3. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/cli_module/cli.py +24 -5
  4. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/cli_module/featurize.py +37 -18
  5. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/collate/base.py +14 -2
  6. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/data.py +172 -231
  7. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/transform/base.py +7 -6
  8. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/typing.py +1 -7
  9. aspect_data-0.0.7/aspect_data.egg-info/PKG-INFO +1163 -0
  10. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect_data.egg-info/SOURCES.txt +2 -5
  11. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect_data.egg-info/requires.txt +3 -3
  12. {aspect_data-0.0.5 → aspect_data-0.0.7}/pyproject.toml +5 -4
  13. aspect_data-0.0.7/test/test_checkpoint.py +245 -0
  14. {aspect_data-0.0.5 → aspect_data-0.0.7}/test/test_collate.py +2 -2
  15. aspect_data-0.0.7/test/test_data_source.py +22 -0
  16. {aspect_data-0.0.5 → aspect_data-0.0.7}/test/test_dataloader.py +3 -3
  17. aspect_data-0.0.7/test/test_empty_pipeline.py +33 -0
  18. aspect_data-0.0.7/test/test_feature_shape.py +21 -0
  19. {aspect_data-0.0.5 → aspect_data-0.0.7}/test/test_transform_dict.py +3 -4
  20. aspect_data-0.0.5/PKG-INFO +0 -931
  21. aspect_data-0.0.5/README.md +0 -866
  22. aspect_data-0.0.5/aspect/checkpoint_utils.py +0 -95
  23. aspect_data-0.0.5/aspect/cli_module/io.py +0 -52
  24. aspect_data-0.0.5/aspect/io.py +0 -409
  25. aspect_data-0.0.5/aspect/package_data.py +0 -54
  26. aspect_data-0.0.5/aspect_data.egg-info/PKG-INFO +0 -931
  27. aspect_data-0.0.5/test/test_checkpoint.py +0 -140
  28. aspect_data-0.0.5/test/test_data_source.py +0 -19
  29. aspect_data-0.0.5/test/test_io.py +0 -125
  30. {aspect_data-0.0.5 → aspect_data-0.0.7}/LICENSE +0 -0
  31. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/__init__.py +0 -0
  32. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/cli_module/__init__.py +0 -0
  33. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/collate/__init__.py +0 -0
  34. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/collate/chemprop.py +0 -0
  35. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/transform/__init__.py +0 -0
  36. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/transform/chemprop.py +0 -0
  37. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/transform/deep_functions.py +0 -0
  38. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/transform/functions.py +0 -0
  39. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect/transform/registry.py +0 -0
  40. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect_data.egg-info/dependency_links.txt +0 -0
  41. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect_data.egg-info/entry_points.txt +0 -0
  42. {aspect_data-0.0.5 → aspect_data-0.0.7}/aspect_data.egg-info/top_level.txt +0 -0
  43. {aspect_data-0.0.5 → aspect_data-0.0.7}/setup.cfg +0 -0
  44. {aspect_data-0.0.5 → aspect_data-0.0.7}/test/test_collate_chemprop.py +0 -0
@@ -0,0 +1,1163 @@
1
+ Metadata-Version: 2.4
2
+ Name: aspect-data
3
+ Version: 0.0.7
4
+ Summary: General purpose, chemistry, and taxonomic featurization of tabular data with caching.
5
+ Author-email: Eachan Johnson <eachan.johnson@crick.ac.uk>
6
+ License: MIT License
7
+
8
+ Copyright (c) [year] [fullname]
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Project-URL: Homepage, https://github.com/scbirlab/aspect
28
+ Project-URL: Bug Tracker, https://github.com/scbirlab/aspect/issues
29
+ Keywords: ai,data,deep-learning,machine-learning
30
+ Classifier: Development Status :: 3 - Alpha
31
+ Classifier: Intended Audience :: Science/Research
32
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Programming Language :: Python :: 3.11
35
+ Classifier: Programming Language :: Python :: 3.12
36
+ Classifier: Programming Language :: Python :: 3.13
37
+ Classifier: Programming Language :: Python :: 3.14
38
+ Classifier: Programming Language :: Python :: 3.15
39
+ Classifier: Programming Language :: Python :: 3 :: Only
40
+ Requires-Python: >=3.11
41
+ Description-Content-Type: text/markdown
42
+ License-File: LICENSE
43
+ Requires-Dist: carabiner-tools[mpl,pd]>=0.0.5.post3
44
+ Requires-Dist: datasets>=3.0.0
45
+ Requires-Dist: filelock
46
+ Requires-Dist: huggingface_hub
47
+ Requires-Dist: numpy
48
+ Requires-Dist: providence>=0.0.2
49
+ Requires-Dist: tqdm
50
+ Provides-Extra: chem
51
+ Requires-Dist: schemist>=0.0.7; extra == "chem"
52
+ Provides-Extra: torch
53
+ Requires-Dist: torch>=2.4; extra == "torch"
54
+ Provides-Extra: chemprop
55
+ Requires-Dist: aspect-data[chem,torch]; extra == "chemprop"
56
+ Requires-Dist: chemprop>=2.1.0; extra == "chemprop"
57
+ Provides-Extra: deep
58
+ Requires-Dist: transformers; extra == "deep"
59
+ Provides-Extra: bio
60
+ Requires-Dist: vectome>=0.0.8; extra == "bio"
61
+ Provides-Extra: dev
62
+ Requires-Dist: aspect-data[bio,chemprop]; extra == "dev"
63
+ Requires-Dist: pytest>=7.4; extra == "dev"
64
+ Requires-Dist: flake8; extra == "dev"
65
+ Dynamic: license-file
66
+
67
+ # 🏔️ aspect
68
+
69
+ ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/scbirlab/aspect/python-publish.yml)
70
+ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/aspect-data)
71
+ ![PyPI](https://img.shields.io/pypi/v/aspect-data)
72
+
73
+ <img src="docs/source/_static/logo.svg" width="200">
74
+
75
+ **aspect** is a Python library and command-line tool for reproducible featurisation of tabular machine-learning datasets.
76
+
77
+ It lets you define independent transformation pipelines for different input columns, including molecular structures, taxonomy, categorical variables, and numerical measurements. Pipelines can be serialised, applied to new datasets, checkpointed, and restored.
78
+
79
+ Aspect uses [Providence](https://github.com/scbirlab/providence) for dataset loading, source provenance, and checkpointing, and [Hugging Face Datasets](https://huggingface.co/docs/datasets/) for Arrow-backed data processing and caching.
80
+
81
+ The core idea:
82
+
83
+ ```text
84
+ Input dataset
85
+ │
86
+ ├── SMILES ──────→ Molecular fingerprints
87
+ ├── Species ─────→ Taxonomic fingerprints
88
+ ├── Assay ───────→ Categorical encoding
89
+ ├── MW ──────────→ Log transformation
90
+ └── Description ─→ Language-model embeddings
91
+ │
92
+ ▼
93
+ Aspect DataPipeline
94
+ │
95
+ ├── Reusable feature specification
96
+ ├── Reproducible dataset checkpoint
97
+ └── Optional source materialisation
98
+ │
99
+ ▼
100
+ Providence DataResolver
101
+ │
102
+ ├── Hugging Face Dataset
103
+ ├── Export: CSV / TSV / JSON / Parquet
104
+ └── Model-specific collation / DataLoader
105
+ ```
106
+
107
+ Feature representations are stored in Arrow-compatible columns. Model-specific collators can convert these stored values into tensors, molecular graphs, or other runtime representations without embedding model-specific logic in dataset preprocessing.
108
+
109
+ ## Contents
110
+
111
+ - [Quick start](#quick-start)
112
+ - [Installation](#installation)
113
+ - [Command-line interface](#command-line-interface)
114
+ - [Python API](#python-api)
115
+ - [Feature specifications](#feature-specifications)
116
+ - [Available transforms](#available-transforms)
117
+ - [Saving and loading pipelines](#saving-and-loading-pipelines)
118
+ - [Supported input and output formats](#supported-input-and-output-formats)
119
+ - [Working with output columns](#working-with-output-columns)
120
+ - [Custom transforms](#custom-transforms)
121
+ - [Model integration](#model-integration)
122
+ - [Development](#development)
123
+ - [Issues and documentation](#issues-and-documentation)
124
+
125
+ ---
126
+
127
+ ## Quick start
128
+
129
+ ### 1. Featurise a dataset
130
+
131
+ Create a small CSV:
132
+
133
+ ```bash
134
+ cat > compounds.csv <<'CSV'
135
+ compound_id,assay,mwt,pIC50
136
+ cmpd-1,MIC,46.07,5.0
137
+ cmpd-2,MIC,60.10,6.2
138
+ cmpd-3,IC50,78.11,4.8
139
+ CSV
140
+ ```
141
+
142
+ Generate numeric and categorical features:
143
+
144
+ ```bash
145
+ aspect featurize compounds.csv \
146
+ --features mwt:log@log_mwt assay:hash@assay_hash pIC50@target \
147
+ --extras compound_id \
148
+ --output features.parquet
149
+ ```
150
+
151
+ The feature specification defines the transformations:
152
+
153
+ | Specification | Meaning |
154
+ |---|---|
155
+ | `mwt:log@log_mwt` | Apply natural logarithm to `mwt` |
156
+ | `assay:hash@assay_hash` | Hash the assay category into a fixed-length vector |
157
+ | `pIC50@target` | Copy `pIC50` into a feature named `target` |
158
+ | `--extras compound_id` | Explicitly retain the compound identifier |
159
+
160
+ By default, Aspect also retains original input columns.
161
+
162
+ ### 2. Save a reproducible checkpoint
163
+
164
+ The same command can save a checkpoint alongside the exported table:
165
+
166
+ ```bash
167
+ aspect featurize compounds.csv \
168
+ --features mwt:log@log_mwt assay:hash@assay_hash \
169
+ --checkpoint features.as \
170
+ --output features.parquet
171
+ ```
172
+
173
+ The checkpoint records the feature specification, data source, and information needed to reconstruct the transformed dataset.
174
+
175
+ ### 3. Restore and export
176
+
177
+ Reconstruct the transformed dataset from its checkpoint:
178
+
179
+ ```bash
180
+ aspect write features.as \
181
+ --output restored.parquet
182
+ ```
183
+
184
+ Export it in another format:
185
+
186
+ ```bash
187
+ aspect write features.as \
188
+ --output restored.csv.gz
189
+ ```
190
+
191
+ ### 4. Python API
192
+
193
+ ```python
194
+ from aspect.data import DataPipeline
195
+
196
+ data = {
197
+ "compound_id": ["cmpd-1", "cmpd-2", "cmpd-3"],
198
+ "assay": ["MIC", "MIC", "IC50"],
199
+ "mwt": [46.07, 60.10, 78.11],
200
+ }
201
+
202
+ pipe = DataPipeline(
203
+ column_transforms={
204
+ "log_mwt": ("mwt", "log"),
205
+ "assay_hash": (
206
+ "assay",
207
+ {"name": "hash", "kwargs": {"ndim": 8}},
208
+ ),
209
+ },
210
+ columns_to_keep=["compound_id"],
211
+ )
212
+
213
+ resolved = pipe(data, drop_unused_columns=True)
214
+
215
+ # Access the underlying Hugging Face Dataset
216
+ features = resolved.data
217
+
218
+ print(features.column_names)
219
+ print(features[:2])
220
+ ```
221
+
222
+ The transformed dataset contains:
223
+
224
+ ```text
225
+ ['compound_id', 'log_mwt', 'assay_hash']
226
+ ```
227
+
228
+ `log_mwt` contains a numeric feature with shape `(n, 1)`, while `assay_hash` contains an `(n, 8)` feature matrix.
229
+
230
+ Save and reload the pipeline:
231
+
232
+ ```python
233
+ pipe.save("features.as")
234
+
235
+ restored = DataPipeline.load("features.as")
236
+ print(restored.data_out.data[:2])
237
+ ```
238
+
239
+ ---
240
+
241
+ ## Installation
242
+
243
+ Aspect requires Python 3.11 or later.
244
+
245
+ ### Basic installation
246
+
247
+ ```bash
248
+ pip install aspect-data
249
+ ```
250
+
251
+ ### Optional dependencies
252
+
253
+ Install only the features you need:
254
+
255
+ | Extra | Functionality | Installation |
256
+ |---|---|---|
257
+ | `chem` | Molecular fingerprints and descriptors via Schemist | `pip install "aspect-data[chem]"` |
258
+ | `bio` | Taxonomic fingerprints via Vectome | `pip install "aspect-data[bio]"` |
259
+ | `torch` | PyTorch integration | `pip install "aspect-data[torch]"` |
260
+ | `chemprop` | Chemprop molecular features | `pip install "aspect-data[chemprop]"` |
261
+ | `deep` | Transformer-based embeddings | `pip install "aspect-data[deep]"` |
262
+
263
+ ### Install from source
264
+
265
+ ```bash
266
+ git clone https://github.com/scbirlab/aspect.git
267
+ cd aspect
268
+ pip install -e ".[dev]"
269
+ ```
270
+
271
+ Aspect depends on [Providence](https://github.com/scbirlab/providence) (`>=0.0.2`), which provides the common dataset-resolution and checkpointing infrastructure.
272
+
273
+ ---
274
+
275
+ ## Command-line interface
276
+
277
+ Aspect provides three commands:
278
+
279
+ ```bash
280
+ aspect serialize
281
+ aspect featurize
282
+ aspect write
283
+ ```
284
+
285
+ View available arguments with:
286
+
287
+ ```bash
288
+ aspect --help
289
+ aspect featurize --help
290
+ aspect serialize --help
291
+ aspect write --help
292
+ ```
293
+
294
+ ### `aspect serialize`
295
+
296
+ Create a reusable feature specification without processing a dataset:
297
+
298
+ ```bash
299
+ aspect serialize \
300
+ --features mwt:log@log_mwt assay:hash@assay_hash \
301
+ --extras compound_id \
302
+ --output feature-spec.as
303
+ ```
304
+
305
+ The specification can then be applied to other datasets:
306
+
307
+ ```bash
308
+ aspect featurize new-compounds.csv \
309
+ --config feature-spec.as \
310
+ --output new-features.parquet
311
+ ```
312
+
313
+ ### `aspect featurize`
314
+
315
+ Apply a feature specification or saved pipeline to a dataset.
316
+
317
+ ```bash
318
+ aspect featurize compounds.csv \
319
+ --features mwt:log@log_mwt assay:hash@assay_hash \
320
+ --output features.parquet
321
+ ```
322
+
323
+ A saved specification can be supplied with `--config`:
324
+
325
+ ```bash
326
+ aspect featurize compounds.csv \
327
+ --config feature-spec.as \
328
+ --output features.parquet
329
+ ```
330
+
331
+ #### Checkpoint without exporting
332
+
333
+ ```bash
334
+ aspect featurize compounds.csv \
335
+ --config feature-spec.as \
336
+ --checkpoint features.as
337
+ ```
338
+
339
+ #### Save source and transformed data
340
+
341
+ ```bash
342
+ aspect featurize compounds.csv \
343
+ --config feature-spec.as \
344
+ --checkpoint features.as \
345
+ --force-write-data
346
+ ```
347
+
348
+ This requests materialisation of both source and transformed data inside the checkpoint, making it less dependent on the original dataset remaining available.
349
+
350
+ Without this option, Providence can retain immutable remote datasets by reference, avoiding unnecessary duplication. Local inputs are generally packaged by the current implementation.
351
+
352
+ #### Process a subset of rows
353
+
354
+ ```bash
355
+ aspect featurize large-table.parquet \
356
+ --start 1000 \
357
+ --end 2000 \
358
+ --features mwt:log@log_mwt \
359
+ --checkpoint subset.as
360
+ ```
361
+
362
+ `--start` is inclusive and `--end` is exclusive. The example selects rows 1000–1999.
363
+
364
+ #### Configure the cache
365
+
366
+ ```bash
367
+ aspect featurize compounds.csv \
368
+ --features assay:hash@assay_hash \
369
+ --cache .cache \
370
+ --output features.parquet
371
+ ```
372
+
373
+ ### `aspect write`
374
+
375
+ Export data from a saved Aspect checkpoint:
376
+
377
+ ```bash
378
+ aspect write features.as --output features.csv
379
+ aspect write features.as --output features.csv.gz
380
+ aspect write features.as --output features.parquet
381
+ aspect write features.as --output features.hf
382
+ ```
383
+
384
+ The checkpoint is loaded through `DataPipeline.load()` and the output is delegated to Providence.
385
+
386
+ If the checkpoint contains only a feature specification and no source dataset, there is no transformed table to export.
387
+
388
+ ---
389
+
390
+ ## Python API
391
+
392
+ The main class is `DataPipeline`.
393
+
394
+ ```python
395
+ from aspect.data import DataPipeline
396
+ ```
397
+
398
+ A pipeline maps input columns to named output features.
399
+
400
+ ```python
401
+ pipe = DataPipeline({
402
+ "log_mwt": ("mwt", "log"),
403
+ "assay_hash": (
404
+ "assay",
405
+ {"name": "hash", "kwargs": {"ndim": 16}},
406
+ ),
407
+ })
408
+ ```
409
+
410
+ ### Input data
411
+
412
+ Pipelines can be applied to Python mappings, Pandas DataFrames, Hugging Face datasets, local files, or Providence resolvers.
413
+
414
+ ```python
415
+ # Dictionary
416
+ resolved = pipe({
417
+ "mwt": [46.07, 60.10],
418
+ "assay": ["MIC", "IC50"],
419
+ })
420
+
421
+ # Pandas DataFrame
422
+ resolved = pipe(df)
423
+
424
+ # Local file
425
+ resolved = pipe("compounds.csv")
426
+
427
+ # Hugging Face Hub dataset
428
+ resolved = pipe(
429
+ "hf://datasets/scbirlab/fang-2023-biogen-adme~scaffold-split:train"
430
+ )
431
+ ```
432
+
433
+ ### Providence integration
434
+
435
+ Aspect uses Providence's `DataResolver` to manage source datasets and transformed results.
436
+
437
+ ```python
438
+ from providence import DataResolver
439
+ from aspect.data import DataPipeline
440
+
441
+ source = DataResolver("compounds.csv")
442
+
443
+ pipe = DataPipeline({
444
+ "log_mwt": ("mwt", "log"),
445
+ })
446
+
447
+ result = pipe(source)
448
+
449
+ # Underlying datasets
450
+ input_ds = pipe.data_in.data
451
+ output_ds = result.data
452
+
453
+ # Source metadata
454
+ source_info = pipe.data_in.data_source
455
+
456
+ print(output_ds.column_names)
457
+ ```
458
+
459
+ `DataPipeline.__call__()` returns a `DataResolver`, rather than a raw Hugging Face dataset.
460
+
461
+ The underlying dataset remains available through `.data`, and provenance is tracked through the resolver.
462
+
463
+ ### Exporting results
464
+
465
+ ```python
466
+ pipe.write_table("features.parquet")
467
+ pipe.write_table("features.csv.gz")
468
+ ```
469
+
470
+ This delegates serialization to Providence.
471
+
472
+ ### Selecting rows
473
+
474
+ For explicit row selection, create and slice the resolver before passing it to Aspect:
475
+
476
+ ```python
477
+ source = DataResolver("compounds.csv")
478
+ source = source.select_rows(start=100, end=200)
479
+
480
+ result = pipe(source)
481
+ ```
482
+
483
+ ### Reusing transformations
484
+
485
+ The same feature specification can be applied to multiple datasets:
486
+
487
+ ```python
488
+ pipe = DataPipeline({
489
+ "log_mwt": ("mwt", "log"),
490
+ })
491
+
492
+ train = pipe("train.csv")
493
+ test = pipe("test.csv")
494
+ ```
495
+
496
+ Each call returns the corresponding transformed resolver. The pipeline's `data_in` and `data_out` attributes refer to the most recent call.
497
+
498
+ ---
499
+
500
+ ## Feature specifications
501
+
502
+ Aspect supports both structured Python specifications and compact CLI strings.
503
+
504
+ ### Python specifications
505
+
506
+ The basic format is:
507
+
508
+ ```python
509
+ {
510
+ "output_column": ("input_column", "transform_name")
511
+ }
512
+ ```
513
+
514
+ Example:
515
+
516
+ ```python
517
+ pipe = DataPipeline({
518
+ "log_mwt": ("mwt", "log"),
519
+ })
520
+ ```
521
+
522
+ ### Parameterised transforms
523
+
524
+ Pass a dictionary containing the transform name and keyword arguments:
525
+
526
+ ```python
527
+ pipe = DataPipeline({
528
+ "assay_hash": (
529
+ "assay",
530
+ {
531
+ "name": "hash",
532
+ "kwargs": {
533
+ "ndim": 32,
534
+ "seed": 123,
535
+ },
536
+ },
537
+ ),
538
+ })
539
+ ```
540
+
541
+ ### Chained transforms
542
+
543
+ Pass a sequence of transformations:
544
+
545
+ ```python
546
+ pipe = DataPipeline({
547
+ "scaled_log_mwt": (
548
+ "mwt",
549
+ [
550
+ "log",
551
+ {
552
+ "name": "scale",
553
+ "kwargs": {"factor": 0.1},
554
+ },
555
+ ],
556
+ ),
557
+ })
558
+ ```
559
+
560
+ The `scale` transform in this example is a custom transform that must be registered first.
561
+
562
+ Chains execute in the supplied order. Each transform must accept the representation produced by the preceding transform.
563
+
564
+ ### CLI specifications
565
+
566
+ The CLI format is:
567
+
568
+ ```text
569
+ input_column:transform@output_column
570
+ ```
571
+
572
+ | Syntax | Behaviour |
573
+ |---|---|
574
+ | `column` | Retain an input column |
575
+ | `column@new_name` | Identity transformation with a new name |
576
+ | `column:transform` | Apply a transform and automatically name the output |
577
+ | `column:transform@new_name` | Apply a transform with an explicit output name |
578
+ | `column:t1:t2@new_name` | Chain transformations |
579
+ | `column:transform(arg=value)@name` | Pass simple transform arguments |
580
+
581
+ Example:
582
+
583
+ ```bash
584
+ aspect featurize compounds.csv \
585
+ --features \
586
+ mwt:log@log_mwt \
587
+ assay:hash(ndim=32)@assay_hash \
588
+ pIC50@target \
589
+ --output features.parquet
590
+ ```
591
+
592
+ Simple integers, floats, and booleans are parsed automatically. For complex or nested parameters, use the Python API.
593
+
594
+ ---
595
+
596
+ ## Available transforms
597
+
598
+ ### Base transforms
599
+
600
+ Available with the standard installation:
601
+
602
+ | Transform | Input | Output |
603
+ |---|---|---|
604
+ | `identity` | Any supported column | Identity representation |
605
+ | `log` | Numeric | Natural logarithm |
606
+ | `hash` | Categorical/string | Deterministic fixed-length vector |
607
+ | `one-hot` | Categorical | One-hot vector |
608
+
609
+ Example:
610
+
611
+ ```python
612
+ pipe = DataPipeline({
613
+ "log_mwt": ("mwt", "log"),
614
+ "assay_hash": (
615
+ "assay",
616
+ {"name": "hash", "kwargs": {"ndim": 16}},
617
+ ),
618
+ "assay_onehot": (
619
+ "assay",
620
+ {
621
+ "name": "one-hot",
622
+ "kwargs": {"categories": ["MIC", "IC50"]},
623
+ },
624
+ ),
625
+ })
626
+ ```
627
+
628
+ ### Chemistry transforms
629
+
630
+ Install with:
631
+
632
+ ```bash
633
+ pip install "aspect-data[chem]"
634
+ ```
635
+
636
+ | Transform | Input | Output |
637
+ |---|---|---|
638
+ | `morgan-fingerprint` | SMILES | Molecular fingerprint |
639
+ | `descriptors-2d` | SMILES | 2D molecular descriptors |
640
+ | `descriptors-3d` | SMILES | 3D molecular descriptors |
641
+
642
+ Example:
643
+
644
+ ```python
645
+ data = {
646
+ "compound_id": ["ethanol", "ethylamine", "benzene"],
647
+ "smiles": ["CCO", "CCN", "c1ccccc1"],
648
+ }
649
+
650
+ pipe = DataPipeline(
651
+ {
652
+ "morgan": ("smiles", "morgan-fingerprint"),
653
+ "desc2d": ("smiles", "descriptors-2d"),
654
+ },
655
+ columns_to_keep=["compound_id"],
656
+ )
657
+
658
+ features = pipe(data, drop_unused_columns=True).data
659
+ ```
660
+
661
+ ### Taxonomic transforms
662
+
663
+ Install with:
664
+
665
+ ```bash
666
+ pip install "aspect-data[bio]"
667
+ ```
668
+
669
+ The `vectome-fingerprint` transform encodes species names or taxonomic identifiers as fixed-length taxonomic representations.
670
+
671
+ ```python
672
+ data = {
673
+ "species": [
674
+ "Mycobacterium tuberculosis",
675
+ "Escherichia coli",
676
+ "Staphylococcus aureus",
677
+ ],
678
+ }
679
+
680
+ pipe = DataPipeline({
681
+ "species_fp": (
682
+ "species",
683
+ {
684
+ "name": "vectome-fingerprint",
685
+ "kwargs": {"ndim": 128},
686
+ },
687
+ ),
688
+ })
689
+
690
+ features = pipe(data).data
691
+ ```
692
+
693
+ ### Deep-learning transforms
694
+
695
+ Install with:
696
+
697
+ ```bash
698
+ pip install "aspect-data[deep]"
699
+ ```
700
+
701
+ The `hf-bart` transform supports transformer-derived text embeddings.
702
+
703
+ ```python
704
+ data = {
705
+ "description": [
706
+ "cell wall inhibitor",
707
+ "protein synthesis inhibitor",
708
+ "DNA gyrase inhibitor",
709
+ ],
710
+ }
711
+
712
+ pipe = DataPipeline({
713
+ "text_embedding": (
714
+ "description",
715
+ {
716
+ "name": "hf-bart",
717
+ "kwargs": {
718
+ "ref": "facebook/bart-base",
719
+ "aggregator": ["mean", "max"],
720
+ },
721
+ },
722
+ ),
723
+ })
724
+
725
+ features = pipe(data).data
726
+ ```
727
+
728
+ Model weights may be downloaded on first use.
729
+
730
+ ### Chemprop transforms
731
+
732
+ Install with:
733
+
734
+ ```bash
735
+ pip install "aspect-data[chemprop]"
736
+ ```
737
+
738
+ The `chemprop-mol` transform prepares molecular datapoints for Chemprop-style graph models.
739
+
740
+ Molecular graphs generally require model-specific batching. Aspect separates dataset storage from runtime collation so graph representations can be reconstructed when needed.
741
+
742
+ ---
743
+
744
+ ## Saving and loading pipelines
745
+
746
+ Aspect supports reusable feature specifications and provenance-aware dataset checkpoints.
747
+
748
+ ### Save a feature specification
749
+
750
+ Create a pipeline without applying it to any dataset:
751
+
752
+ ```python
753
+ pipe = DataPipeline({
754
+ "log_mwt": ("mwt", "log"),
755
+ "assay_hash": (
756
+ "assay",
757
+ {"name": "hash", "kwargs": {"ndim": 16}},
758
+ ),
759
+ })
760
+
761
+ pipe.save("feature-spec.as")
762
+ ```
763
+
764
+ Restore and apply it later:
765
+
766
+ ```python
767
+ from aspect.data import DataPipeline
768
+
769
+ pipe = DataPipeline.load("feature-spec.as")
770
+
771
+ result = pipe({
772
+ "mwt": [46.07, 60.10],
773
+ "assay": ["MIC", "IC50"],
774
+ })
775
+ ```
776
+
777
+ ### Checkpoint a transformed dataset
778
+
779
+ ```python
780
+ pipe = DataPipeline({
781
+ "log_mwt": ("mwt", "log"),
782
+ })
783
+
784
+ result = pipe("compounds.csv")
785
+ pipe.save("features.as")
786
+ ```
787
+
788
+ The checkpoint records the pipeline configuration and a Providence checkpoint describing the input dataset.
789
+
790
+ Load it again:
791
+
792
+ ```python
793
+ restored = DataPipeline.load("features.as")
794
+
795
+ features = restored.data_out.data
796
+ ```
797
+
798
+ By default, when transformed data has not been explicitly saved, loading reconstructs it by applying the feature pipeline to the restored source dataset.
799
+
800
+ ### Materialise transformed data
801
+
802
+ ```python
803
+ pipe.save(
804
+ "features.as",
805
+ save_transformed=True,
806
+ )
807
+ ```
808
+
809
+ This stores a transformed-data checkpoint alongside the source checkpoint.
810
+
811
+ ### Package source data
812
+
813
+ ```python
814
+ pipe.save(
815
+ "features.as",
816
+ save_source_data=True,
817
+ save_transformed=True,
818
+ )
819
+ ```
820
+
821
+ This requests packaging of the input data and transformed data.
822
+
823
+ For remote datasets with immutable revisions, Providence can instead retain source references, allowing checkpoints to be substantially smaller.
824
+
825
+ Local sources are normally materialised to preserve reproducibility.
826
+
827
+ ### Load without applying transformations
828
+
829
+ ```python
830
+ pipe = DataPipeline.load(
831
+ "features.as",
832
+ skip_call=True,
833
+ )
834
+ ```
835
+
836
+ This restores the specification and available checkpoint artefacts without automatically running the transformation pipeline.
837
+
838
+ ### Checkpoint layout
839
+
840
+ A checkpoint may contain:
841
+
842
+ ```text
843
+ features.as/
844
+ ├── config.json
845
+ ├── data.pv/
846
+ └── transformed.pv/
847
+ ```
848
+
849
+ `config.json` contains the pipeline specification and checkpoint metadata.
850
+
851
+ `data.pv` contains the Providence source checkpoint.
852
+
853
+ `transformed.pv` is included when transformed data is explicitly checkpointed.
854
+
855
+ The contents of Providence checkpoints depend on whether datasets are retained by reference or materialised.
856
+
857
+ ### Compatibility
858
+
859
+ The legacy methods `save_checkpoint()` and `load_checkpoint()` remain available as compatibility aliases, but new code should use `save()` and `load()`.
860
+
861
+ ---
862
+
863
+ ## Supported input and output formats
864
+
865
+ ### Input types
866
+
867
+ Aspect accepts the input types supported by Providence, including:
868
+
869
+ | Input | Example |
870
+ |---|---|
871
+ | Python mapping | `{"smiles": ["CCO", "CCN"]}` |
872
+ | Pandas DataFrame | `pipe(df)` |
873
+ | Hugging Face Dataset | `pipe(dataset)` |
874
+ | Hugging Face IterableDataset | `pipe(iterable_dataset)` |
875
+ | Local file | `pipe("data.csv")` |
876
+ | Hugging Face dataset reference | `pipe("hf://datasets/org/repo~config:split")` |
877
+ | Providence DataResolver | `pipe(resolved)` |
878
+
879
+ ### Local files
880
+
881
+ Commonly supported formats include:
882
+
883
+ - CSV: `.csv`, `.csv.gz`
884
+ - Tab-separated: `.tsv`, `.tsv.gz`, `.txt`, `.txt.gz`
885
+ - JSON: `.json`
886
+ - Parquet: `.parquet`
887
+ - Arrow: `.arrow`
888
+ - XML: `.xml`
889
+ - Saved Hugging Face datasets: `.hf`
890
+
891
+ ### Output formats
892
+
893
+ The CLI and `write_table()` use Providence to select an output format from the filename.
894
+
895
+ | Extension | Format |
896
+ |---|---|
897
+ | `.csv` | CSV |
898
+ | `.csv.gz` | Gzip-compressed CSV |
899
+ | `.tsv`, `.txt` | Tab-separated text |
900
+ | `.tsv.gz`, `.txt.gz` | Gzip-compressed tab-separated text |
901
+ | `.json` | JSON |
902
+ | `.parquet` | Parquet |
903
+ | `.hf` | Hugging Face dataset directory |
904
+ | Unrecognised | Hugging Face dataset directory with `.hf` appended |
905
+
906
+ ### Hugging Face Hub references
907
+
908
+ Providence supports versioned dataset references:
909
+
910
+ ```text
911
+ hf://datasets/<owner>/<repo>~<config>:<split>@<revision>
912
+ ```
913
+
914
+ For example:
915
+
916
+ ```text
917
+ hf://datasets/scbirlab/fang-2023-biogen-adme~scaffold-split:train
918
+ ```
919
+
920
+ The revision, configuration, and split are optional where supported by the resolver.
921
+
922
+ Pinning a dataset to an immutable commit revision improves reproducibility.
923
+
924
+ ---
925
+
926
+ ## Working with output columns
927
+
928
+ By default, Aspect retains original columns and adds transformed features.
929
+
930
+ ```python
931
+ out = pipe(data)
932
+ ```
933
+
934
+ To retain only transformed features and explicitly selected metadata:
935
+
936
+ ```python
937
+ pipe = DataPipeline(
938
+ {
939
+ "log_mwt": ("mwt", "log"),
940
+ "assay_hash": ("assay", "hash"),
941
+ },
942
+ columns_to_keep=["compound_id"],
943
+ )
944
+
945
+ out = pipe(
946
+ data,
947
+ drop_unused_columns=True,
948
+ )
949
+ ```
950
+
951
+ Extra columns can also be specified at call time:
952
+
953
+ ```python
954
+ out = pipe(
955
+ data,
956
+ drop_unused_columns=True,
957
+ keep_extra_columns=["compound_id", "target"],
958
+ )
959
+ ```
960
+
961
+ Access the underlying output dataset using:
962
+
963
+ ```python
964
+ dataset = out.data
965
+ print(dataset.features)
966
+ print(dataset.column_names)
967
+ ```
968
+
969
+ ---
970
+
971
+ ## Custom transforms
972
+
973
+ Custom transforms can be registered through Aspect's transform registry.
974
+
975
+ A transform factory receives configuration arguments and returns a callable that operates on data batches.
976
+
977
+ ```python
978
+ import numpy as np
979
+
980
+ from aspect.data import DataPipeline
981
+ from aspect.transform.registry import register_function
982
+
983
+
984
+ @register_function("square")
985
+ def Square():
986
+ def _square(data, input_column):
987
+ x = np.asarray(data[input_column], dtype=float)
988
+ return x ** 2
989
+
990
+ return _square
991
+
992
+
993
+ pipe = DataPipeline({
994
+ "mwt_squared": ("mwt", "square"),
995
+ })
996
+
997
+ out = pipe({
998
+ "mwt": [46.07, 60.10, 78.11],
999
+ }).data
1000
+ ```
1001
+
1002
+ ### Parameterised transforms
1003
+
1004
+ ```python
1005
+ @register_function("scale")
1006
+ def Scale(factor=1.0):
1007
+ def _scale(data, input_column):
1008
+ x = np.asarray(data[input_column], dtype=float)
1009
+ return x * factor
1010
+
1011
+ return _scale
1012
+
1013
+
1014
+ pipe = DataPipeline({
1015
+ "scaled_mwt": (
1016
+ "mwt",
1017
+ {"name": "scale", "kwargs": {"factor": 0.001}},
1018
+ ),
1019
+ })
1020
+ ```
1021
+
1022
+ Custom transforms must be registered in the Python process before loading pipelines that reference them.
1023
+
1024
+ ---
1025
+
1026
+ ## Model integration
1027
+
1028
+ Aspect separates stored feature representations from model-specific runtime inputs.
1029
+
1030
+ The output dataset may contain numeric arrays, chemical fingerprints, taxonomic encodings, or other Arrow-compatible values.
1031
+
1032
+ For simple numerical models, extract the dataset:
1033
+
1034
+ ```python
1035
+ features = pipe(data).data
1036
+ ```
1037
+
1038
+ For PyTorch models, use the built-in DataLoader integration:
1039
+
1040
+ ```python
1041
+ loader = pipe.dataloader(
1042
+ batch_size=32,
1043
+ shuffle=True,
1044
+ )
1045
+
1046
+ for batch in loader:
1047
+ # Batched, collated features
1048
+ pass
1049
+ ```
1050
+
1051
+ This requires the `torch` extra.
1052
+
1053
+ Transforms requiring specialised runtime representations can provide collators. These are applied when constructing model batches, allowing features such as molecular graphs to be stored independently from the framework-specific objects consumed by a model.
1054
+
1055
+ Custom collators can be provided through the `collators` argument:
1056
+
1057
+ ```python
1058
+ loader = pipe.dataloader(
1059
+ batch_size=32,
1060
+ collators={
1061
+ "custom_feature": custom_collator,
1062
+ },
1063
+ )
1064
+ ```
1065
+
1066
+ ### Mixed molecular and biological features
1067
+
1068
+ Aspect can combine multiple representations in one dataset:
1069
+
1070
+ ```python
1071
+ data = {
1072
+ "compound_id": ["cmpd-1", "cmpd-2", "cmpd-3"],
1073
+ "smiles": ["CCO", "CCN", "c1ccccc1"],
1074
+ "assay": ["solubility", "clearance", "microsome"],
1075
+ "species": [
1076
+ "Escherichia coli",
1077
+ "Mycobacterium tuberculosis",
1078
+ "Staphylococcus aureus",
1079
+ ],
1080
+ "mwt": [46.07, 45.08, 78.11],
1081
+ "label": [0.1, 0.4, 0.8],
1082
+ }
1083
+
1084
+ pipe = DataPipeline(
1085
+ {
1086
+ "morgan": ("smiles", "morgan-fingerprint"),
1087
+ "desc2d": ("smiles", "descriptors-2d"),
1088
+ "assay_hash": (
1089
+ "assay",
1090
+ {"name": "hash", "kwargs": {"ndim": 32}},
1091
+ ),
1092
+ "species_fp": (
1093
+ "species",
1094
+ {"name": "vectome-fingerprint", "kwargs": {"ndim": 64}},
1095
+ ),
1096
+ "log_mwt": ("mwt", "log"),
1097
+ "y": ("label", "identity"),
1098
+ },
1099
+ columns_to_keep=["compound_id"],
1100
+ )
1101
+
1102
+ features = pipe(
1103
+ data,
1104
+ drop_unused_columns=True,
1105
+ ).data
1106
+ ```
1107
+
1108
+ This requires the chemistry and taxonomy extras.
1109
+
1110
+ Downstream models can independently consume molecular fingerprints, descriptors, categorical features, and taxonomic encodings, or combine suitable dense features into a common representation.
1111
+
1112
+ ---
1113
+
1114
+ ## Development
1115
+
1116
+ Install the development dependencies:
1117
+
1118
+ ```bash
1119
+ pip install -e ".[dev]"
1120
+ ```
1121
+
1122
+ Run the test suite:
1123
+
1124
+ ```bash
1125
+ pytest
1126
+ ```
1127
+
1128
+ Run module doctests:
1129
+
1130
+ ```bash
1131
+ pytest aspect --doctest-modules
1132
+ ```
1133
+
1134
+ Run the CLI integration tests:
1135
+
1136
+ ```bash
1137
+ bash test/scripts/run-tests.sh
1138
+ ```
1139
+
1140
+ Aspect maintains separate GitHub Actions workflows for Python tests and CLI smoke tests.
1141
+
1142
+ ## Related packages
1143
+
1144
+ Aspect is part of a small ecosystem for reproducible molecular machine-learning workflows:
1145
+
1146
+ - [Providence](https://github.com/scbirlab/providence) — Dataset loading, source provenance, and checkpointing.
1147
+ - [Eluent](https://github.com/scbirlab/eluent) — Chemistry-aware grouping, splitting, and cross-validation.
1148
+ - [Schemist](https://github.com/scbirlab/schemist) — Molecular featurisation and cheminformatics.
1149
+ - [Vectome](https://github.com/scbirlab/vectome) — Taxonomic and biological representations.
1150
+
1151
+ The packages can be used independently or composed into reproducible workflows from source data to model-ready features and evaluation splits.
1152
+
1153
+ ---
1154
+
1155
+ ## Issues and documentation
1156
+
1157
+ Bug reports, feature requests, and contributions are welcome through the [GitHub issue tracker](https://github.com/scbirlab/aspect/issues).
1158
+
1159
+ Documentation: [aspect.readthedocs.org](https://aspect.readthedocs.org)
1160
+
1161
+ Source code: [github.com/scbirlab/aspect](https://github.com/scbirlab/aspect)
1162
+
1163
+ License: MIT.