fasttransform 0.0.2__tar.gz → 0.0.4__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.
@@ -0,0 +1,255 @@
1
+ Metadata-Version: 2.4
2
+ Name: fasttransform
3
+ Version: 0.0.4
4
+ Summary: Transform is the main building block of data pipelines in fastai. And elsewhere if you want.
5
+ Author-email: Jeremy Howard and Rens Dimmendaal and Alexis Gallagher <info@fast.ai>
6
+ License: Apache-2.0
7
+ Project-URL: Repository, https://github.com/AnswerDotAI/fasttransform
8
+ Project-URL: Documentation, https://AnswerDotAI.github.io/fasttransform
9
+ Keywords: nbdev,jupyter,notebook,python
10
+ Classifier: Natural Language :: English
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Requires-Python: >=3.9
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: fastcore>=2.2.21
19
+ Requires-Dist: plum-dispatch<2.10
20
+ Provides-Extra: dev
21
+ Requires-Dist: matplotlib; extra == "dev"
22
+ Requires-Dist: numpy; extra == "dev"
23
+ Requires-Dist: pandas; extra == "dev"
24
+ Dynamic: license-file
25
+
26
+ # Welcome to fasttransform
27
+
28
+
29
+ <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
30
+
31
+ `fasttransform` provides reusable data transformations and pipelines. It is the main building block of fastai’s data pipelines and can also be used independently. A [`Transform`](https://AnswerDotAI.github.io/fasttransform/transform.html#transform) combines a function with optional inverse, setup, and type-handling behaviour. A [`Pipeline`](https://AnswerDotAI.github.io/fasttransform/transform.html#pipeline) composes transforms.
32
+
33
+ ## Installation
34
+
35
+ Install latest from the GitHub [repository](https://github.com/AnswerDotAI/fasttransform):
36
+
37
+ ``` sh
38
+ $ pip install git+https://github.com/AnswerDotAI/fasttransform.git
39
+ ```
40
+
41
+ or from [pypi](https://pypi.org/project/fasttransform/):
42
+
43
+ ``` sh
44
+ $ pip install fasttransform
45
+ ```
46
+
47
+ ## Quick start
48
+
49
+ ### Transform
50
+
51
+ Create a [`Transform`](https://AnswerDotAI.github.io/fasttransform/transform.html#transform) by passing a function to its constructor or using it as a decorator. The function becomes the transform’s `encodes` method.
52
+
53
+ A transform supports:
54
+
55
+ - Reversibility: keep a function and its inverse in one object.
56
+ - Setup: configure a transform instance using the dataset.
57
+ - Type-based multiple dispatch: select a function based on argument types.
58
+ - Type conversion and preservation: control the result’s type, including subclasses.
59
+
60
+ To create a transform with a decorator:
61
+
62
+ ``` python
63
+ from fasttransform import Transform, Pipeline
64
+ ```
65
+
66
+ ``` python
67
+ @Transform
68
+ def add_one(x):
69
+ return x + 1
70
+
71
+ # Usage
72
+ add_one(2)
73
+ ```
74
+
75
+ 3
76
+
77
+ ### Reversibility
78
+
79
+ Pass a function and its inverse to make a transform reversible. Use this to normalize and de-normalize numerical values, or to encode categories as indices and decode them again:
80
+
81
+ ``` python
82
+ def enc(x): return x*2
83
+ def dec(x): return x//2
84
+
85
+ t = Transform(enc,dec)
86
+
87
+ t(2), t.decode(2), t.decode(t(2))
88
+ ```
89
+
90
+ (4, 1, 2)
91
+
92
+ ### Setup
93
+
94
+ A transform’s `setups` method can calculate properties from a dataset. This z-score normalization transform stores the mean and standard deviation. Its `encodes` and `decodes` methods use those values:
95
+
96
+ ``` python
97
+ import statistics
98
+
99
+ class NormalizeMean(Transform):
100
+ def setups(self, items):
101
+ self.mean = statistics.mean(items)
102
+ self.std = statistics.stdev(items)
103
+
104
+ def encodes(self, x):
105
+ return (x - self.mean) / self.std
106
+
107
+ def decodes(self, x):
108
+ return x * self.std + self.mean
109
+
110
+ normalize = NormalizeMean()
111
+ normalize.setup([1, 2, 3, 4, 5])
112
+ normalize.mean
113
+ ```
114
+
115
+ 3
116
+
117
+ ### Type-based multiple dispatch
118
+
119
+ Pass multiple functions with different parameter annotations to select behaviour by input type. This is useful for handling different image formats or numerical types in one transform.
120
+
121
+ This transform selects a function for an `int` or a `str`:
122
+
123
+ ``` python
124
+ def inc1(x:int): return x+1
125
+ def inc2(x:str): return x+"a"
126
+
127
+ t = Transform(enc=(inc1,inc2))
128
+
129
+ t(5), t('b')
130
+ ```
131
+
132
+ (6, 'ba')
133
+
134
+ When no type annotation matches an input, the transform returns that input unchanged.
135
+
136
+ ``` python
137
+ add_one(2.0)
138
+ ```
139
+
140
+ 3.0
141
+
142
+ ``` python
143
+ normalize(3.0)
144
+ ```
145
+
146
+ 0.0
147
+
148
+ ### Type conversion and preservation
149
+
150
+ [`Transform`](https://AnswerDotAI.github.io/fasttransform/transform.html#transform) uses the wrapped function’s return type to control conversion in `encodes` and `decodes`. The return type can be explicit or implicit. The rules are:
151
+
152
+ 1. The result has the function’s return type, with conversion when needed.
153
+ 2. When the input’s runtime type is a subtype of that return type, the result preserves the input’s type.
154
+ 3. A return annotation of `None` disables type conversion and preservation.
155
+
156
+ #### Return type
157
+
158
+ `FS` is a subclass of `float`. Normal Python multiplication of an `FS` and a `float` returns a `float`:
159
+
160
+ ``` python
161
+ class FS(float):
162
+ def __repr__(self): return f'FS({float(self)})'
163
+
164
+
165
+ f1 = float(1)
166
+ FS2 = FS(2)
167
+
168
+ val = f1 * FS2
169
+ type(val) # => float
170
+ ```
171
+
172
+ float
173
+
174
+ With [`Transform`](https://AnswerDotAI.github.io/fasttransform/transform.html#transform), an `FS` return annotation makes the multiplication return an `FS`:
175
+
176
+ ``` python
177
+ def double_FS(x)->FS: return FS(2)*x
178
+ t = Transform(double_FS)
179
+ val = t(1)
180
+ assert isinstance(val,FS)
181
+ val
182
+ ```
183
+
184
+ FS(2.0)
185
+
186
+ #### Type preservation
187
+
188
+ Without a return annotation, this multiplication transform preserves the input’s runtime type. Passing an `FS` returns an `FS`. The wrapped function alone would return a `float`:
189
+
190
+ ``` python
191
+ def double(x): return x*2.0 # no type annotation
192
+ t = Transform(double)
193
+ fs1 = FS(1)
194
+ val = t(fs1)
195
+ assert isinstance(val,FS)
196
+ val # => FS(2), an FS value of 2
197
+ ```
198
+
199
+ FS(2.0)
200
+
201
+ #### Disabling conversion
202
+
203
+ Use a return annotation of `None` to disable type conversion and preservation:
204
+
205
+ ``` python
206
+ def double_none(x) -> None: return x*2.0 # "None" returnt type means "no conversion"
207
+ t = Transform(double_none)
208
+ fs1 = FS(1)
209
+ val = t(fs1)
210
+ assert isinstance(val,float)
211
+ val # => 2.0, a float of 2, because of fallback to standard Python type logic
212
+ ```
213
+
214
+ 2.0
215
+
216
+ ### Pipelines
217
+
218
+ A [`Pipeline`](https://AnswerDotAI.github.io/fasttransform/transform.html#pipeline) applies transforms in sequence. This pipeline doubles a value and then normalizes it. `decode` reverses the transformations:
219
+
220
+ ``` python
221
+ def double(x): return x*2.0
222
+ def halve(x): return x/2.0
223
+ dt = Transform(double,halve)
224
+
225
+ class NormalizeMean(Transform):
226
+ def setups(self, items):
227
+ self.mean = statistics.mean(items)
228
+ self.std = statistics.stdev(items)
229
+
230
+ def encodes(self, x):
231
+ return (x - self.mean) / self.std
232
+
233
+ def decodes(self, x):
234
+ return x * self.std + self.mean
235
+
236
+ normalize = NormalizeMean()
237
+ normalize.setup([1, 2, 3, 4, 5])
238
+
239
+ p = Pipeline((dt, normalize))
240
+
241
+ v = p(5)
242
+ v
243
+ ```
244
+
245
+ 4.427188724235731
246
+
247
+ ``` python
248
+ p.decode(v)
249
+ ```
250
+
251
+ 5.0
252
+
253
+ ### Documentation
254
+
255
+ See the [documentation](https://answerdotai.github.io/fasttransform/) for the full API.
@@ -0,0 +1,230 @@
1
+ # Welcome to fasttransform
2
+
3
+
4
+ <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
5
+
6
+ `fasttransform` provides reusable data transformations and pipelines. It is the main building block of fastai’s data pipelines and can also be used independently. A [`Transform`](https://AnswerDotAI.github.io/fasttransform/transform.html#transform) combines a function with optional inverse, setup, and type-handling behaviour. A [`Pipeline`](https://AnswerDotAI.github.io/fasttransform/transform.html#pipeline) composes transforms.
7
+
8
+ ## Installation
9
+
10
+ Install latest from the GitHub [repository](https://github.com/AnswerDotAI/fasttransform):
11
+
12
+ ``` sh
13
+ $ pip install git+https://github.com/AnswerDotAI/fasttransform.git
14
+ ```
15
+
16
+ or from [pypi](https://pypi.org/project/fasttransform/):
17
+
18
+ ``` sh
19
+ $ pip install fasttransform
20
+ ```
21
+
22
+ ## Quick start
23
+
24
+ ### Transform
25
+
26
+ Create a [`Transform`](https://AnswerDotAI.github.io/fasttransform/transform.html#transform) by passing a function to its constructor or using it as a decorator. The function becomes the transform’s `encodes` method.
27
+
28
+ A transform supports:
29
+
30
+ - Reversibility: keep a function and its inverse in one object.
31
+ - Setup: configure a transform instance using the dataset.
32
+ - Type-based multiple dispatch: select a function based on argument types.
33
+ - Type conversion and preservation: control the result’s type, including subclasses.
34
+
35
+ To create a transform with a decorator:
36
+
37
+ ``` python
38
+ from fasttransform import Transform, Pipeline
39
+ ```
40
+
41
+ ``` python
42
+ @Transform
43
+ def add_one(x):
44
+ return x + 1
45
+
46
+ # Usage
47
+ add_one(2)
48
+ ```
49
+
50
+ 3
51
+
52
+ ### Reversibility
53
+
54
+ Pass a function and its inverse to make a transform reversible. Use this to normalize and de-normalize numerical values, or to encode categories as indices and decode them again:
55
+
56
+ ``` python
57
+ def enc(x): return x*2
58
+ def dec(x): return x//2
59
+
60
+ t = Transform(enc,dec)
61
+
62
+ t(2), t.decode(2), t.decode(t(2))
63
+ ```
64
+
65
+ (4, 1, 2)
66
+
67
+ ### Setup
68
+
69
+ A transform’s `setups` method can calculate properties from a dataset. This z-score normalization transform stores the mean and standard deviation. Its `encodes` and `decodes` methods use those values:
70
+
71
+ ``` python
72
+ import statistics
73
+
74
+ class NormalizeMean(Transform):
75
+ def setups(self, items):
76
+ self.mean = statistics.mean(items)
77
+ self.std = statistics.stdev(items)
78
+
79
+ def encodes(self, x):
80
+ return (x - self.mean) / self.std
81
+
82
+ def decodes(self, x):
83
+ return x * self.std + self.mean
84
+
85
+ normalize = NormalizeMean()
86
+ normalize.setup([1, 2, 3, 4, 5])
87
+ normalize.mean
88
+ ```
89
+
90
+ 3
91
+
92
+ ### Type-based multiple dispatch
93
+
94
+ Pass multiple functions with different parameter annotations to select behaviour by input type. This is useful for handling different image formats or numerical types in one transform.
95
+
96
+ This transform selects a function for an `int` or a `str`:
97
+
98
+ ``` python
99
+ def inc1(x:int): return x+1
100
+ def inc2(x:str): return x+"a"
101
+
102
+ t = Transform(enc=(inc1,inc2))
103
+
104
+ t(5), t('b')
105
+ ```
106
+
107
+ (6, 'ba')
108
+
109
+ When no type annotation matches an input, the transform returns that input unchanged.
110
+
111
+ ``` python
112
+ add_one(2.0)
113
+ ```
114
+
115
+ 3.0
116
+
117
+ ``` python
118
+ normalize(3.0)
119
+ ```
120
+
121
+ 0.0
122
+
123
+ ### Type conversion and preservation
124
+
125
+ [`Transform`](https://AnswerDotAI.github.io/fasttransform/transform.html#transform) uses the wrapped function’s return type to control conversion in `encodes` and `decodes`. The return type can be explicit or implicit. The rules are:
126
+
127
+ 1. The result has the function’s return type, with conversion when needed.
128
+ 2. When the input’s runtime type is a subtype of that return type, the result preserves the input’s type.
129
+ 3. A return annotation of `None` disables type conversion and preservation.
130
+
131
+ #### Return type
132
+
133
+ `FS` is a subclass of `float`. Normal Python multiplication of an `FS` and a `float` returns a `float`:
134
+
135
+ ``` python
136
+ class FS(float):
137
+ def __repr__(self): return f'FS({float(self)})'
138
+
139
+
140
+ f1 = float(1)
141
+ FS2 = FS(2)
142
+
143
+ val = f1 * FS2
144
+ type(val) # => float
145
+ ```
146
+
147
+ float
148
+
149
+ With [`Transform`](https://AnswerDotAI.github.io/fasttransform/transform.html#transform), an `FS` return annotation makes the multiplication return an `FS`:
150
+
151
+ ``` python
152
+ def double_FS(x)->FS: return FS(2)*x
153
+ t = Transform(double_FS)
154
+ val = t(1)
155
+ assert isinstance(val,FS)
156
+ val
157
+ ```
158
+
159
+ FS(2.0)
160
+
161
+ #### Type preservation
162
+
163
+ Without a return annotation, this multiplication transform preserves the input’s runtime type. Passing an `FS` returns an `FS`. The wrapped function alone would return a `float`:
164
+
165
+ ``` python
166
+ def double(x): return x*2.0 # no type annotation
167
+ t = Transform(double)
168
+ fs1 = FS(1)
169
+ val = t(fs1)
170
+ assert isinstance(val,FS)
171
+ val # => FS(2), an FS value of 2
172
+ ```
173
+
174
+ FS(2.0)
175
+
176
+ #### Disabling conversion
177
+
178
+ Use a return annotation of `None` to disable type conversion and preservation:
179
+
180
+ ``` python
181
+ def double_none(x) -> None: return x*2.0 # "None" returnt type means "no conversion"
182
+ t = Transform(double_none)
183
+ fs1 = FS(1)
184
+ val = t(fs1)
185
+ assert isinstance(val,float)
186
+ val # => 2.0, a float of 2, because of fallback to standard Python type logic
187
+ ```
188
+
189
+ 2.0
190
+
191
+ ### Pipelines
192
+
193
+ A [`Pipeline`](https://AnswerDotAI.github.io/fasttransform/transform.html#pipeline) applies transforms in sequence. This pipeline doubles a value and then normalizes it. `decode` reverses the transformations:
194
+
195
+ ``` python
196
+ def double(x): return x*2.0
197
+ def halve(x): return x/2.0
198
+ dt = Transform(double,halve)
199
+
200
+ class NormalizeMean(Transform):
201
+ def setups(self, items):
202
+ self.mean = statistics.mean(items)
203
+ self.std = statistics.stdev(items)
204
+
205
+ def encodes(self, x):
206
+ return (x - self.mean) / self.std
207
+
208
+ def decodes(self, x):
209
+ return x * self.std + self.mean
210
+
211
+ normalize = NormalizeMean()
212
+ normalize.setup([1, 2, 3, 4, 5])
213
+
214
+ p = Pipeline((dt, normalize))
215
+
216
+ v = p(5)
217
+ v
218
+ ```
219
+
220
+ 4.427188724235731
221
+
222
+ ``` python
223
+ p.decode(v)
224
+ ```
225
+
226
+ 5.0
227
+
228
+ ### Documentation
229
+
230
+ See the [documentation](https://answerdotai.github.io/fasttransform/) for the full API.
@@ -1,4 +1,4 @@
1
- __version__ = "0.0.2"
1
+ __version__ = "0.0.4"
2
2
 
3
3
  from .cast import *
4
4
  from .transform import *
@@ -1,11 +1,13 @@
1
- """Type casting utility functions"""
1
+ """Type casting utility functions
2
+
3
+ Docs: https://AnswerDotAI.github.io/fasttransform/cast.html.md"""
2
4
 
3
5
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_cast.ipynb.
4
6
 
5
- # %% auto 0
7
+ # %% auto #0
6
8
  __all__ = ['retain_meta', 'default_set_meta', 'cast', 'retain_type', 'retain_types', 'explode_types']
7
9
 
8
- # %% ../nbs/00_cast.ipynb 1
10
+ # %% ../nbs/00_cast.ipynb #4af968d5
9
11
  from typing import Any
10
12
 
11
13
  from plum import dispatch, Function
@@ -15,14 +17,14 @@ from fastcore.imports import *
15
17
  from fastcore.foundation import *
16
18
  from fastcore.utils import *
17
19
 
18
- # %% ../nbs/00_cast.ipynb 6
20
+ # %% ../nbs/00_cast.ipynb #8fc704ac
19
21
  def retain_meta(x, res, as_copy=False):
20
22
  "Call `res.set_meta(x)`, if it exists"
21
23
  if hasattr(res,'set_meta'): res.set_meta(x, as_copy=as_copy)
22
24
  return res
23
25
 
24
26
 
25
- # %% ../nbs/00_cast.ipynb 7
27
+ # %% ../nbs/00_cast.ipynb #5a973173
26
28
  def default_set_meta(self, x, as_copy=False):
27
29
  "Copy over `_meta` from `x` to `res`, if it's missing"
28
30
  if hasattr(x, '_meta') and not hasattr(self, '_meta'):
@@ -32,7 +34,7 @@ def default_set_meta(self, x, as_copy=False):
32
34
  return self
33
35
 
34
36
 
35
- # %% ../nbs/00_cast.ipynb 8
37
+ # %% ../nbs/00_cast.ipynb #05108cf6
36
38
  def cast(x, typ):
37
39
  "cast `x` to type `typ` (may also change `x` inplace)"
38
40
  res = typ._before_cast(x) if hasattr(typ, '_before_cast') else x
@@ -43,7 +45,7 @@ def cast(x, typ):
43
45
  except: res = typ(res)
44
46
  return retain_meta(x, res)
45
47
 
46
- # %% ../nbs/00_cast.ipynb 15
48
+ # %% ../nbs/00_cast.ipynb #1364fbd1
47
49
  def retain_type(new, old, ret_type=Any,as_copy=False):
48
50
  "Cast `new` to `ret_type` if given, or `old`'s type if `new` is a superclass of `old`. No conversion is done if `ret_type=None`"
49
51
  if new is None: return new
@@ -54,7 +56,7 @@ def retain_type(new, old, ret_type=Any,as_copy=False):
54
56
  if ret_type is NoneType or isinstance(new,ret_type): return new
55
57
  return retain_meta(old, cast(new, ret_type), as_copy=as_copy)
56
58
 
57
- # %% ../nbs/00_cast.ipynb 40
59
+ # %% ../nbs/00_cast.ipynb #f3cd995c
58
60
  def retain_types(new, old=None, typs=None):
59
61
  "Cast each item of `new` to type of matching item in `old` if it's a superclass"
60
62
  if not is_listy(new):
@@ -69,7 +71,7 @@ def retain_types(new, old=None, typs=None):
69
71
  return t(L(new, old, typs).map_zip(retain_types, cycled=True))
70
72
 
71
73
 
72
- # %% ../nbs/00_cast.ipynb 42
74
+ # %% ../nbs/00_cast.ipynb #c6f1ec26
73
75
  def explode_types(o):
74
76
  "Return the type of `o`, potentially in nested dictionaries for thing that are listy"
75
77
  if not is_listy(o): return type(o)