tools 1.0.2__tar.gz → 1.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.
Files changed (44) hide show
  1. {tools-1.0.2 → tools-1.0.4}/PKG-INFO +6 -8
  2. {tools-1.0.2 → tools-1.0.4}/README.md +5 -7
  3. {tools-1.0.2 → tools-1.0.4}/tools/__init__.py +1 -1
  4. tools-1.0.4/tools/dict_operations.py +139 -0
  5. tools-1.0.4/tools/plot/__init__.py +26 -0
  6. tools-1.0.4/tools/sklearn/metrics.py +189 -0
  7. {tools-1.0.2 → tools-1.0.4}/tools/tools.py +35 -1
  8. {tools-1.0.2 → tools-1.0.4}/tools.egg-info/PKG-INFO +6 -8
  9. {tools-1.0.2 → tools-1.0.4}/tools.egg-info/SOURCES.txt +1 -0
  10. tools-1.0.2/tools/plot/__init__.py +0 -5
  11. tools-1.0.2/tools/sklearn/metrics.py +0 -112
  12. {tools-1.0.2 → tools-1.0.4}/LICENSE.txt +0 -0
  13. {tools-1.0.2 → tools-1.0.4}/setup.cfg +0 -0
  14. {tools-1.0.2 → tools-1.0.4}/setup.py +0 -0
  15. {tools-1.0.2 → tools-1.0.4}/tools/array.py +0 -0
  16. {tools-1.0.2 → tools-1.0.4}/tools/data.py +0 -0
  17. {tools-1.0.2 → tools-1.0.4}/tools/exp.py +0 -0
  18. {tools-1.0.2 → tools-1.0.4}/tools/hydra/__init__.py +0 -0
  19. {tools-1.0.2 → tools-1.0.4}/tools/modules.py +0 -0
  20. {tools-1.0.2 → tools-1.0.4}/tools/numpy/__init__.py +0 -0
  21. {tools-1.0.2 → tools-1.0.4}/tools/numpy/_f.py +0 -0
  22. {tools-1.0.2 → tools-1.0.4}/tools/numpy/_utils.py +0 -0
  23. {tools-1.0.2 → tools-1.0.4}/tools/os.py +0 -0
  24. {tools-1.0.2 → tools-1.0.4}/tools/pandas/__init__.py +0 -0
  25. {tools-1.0.2 → tools-1.0.4}/tools/plot/sklearn.py +0 -0
  26. {tools-1.0.2 → tools-1.0.4}/tools/plot/utils.py +0 -0
  27. {tools-1.0.2 → tools-1.0.4}/tools/random.py +0 -0
  28. {tools-1.0.2 → tools-1.0.4}/tools/sklearn/__init__.py +0 -0
  29. {tools-1.0.2 → tools-1.0.4}/tools/sklearn/model_selection.py +0 -0
  30. {tools-1.0.2 → tools-1.0.4}/tools/sklearn/preprocessing.py +0 -0
  31. {tools-1.0.2 → tools-1.0.4}/tools/stats/__init__.py +0 -0
  32. {tools-1.0.2 → tools-1.0.4}/tools/torch/__init__.py +0 -0
  33. {tools-1.0.2 → tools-1.0.4}/tools/torch/_pandas.py +0 -0
  34. {tools-1.0.2 → tools-1.0.4}/tools/torch/data.py +0 -0
  35. {tools-1.0.2 → tools-1.0.4}/tools/torch/estimator.py +0 -0
  36. {tools-1.0.2 → tools-1.0.4}/tools/torch/federated_learning.py +0 -0
  37. {tools-1.0.2 → tools-1.0.4}/tools/torch/layers.py +0 -0
  38. {tools-1.0.2 → tools-1.0.4}/tools/torch/model.py +0 -0
  39. {tools-1.0.2 → tools-1.0.4}/tools/torch/optim/__init__.py +0 -0
  40. {tools-1.0.2 → tools-1.0.4}/tools/torch/optim/lr_scheduler.py +0 -0
  41. {tools-1.0.2 → tools-1.0.4}/tools/torch/plot.py +0 -0
  42. {tools-1.0.2 → tools-1.0.4}/tools/torch/utils.py +0 -0
  43. {tools-1.0.2 → tools-1.0.4}/tools.egg-info/dependency_links.txt +0 -0
  44. {tools-1.0.2 → tools-1.0.4}/tools.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tools
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: python syntax tool
5
5
  Home-page: https://github.com/jsyoo61/tools
6
6
  Author: JaeSung Yoo
@@ -12,7 +12,7 @@ Requires-Python: >=3.6
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.txt
14
14
 
15
- # tools-jsyoo61
15
+ # tools
16
16
 
17
17
  (`tools` package was replaced on 2025.04.28. If you're looking for web scraping tools, visit http://pypi.python.org/pypi/weblib)
18
18
 
@@ -28,12 +28,10 @@ jsyoo61@unc.edu
28
28
  Most useful functions are in `tools.tools` which is loaded to the main module by default. \
29
29
  API dependent tools are in their corresponding folders: `tools.API_name` (i.e. `tools.torch.optim`)
30
30
 
31
- Planning to document using chatGPT,
32
- Not documented yet, so you'll have to look at documents written inside the codes. (Most codes contain explanation)
31
+ Undocumented, so you'll have to look at documents written inside the codes or with help(). (Most codes contain explanation)
32
+ Planning to document with chatGPT.
33
33
 
34
34
  I'm happy to discuss questions or suggestions, please contact me via email. :)
35
35
 
36
- 1.0.1. (2025.5.1.)
37
-
38
- - `tools.sklearn.metrics.r2_score()` `multioutput` argument fixed
39
- - `tools.sklearn.metrics` axis=None returns a single np.float object
36
+ 1.0.4. (2025.8.14.)
37
+ - `tools.sklearn.metrics` stable, has proper arguments `axis_ref`, `axis_bias`
@@ -1,4 +1,4 @@
1
- # tools-jsyoo61
1
+ # tools
2
2
 
3
3
  (`tools` package was replaced on 2025.04.28. If you're looking for web scraping tools, visit http://pypi.python.org/pypi/weblib)
4
4
 
@@ -14,12 +14,10 @@ jsyoo61@unc.edu
14
14
  Most useful functions are in `tools.tools` which is loaded to the main module by default. \
15
15
  API dependent tools are in their corresponding folders: `tools.API_name` (i.e. `tools.torch.optim`)
16
16
 
17
- Planning to document using chatGPT,
18
- Not documented yet, so you'll have to look at documents written inside the codes. (Most codes contain explanation)
17
+ Undocumented, so you'll have to look at documents written inside the codes or with help(). (Most codes contain explanation)
18
+ Planning to document with chatGPT.
19
19
 
20
20
  I'm happy to discuss questions or suggestions, please contact me via email. :)
21
21
 
22
- 1.0.1. (2025.5.1.)
23
-
24
- - `tools.sklearn.metrics.r2_score()` `multioutput` argument fixed
25
- - `tools.sklearn.metrics` axis=None returns a single np.float object
22
+ 1.0.4. (2025.8.14.)
23
+ - `tools.sklearn.metrics` stable, has proper arguments `axis_ref`, `axis_bias`
@@ -1,5 +1,5 @@
1
1
 
2
- __version__ = "1.0.2"
2
+ __version__ = "1.0.4"
3
3
  from .tools import *
4
4
  from . import os
5
5
 
@@ -0,0 +1,139 @@
1
+ import numpy as np
2
+ import utils as U
3
+
4
+ # %%
5
+ def add_batch_dim(data):
6
+ """
7
+ adds batch dimension (axis=0)
8
+
9
+ Parameters
10
+ ----------
11
+ data : numpy.ndarray or dict of arrays
12
+
13
+ Returns
14
+ -------
15
+ data : numpy.ndarray or dict of arrays with axis=0 dimension added
16
+ """
17
+ if isinstance(data, dict):
18
+ data = {k: v[None,...] for k, v in data.items()}
19
+ else:
20
+ data = data[None,...]
21
+ return data
22
+
23
+ def remove_batch_dim(data):
24
+ if isinstance(data, dict):
25
+ data = {k: v.squeeze(0) for k, v in data.items()}
26
+ else:
27
+ data = data.squeeze(0)
28
+ return data
29
+
30
+ def __eq__(data1, data2):
31
+ if isinstance(data1, dict) and isinstance(data2, dict):
32
+ k1, k2 = sorted(list(data1.keys())), sorted(list(data2.keys()))
33
+ if k1!=k2:
34
+ return False
35
+ else:
36
+ equal_values = [all(data1[k]==data2[k]) for k in k1]
37
+ return all(equal_values)
38
+ else:
39
+ return data1==data2
40
+
41
+ def __getitem__(data, idx):
42
+ if isinstance(data, dict):
43
+ return {k: v[idx] for k, v in data.items()}
44
+ else:
45
+ return data[idx]
46
+
47
+ def __iter__(data):
48
+ if isinstance(data, dict):
49
+ iterators = {k: iter(v) for k, v in data.items()}
50
+ while True:
51
+ try:
52
+ yield {k: next(v) for k, v in iterators.items()}
53
+ except StopIteration:
54
+ break
55
+ else:
56
+ return iter(data)
57
+
58
+ def __len__(data):
59
+ if isinstance(data, dict):
60
+ l_len = [len(v) for v in data.values()]
61
+ assert U.equal(l_len)
62
+ return l_len[0]
63
+
64
+ else:
65
+ return len(data)
66
+
67
+ def array(data, dtype=None):
68
+ '''
69
+ data: iterable or iterable of dicts
70
+ '''
71
+ if isinstance(data, dict):
72
+ return {k: np.array(v, dtype=dtype) for k, v in data.items()}
73
+ else:
74
+ np.array(data, dtype=dtype)
75
+
76
+ def astype(data, dtype):
77
+ if isinstance(data, dict):
78
+ return {k: v.astype(dtype) for k, v in data.items()}
79
+ else:
80
+ data.astype(dtype)
81
+
82
+ def broadcast_to(data, shape):
83
+ if isinstance(data, dict):
84
+ return {k: np.broadcast_to(v, shape=shape) for k, v in data.items()}
85
+ else:
86
+ return np.broadcast_to(data, shape=shape)
87
+
88
+ def shape(data):
89
+ if isinstance(data, dict):
90
+ l_shape = [v.shape for v in data.values()]
91
+ assert U.equal(l_shape), "shape within dict are not equal."
92
+ return l_shape[0]
93
+ else:
94
+ return data.shape
95
+
96
+ def stack(data, axis):
97
+ if isinstance(data, dict):
98
+ return {k: np.stack(v, axis=axis) for k, v in data.items()}
99
+ else:
100
+ return np.stack(data, axis=axis)
101
+
102
+ def nwise(data, n):
103
+ """
104
+ Returns n-elements from the data sequentially.
105
+
106
+ Returns
107
+ -------
108
+ generator object
109
+
110
+ See Also
111
+ --------
112
+ itertools.pairwise : Same as nwise but with n=2
113
+
114
+ Examples
115
+ --------
116
+ >>> list(nwise(np.arange(5), n=3))
117
+ [array([0, 1, 2]), array([1, 2, 3]), array([2, 3, 4])]
118
+ """
119
+ if isinstance(data, dict):
120
+ l_shape = [v.shape for v in data.values()]
121
+ assert U.equal(l_shape), "shape within dict are not equal."
122
+ data_shape = l_shape[0]
123
+ for i in range(data_shape[0]-n+1):
124
+ yield {k: v[i:i+n] for k, v in data.items()}
125
+ else:
126
+ for i in range(len(data)-n+1):
127
+ yield data[i:i+n]
128
+
129
+ def concatenate(data, axis):
130
+ if isinstance(data, dict):
131
+ return {k: np.concatenate(v, axis=axis) for k, v in data.items()}
132
+ else:
133
+ return np.concatenate(data, axis=axis)
134
+
135
+ def to(data, **kwargs):
136
+ if isinstance(data, dict):
137
+ return {k: v.to(**kwargs) for k, v in data.items()}
138
+ else:
139
+ return data.to(**kwargs)
@@ -0,0 +1,26 @@
1
+ from .sklearn import *
2
+ from .utils import *
3
+
4
+ if __name__ == '__main__':
5
+ pass
6
+
7
+ def add_colorbar(ax):
8
+ """
9
+ Add a colorbar to the given axes.
10
+
11
+ Parameters
12
+ ----------
13
+ ax : matplotlib.axes.Axes
14
+
15
+ Returns
16
+ -------
17
+ C : ndarray of shape (n_classes, n_classes)
18
+ Explanation variable
19
+ """
20
+ from matplotlib import cm
21
+ from mpl_toolkits.axes_grid1 import make_axes_locatable
22
+
23
+ divider = make_axes_locatable(ax)
24
+ cax = divider.append_axes("right", size="5%", pad=0.05)
25
+ cbar = ax.figure.colorbar(cm.ScalarMappable(norm=ax.images[0].norm, cmap=ax.images[0].cmap), cax=cax)
26
+ return cbar
@@ -0,0 +1,189 @@
1
+ from collections.abc import Iterable
2
+ import warnings
3
+
4
+ import numpy as np
5
+ from sklearn.metrics import r2_score as r2_score_sklearn
6
+
7
+ def squared_error(y_true, y_pred, axis=None):
8
+ """
9
+ MSE averaging across specified axis.
10
+ if axis=(), returns entry-by-entry squared error.
11
+
12
+ Parameters
13
+ ----------
14
+ y_true : np.ndarray
15
+ y_pred : np.ndarray
16
+
17
+ axis : int or iterable of int, default=None
18
+ Axis to collapse.
19
+
20
+ Returns
21
+ -------
22
+ score : numpy.ndarray of shape with collapsed axis
23
+ """
24
+ if axis is None:
25
+ axis = tuple(range(y_true.ndim)) # Collapse all dimensions
26
+ score = (y_true-y_pred)**2
27
+ score = np.mean(score, axis=axis)
28
+ return score
29
+
30
+ def absolute_error(y_true, y_pred, axis=None):
31
+ """
32
+ MAE averaging across specified axis.
33
+ if axis=(), returns entry-by-entry absolute error.
34
+
35
+ Parameters
36
+ ----------
37
+ y_true : np.ndarray
38
+ y_pred : np.ndarray
39
+
40
+ axis : int or iterable of int, default=None
41
+ Axis to collapse.
42
+
43
+ Returns
44
+ -------
45
+ score : numpy.ndarray of shape with collapsed axis
46
+ """
47
+ if axis is None:
48
+ axis = tuple(range(y_true.ndim)) # Collapse all dimensions
49
+ score = np.abs(y_true-y_pred)
50
+ score = np.mean(score, axis=axis)
51
+ return score
52
+
53
+ def r2_score(y_true, y_pred, axis=None, axis_ref=None, axis_bias=None, multioutput='raw_values', force_finite=True):
54
+ """
55
+ R^2 score for multidimensional predictions.
56
+ collapses all axes except the specified axis.
57
+
58
+ Computes 1 - RSS / TSS, where RSS is the residual sum of squares and TSS is the total sum of squares.
59
+
60
+ Parameters
61
+ ----------
62
+ y_true : np.ndarray
63
+ y_pred : np.ndarray
64
+ axis: int or iterable of int, default=None
65
+ Axis to collapse.
66
+ If None, collapses all axes.
67
+
68
+ multioutput : Reference to `sklearn.metrics.r2_score`
69
+ https://scikit-learn.org/stable/modules/generated/sklearn.metrics.r2_score.html
70
+
71
+ Note:
72
+ - default is 'raw_values', which is different from sklearn.
73
+ - when multioutput is uniform_average or variance_weighted, return value is a single float even if axis is specified.
74
+ The axis specifies the feature dimensions to average over.
75
+
76
+ Returns
77
+ -------
78
+ z : np.ndarray
79
+ if axis is specified, returns an array of shape (y_true.shape[axis],)
80
+ """
81
+
82
+ # Residual Sum of Squares (RSS) and Total Sum of Squares (TSS)
83
+ RS = (y_true - y_pred)**2 # Residual Square (RS)
84
+ RSS = np.sum(RS, axis=axis, keepdims=True)
85
+
86
+ if axis_ref is None:
87
+ axis_ref = axis
88
+ if axis_bias is None:
89
+ axis_bias = axis_ref
90
+
91
+ axis_ref_set = {axis_ref} if not isinstance(axis_ref, Iterable) else set(axis_ref)
92
+ axis_set = {axis} if not isinstance(axis, Iterable) else set(axis)
93
+ axis_bias_set = {axis_bias} if axis_bias is not None and not isinstance(axis_bias, Iterable) else set(axis_bias) if axis_bias is not None else set()
94
+
95
+ assert axis_bias_set.issubset(axis_ref_set), f'axis_bias ({axis_bias}) must be a subset of axis_ref ({axis_ref}) because axis_ measure variability' # If axis_bias is not a subset of axis_ref, expand axis_ref to include axis_bias
96
+
97
+ # Dimensions of TSS must be smaller than RSS, so mean/sum over axis_ref and axis
98
+ axis_sum = axis
99
+ axis_mean = tuple(axis_ref_set - axis_set) # Average over axis_ref - axis
100
+
101
+ if not axis_set.issubset(axis_ref_set): # If axis is not a subset of axis_ref, expand axis_ref to include axis
102
+ warnings.warn(f"axis {axis} is not a subset of axis_ref {axis_ref}, TSS sums over axis {axis_sum} and averages over remaining axis_ref {axis_mean}")
103
+
104
+ # axis_bias used to compute the mean of y_true
105
+ y_mean = np.mean(y_true, axis=axis_bias, keepdims=True)
106
+ TS = (y_true - y_mean)**2 # Total Square (TS)
107
+
108
+ # axis_ref used to aggregate additional dimensions (average) additional to axis
109
+ TSS = np.mean(TS, axis=axis_mean, keepdims=True)
110
+ TSS = np.sum(TSS, axis=axis_sum, keepdims=True)
111
+
112
+ score = 1 - RSS / TSS
113
+ score = np.squeeze(score, axis=axis) # Collapse the axis_ref dimension
114
+
115
+ if force_finite:
116
+ score[np.isnan(score)] = 1
117
+ score[np.isinf(score)] = 0 # -Inf means no fit, so set to 0
118
+
119
+ if axis is None:
120
+ score = score.item()
121
+
122
+ return score
123
+
124
+ # def r2_score(y_true, y_pred, axis=None, multioutput='raw_values'):
125
+ # """
126
+ # R^2 score for multidimensional predictions.
127
+ # collapses all axes except the specified axis.
128
+
129
+ # Parameters
130
+ # ----------
131
+ # y_true : np.ndarray
132
+ # y_pred : np.ndarray
133
+ # axis: int or iterable of int, default=None
134
+ # Axis to collapse.
135
+ # If None, collapses all axes.
136
+
137
+ # multioutput : Reference to `sklearn.metrics.r2_score`
138
+ # https://scikit-learn.org/stable/modules/generated/sklearn.metrics.r2_score.html
139
+
140
+ # Note:
141
+ # - default is 'raw_values', which is different from sklearn.
142
+ # - when multioutput is uniform_average or variance_weighted, return value is a single float even if axis is specified.
143
+ # The axis specifies the feature dimensions to average over.
144
+
145
+ # Returns
146
+ # -------
147
+ # z : np.ndarray
148
+ # if axis is specified, returns an array of shape (y_true.shape[axis],)
149
+ # """
150
+ # assert y_true.shape == y_pred.shape, f"y_true and y_pred must have the same shape, received: {y_true.shape} and {y_pred.shape}"
151
+ # if axis is None:
152
+ # axis = list(range(y_true.ndim)) # Collapse all dimensions
153
+ # axis_was_none = True
154
+ # elif not isinstance(axis, Iterable):
155
+ # axis = [axis]
156
+ # axis_was_none = False
157
+ # else:
158
+ # axis = list(axis)
159
+ # axis_was_none = False
160
+
161
+ # if len(axis) > y_true.ndim:
162
+ # raise ValueError("Axis is greater than the number of dimensions of y_true and y_pred")
163
+
164
+ # dim_collapse = axis
165
+ # dim_final = list(set(range(y_true.ndim)).difference(axis))
166
+ # shape_final = np.array(y_true.shape)[dim_final] if len(dim_final)!=0 else (1,)
167
+
168
+ # y_true = np.transpose(y_true, (*dim_collapse, *dim_final)).reshape(-1, np.prod(shape_final)) # Move axis to the end, and flatten the rest
169
+ # y_pred = np.transpose(y_pred, (*dim_collapse, *dim_final)).reshape(-1, np.prod(shape_final))
170
+
171
+ # # score = r2_score_sklearn(y_true, y_pred, multioutput=multioutput)
172
+ # score = r2_score_sklearn(y_true, y_pred, multioutput='raw_values')
173
+
174
+ # if type(score) == float and np.isnan(score).item():
175
+ # warnings.warn("R2 score is a single NaN, shape matching with NaN")
176
+ # score = np.full(shape_final, np.nan)
177
+ # return score
178
+
179
+ # if multioutput == 'raw_values':
180
+ # score = score.reshape(*shape_final) if not axis_was_none else score[0]
181
+ # return score
182
+ # elif multioutput == 'uniform_average':
183
+ # return score.mean()
184
+ # elif multioutput == 'variance_weighted':
185
+ # return np.average(score, weights=np.var(y_true, axis=0))
186
+ # else:
187
+ # raise ValueError("multioutput must be one of ['raw_values', 'uniform_average', 'variance_weighted']")
188
+
189
+ # %%
@@ -162,6 +162,21 @@ def unnest_dict(d, format='.'):
162
162
  un_d[k] = v
163
163
  return un_d
164
164
 
165
+ def nest_dict(d, format='.'):
166
+ '''
167
+ Convert a 1st order dictionary with format-separated-keys into a nested dictionary.
168
+ '''
169
+ n_d = {}
170
+ for k, v in d.items():
171
+ keys = k.split(format)
172
+ d_ = n_d # Start from root
173
+ for key in keys[:-1]: # Traverse to the last key
174
+ if key not in d_: # If key does not exist, create a new dict
175
+ d_[key] = {}
176
+ d_ = d_[key] # Move to the next dict
177
+ d_[keys[-1]] = v # Set the value to the last key
178
+ return n_d
179
+
165
180
  def nestdict_to_list(d, key=None):
166
181
  '''
167
182
  open 2nd order nested dict to list of dicts.
@@ -187,7 +202,26 @@ def update_ld(ld, d):
187
202
 
188
203
  return ld
189
204
 
190
- def update_keys(d, d_key, copy=True): # inplace? copy?
205
+ def update_keys(d, d_key, copy=False): # inplace? copy?
206
+ """
207
+ Update keys of a dictionary.
208
+
209
+ Parameters
210
+ ----------
211
+ d : dict
212
+ Dictionary to update.
213
+ d_key : dict
214
+ Dictionary of old and new keys.
215
+ The keys of d_key are the old keys, and the values are the new keys.
216
+ copy : bool, default=False
217
+ If True, a copy of the dictionary is made before updating the keys.
218
+
219
+ Returns
220
+ -------
221
+ d : dict
222
+ Updated dictionary with new keys.
223
+ If copy is True, a new dictionary is returned.
224
+ """
191
225
  if copy:
192
226
  d = dcopy(d)
193
227
  for k_old, k_new in d_key.items():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tools
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: python syntax tool
5
5
  Home-page: https://github.com/jsyoo61/tools
6
6
  Author: JaeSung Yoo
@@ -12,7 +12,7 @@ Requires-Python: >=3.6
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.txt
14
14
 
15
- # tools-jsyoo61
15
+ # tools
16
16
 
17
17
  (`tools` package was replaced on 2025.04.28. If you're looking for web scraping tools, visit http://pypi.python.org/pypi/weblib)
18
18
 
@@ -28,12 +28,10 @@ jsyoo61@unc.edu
28
28
  Most useful functions are in `tools.tools` which is loaded to the main module by default. \
29
29
  API dependent tools are in their corresponding folders: `tools.API_name` (i.e. `tools.torch.optim`)
30
30
 
31
- Planning to document using chatGPT,
32
- Not documented yet, so you'll have to look at documents written inside the codes. (Most codes contain explanation)
31
+ Undocumented, so you'll have to look at documents written inside the codes or with help(). (Most codes contain explanation)
32
+ Planning to document with chatGPT.
33
33
 
34
34
  I'm happy to discuss questions or suggestions, please contact me via email. :)
35
35
 
36
- 1.0.1. (2025.5.1.)
37
-
38
- - `tools.sklearn.metrics.r2_score()` `multioutput` argument fixed
39
- - `tools.sklearn.metrics` axis=None returns a single np.float object
36
+ 1.0.4. (2025.8.14.)
37
+ - `tools.sklearn.metrics` stable, has proper arguments `axis_ref`, `axis_bias`
@@ -4,6 +4,7 @@ setup.py
4
4
  tools/__init__.py
5
5
  tools/array.py
6
6
  tools/data.py
7
+ tools/dict_operations.py
7
8
  tools/exp.py
8
9
  tools/modules.py
9
10
  tools/os.py
@@ -1,5 +0,0 @@
1
- from .sklearn import *
2
- from .utils import *
3
-
4
- if __name__ == '__main__':
5
- pass
@@ -1,112 +0,0 @@
1
- from collections.abc import Iterable
2
- import warnings
3
-
4
- import numpy as np
5
- from sklearn.metrics import r2_score as r2_score_sklearn
6
-
7
- def squared_error(y_true, y_pred, axis=None):
8
- """
9
- MSE averaging across specified axis.
10
- if axis=(), returns entry-by-entry squared error.
11
-
12
- Parameters
13
- ----------
14
- y_true : np.ndarray
15
- y_pred : np.ndarray
16
-
17
- axis : int or iterable of int, default=None
18
- Axis to collapse.
19
-
20
- Returns
21
- -------
22
- score : numpy.ndarray of shape with collapsed axis
23
- """
24
- if axis is None:
25
- axis = tuple(range(y_true.ndim)) # Collapse all dimensions
26
- score = (y_true-y_pred)**2
27
- score = np.mean(score, axis=axis)
28
- return score
29
-
30
- def absolute_error(y_true, y_pred, axis=None):
31
- """
32
- MAE averaging across specified axis.
33
- if axis=(), returns entry-by-entry squared error.
34
-
35
- Parameters
36
- ----------
37
- y_true : np.ndarray
38
- y_pred : np.ndarray
39
-
40
- axis : int or iterable of int, default=None
41
- Axis to collapse.
42
-
43
- Returns
44
- -------
45
- score : numpy.ndarray of shape with collapsed axis
46
- """
47
- if axis is None:
48
- axis = tuple(range(y_true.ndim)) # Collapse all dimensions
49
- score = np.abs(y_true-y_pred)
50
- score = np.mean(score, axis=axis)
51
- return score
52
-
53
- def r2_score(y_true, y_pred, axis=None, multioutput='raw_values'):
54
- """
55
- R^2 score for multidimensional predictions.
56
- collapses all axes except the specified axis.
57
-
58
- Parameters
59
- ----------
60
- y_true : np.ndarray
61
- y_pred : np.ndarray
62
- axis: int or iterable of int, default=None
63
- Axis to collapse.
64
- It must be specified if y_true and y_pred dimensions are > 2
65
- multioutput : Reference to `sklearn.metrics.r2_score`
66
- https://scikit-learn.org/stable/modules/generated/sklearn.metrics.r2_score.html
67
-
68
- Returns
69
- -------
70
- z : np.ndarray
71
- if axis is specified, returns an array of shape (y_true.shape[axis],)
72
- """
73
- assert y_true.shape == y_pred.shape, f"y_true and y_pred must have the same shape, received: {y_true.shape} and {y_pred.shape}"
74
- if axis is None:
75
- axis = list(range(y_true.ndim)) # Collapse all dimensions
76
- axis_was_none = True
77
- elif not isinstance(axis, Iterable):
78
- axis = [axis]
79
- axis_was_none = False
80
- else:
81
- axis = list(axis)
82
- axis_was_none = False
83
-
84
- if len(axis) > y_true.ndim:
85
- raise ValueError("Axis is greater than the number of dimensions of y_true and y_pred")
86
-
87
- dim_collapse = axis
88
- dim_final = list(set(range(y_true.ndim)).difference(axis))
89
- shape_final = np.array(y_true.shape)[dim_final] if len(dim_final)!=0 else (1,)
90
-
91
- y_true = np.transpose(y_true, (*dim_collapse, *dim_final)).reshape(-1, np.prod(shape_final)) # Move axis to the end, and flatten the rest
92
- y_pred = np.transpose(y_pred, (*dim_collapse, *dim_final)).reshape(-1, np.prod(shape_final))
93
-
94
- # score = r2_score_sklearn(y_true, y_pred, multioutput=multioutput)
95
- score = r2_score_sklearn(y_true, y_pred, multioutput='raw_values')
96
-
97
- if type(score) == float and np.isnan(score).item():
98
- warnings.warn("R2 score is a single NaN, shape matching with NaN")
99
- score = np.full(shape_final, np.nan)
100
- return score
101
-
102
- if multioutput == 'raw_values':
103
- score = score.reshape(*shape_final) if not axis_was_none else score[0]
104
- return score
105
- elif multioutput == 'uniform_average':
106
- return score.mean()
107
- elif multioutput == 'variance_weighted':
108
- return np.average(score, weights=np.var(y_true, axis=0))
109
- else:
110
- raise ValueError("multioutput must be one of ['raw_values', 'uniform_average', 'variance_weighted']")
111
-
112
- # %%
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes