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.
- {tools-1.0.2 → tools-1.0.4}/PKG-INFO +6 -8
- {tools-1.0.2 → tools-1.0.4}/README.md +5 -7
- {tools-1.0.2 → tools-1.0.4}/tools/__init__.py +1 -1
- tools-1.0.4/tools/dict_operations.py +139 -0
- tools-1.0.4/tools/plot/__init__.py +26 -0
- tools-1.0.4/tools/sklearn/metrics.py +189 -0
- {tools-1.0.2 → tools-1.0.4}/tools/tools.py +35 -1
- {tools-1.0.2 → tools-1.0.4}/tools.egg-info/PKG-INFO +6 -8
- {tools-1.0.2 → tools-1.0.4}/tools.egg-info/SOURCES.txt +1 -0
- tools-1.0.2/tools/plot/__init__.py +0 -5
- tools-1.0.2/tools/sklearn/metrics.py +0 -112
- {tools-1.0.2 → tools-1.0.4}/LICENSE.txt +0 -0
- {tools-1.0.2 → tools-1.0.4}/setup.cfg +0 -0
- {tools-1.0.2 → tools-1.0.4}/setup.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/array.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/data.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/exp.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/hydra/__init__.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/modules.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/numpy/__init__.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/numpy/_f.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/numpy/_utils.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/os.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/pandas/__init__.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/plot/sklearn.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/plot/utils.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/random.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/sklearn/__init__.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/sklearn/model_selection.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/sklearn/preprocessing.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/stats/__init__.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/torch/__init__.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/torch/_pandas.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/torch/data.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/torch/estimator.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/torch/federated_learning.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/torch/layers.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/torch/model.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/torch/optim/__init__.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/torch/optim/lr_scheduler.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/torch/plot.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools/torch/utils.py +0 -0
- {tools-1.0.2 → tools-1.0.4}/tools.egg-info/dependency_links.txt +0 -0
- {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.
|
|
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
|
|
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
|
-
|
|
32
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
18
|
-
|
|
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.
|
|
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`
|
|
@@ -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=
|
|
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.
|
|
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
|
|
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
|
-
|
|
32
|
-
|
|
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.
|
|
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,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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|