Moral88 0.2.0__tar.gz → 0.3.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,266 @@
1
+ import numpy as np
2
+
3
+ def validate_inputs(y_true, y_pred):
4
+ """
5
+ Validate the inputs for type and length.
6
+ """
7
+ if not isinstance(y_true, (list, tuple, np.ndarray)) or not isinstance(y_pred, (list, tuple, np.ndarray)):
8
+ raise TypeError("Both y_true and y_pred must be lists, tuples, or numpy arrays.")
9
+
10
+ y_true = np.array(y_true)
11
+ y_pred = np.array(y_pred)
12
+
13
+ if y_true.shape != y_pred.shape:
14
+ raise ValueError("Shapes of y_true and y_pred must be the same.")
15
+
16
+ if not np.issubdtype(y_true.dtype, np.number) or not np.issubdtype(y_pred.dtype, np.number):
17
+ raise TypeError("All elements in y_true and y_pred must be numeric.")
18
+
19
+ def mean_absolute_error(y_true, y_pred, normalize=True, threshold=None, method='mean', library='Moral88', flatten=True):
20
+ """
21
+ Calculate Mean Absolute Error (MAE) for single or multi-dimensional data.
22
+ """
23
+ validate_inputs(y_true, y_pred)
24
+
25
+ # y_true = np.array(y_true)
26
+ # y_pred = np.array(y_pred)
27
+
28
+ if flatten:
29
+ y_true = y_true.ravel()
30
+ y_pred = y_pred.ravel()
31
+
32
+ if library == 'Moral88':
33
+ if threshold is not None:
34
+ y_pred = np.clip(y_pred, threshold[0], threshold[1])
35
+
36
+ absolute_errors = np.abs(y_true - y_pred)
37
+
38
+ if method == 'mean':
39
+ result = np.mean(absolute_errors)
40
+ elif method == 'sum':
41
+ result = np.sum(absolute_errors)
42
+ elif method == 'none':
43
+ result = absolute_errors
44
+ else:
45
+ raise ValueError("Invalid method. Choose from {'mean', 'sum', 'none'}.")
46
+
47
+ if normalize and method != 'none':
48
+ range_y = np.ptp(y_true)
49
+ result = result / max(abs(range_y), 1)
50
+
51
+ return result
52
+
53
+ elif library == 'sklearn':
54
+ from sklearn.metrics import mean_absolute_error as sklearn_mae
55
+ return sklearn_mae(y_true, y_pred)
56
+
57
+ elif library == 'torch':
58
+ import torch
59
+ y_true_tensor = torch.tensor(y_true, dtype=torch.float32)
60
+ y_pred_tensor = torch.tensor(y_pred, dtype=torch.float32)
61
+ return torch.mean(torch.abs(y_true_tensor - y_pred_tensor)).item()
62
+
63
+ elif library == 'tensorflow':
64
+ import tensorflow as tf
65
+ y_true_tensor = tf.convert_to_tensor(y_true, dtype=tf.float32)
66
+ y_pred_tensor = tf.convert_to_tensor(y_pred, dtype=tf.float32)
67
+ return tf.reduce_mean(tf.abs(y_true_tensor - y_pred_tensor)).numpy()
68
+
69
+ else:
70
+ raise ValueError(f"Invalid library: {library}. Choose from {'Moral88', 'sklearn', 'torch', 'tensorflow'}.")
71
+
72
+ def mean_squared_error(y_true, y_pred, normalize=True, threshold=None, method='mean', library='Moral88', flatten=True):
73
+ """
74
+ Calculate Mean Squared Error (MSE) for single or multi-dimensional data.
75
+ """
76
+ validate_inputs(y_true, y_pred)
77
+
78
+ # y_true = np.array(y_true)
79
+ # y_pred = np.array(y_pred)
80
+
81
+ if flatten:
82
+ y_true = y_true.ravel()
83
+ y_pred = y_pred.ravel()
84
+
85
+ if library == 'Moral88':
86
+ if threshold is not None:
87
+ y_pred = np.clip(y_pred, threshold[0], threshold[1])
88
+
89
+ squared_errors = (y_true - y_pred) ** 2
90
+
91
+ if method == 'mean':
92
+ result = np.mean(squared_errors)
93
+ elif method == 'sum':
94
+ result = np.sum(squared_errors)
95
+ elif method == 'none':
96
+ result = squared_errors
97
+ else:
98
+ raise ValueError("Invalid method. Choose from {'mean', 'sum', 'none'}.")
99
+
100
+ if normalize and method != 'none':
101
+ range_y = np.ptp(y_true)
102
+ result = result / max(abs(range_y), 1)
103
+
104
+ return result
105
+
106
+ elif library == 'sklearn':
107
+ from sklearn.metrics import mean_squared_error as sklearn_mse
108
+ return sklearn_mse(y_true, y_pred)
109
+
110
+ elif library == 'torch':
111
+ import torch
112
+ y_true_tensor = torch.tensor(y_true, dtype=torch.float32)
113
+ y_pred_tensor = torch.tensor(y_pred, dtype=torch.float32)
114
+ return torch.mean((y_true_tensor - y_pred_tensor) ** 2).item()
115
+
116
+ elif library == 'tensorflow':
117
+ import tensorflow as tf
118
+ y_true_tensor = tf.convert_to_tensor(y_true, dtype=tf.float32)
119
+ y_pred_tensor = tf.convert_to_tensor(y_pred, dtype=tf.float32)
120
+ return tf.reduce_mean(tf.square(y_true_tensor - y_pred_tensor)).numpy()
121
+
122
+ else:
123
+ raise ValueError(f"Invalid library: {library}. Choose from {'Moral88', 'sklearn', 'torch', 'tensorflow'}.")
124
+
125
+ def r_squared(y_true, y_pred, flatten=True):
126
+ """
127
+ Compute R-Squared for single or multi-dimensional data.
128
+ """
129
+ validate_inputs(y_true, y_pred)
130
+
131
+ y_true = np.array(y_true)
132
+ y_pred = np.array(y_pred)
133
+
134
+ if flatten:
135
+ y_true = y_true.ravel()
136
+ y_pred = y_pred.ravel()
137
+
138
+ ss_total = np.sum((y_true - np.mean(y_true)) ** 2)
139
+ ss_residual = np.sum((y_true - y_pred) ** 2)
140
+ return 1 - (ss_residual / ss_total)
141
+
142
+ import numpy as np
143
+ import warnings
144
+ from typing import Union, List, Tuple
145
+ from scipy import sparse
146
+
147
+ class DataValidator:
148
+ def __init__(self):
149
+ pass
150
+
151
+ def check_device_cpu(self, device):
152
+ if device not in {"cpu", None}:
153
+ raise ValueError(f"Unsupported device: {device!r}. Only 'cpu' is supported.")
154
+
155
+ def is_1d_array(self, array: Union[np.ndarray, list], warn: bool = False) -> np.ndarray:
156
+ """
157
+ Ensures input is a 1D array. Raises an error if it's not 1D or convertible to 1D.
158
+ """
159
+ array = np.asarray(array)
160
+ shape = array.shape
161
+
162
+ if len(shape) == 1:
163
+ return array
164
+ elif len(shape) == 2 and shape[1] == 1:
165
+ if warn:
166
+ warnings.warn("Input is 2D but will be converted to 1D.", UserWarning)
167
+ return array.ravel()
168
+ else:
169
+ raise ValueError(f"Input must be 1D. Found shape {shape}.")
170
+
171
+ def check_samples(self, array: Union[np.ndarray, list]) -> int:
172
+ """
173
+ Returns the number of samples in the array.
174
+ """
175
+ if hasattr(array, 'shape') and len(array.shape) > 0:
176
+ return array.shape[0]
177
+ else:
178
+ raise TypeError("Input must be an array-like object with at least one dimension.")
179
+
180
+ def check_consistent_length(self, *arrays: Union[np.ndarray, list]):
181
+ """
182
+ Ensures all input arrays have the same length.
183
+ """
184
+ lengths = [self.check_samples(arr) for arr in arrays]
185
+ if len(set(lengths)) > 1:
186
+ raise ValueError(f"Inconsistent lengths: {lengths}")
187
+
188
+ def validate_regression_targets(self, y_true, y_pred, dtype=np.float64):
189
+ """
190
+ Ensures regression target values are consistent and converted to the specified dtype.
191
+ """
192
+ y_true = np.asarray(y_true, dtype=dtype)
193
+ y_pred = np.asarray(y_pred, dtype=dtype)
194
+
195
+ if y_true.shape != y_pred.shape:
196
+ raise ValueError(f"Shapes of y_true {y_true.shape} and y_pred {y_pred.shape} do not match.")
197
+
198
+ return y_true, y_pred
199
+
200
+ def check_array(self, array, ensure_2d: bool = True, dtype=np.float64, allow_nan: bool = False):
201
+ """
202
+ Validates input array and converts it to specified dtype.
203
+ """
204
+ array = np.asarray(array, dtype=dtype)
205
+
206
+ if ensure_2d and array.ndim == 1:
207
+ array = array.reshape(-1, 1)
208
+
209
+ if not allow_nan and np.isnan(array).any():
210
+ raise ValueError("Input contains NaN values, which are not allowed.")
211
+
212
+ return array
213
+
214
+ def check_sparse(self, array, accept_sparse: Tuple[str] = ('csr', 'csc')):
215
+ """
216
+ Validates sparse matrices and converts to an acceptable format.
217
+ """
218
+ if sparse.issparse(array):
219
+ if array.format not in accept_sparse:
220
+ return array.asformat(accept_sparse[0])
221
+ return array
222
+ else:
223
+ raise ValueError("Input is not a sparse matrix.")
224
+
225
+ def validate_r2_score_inputs(self, y_true, y_pred, sample_weight=None):
226
+ """
227
+ Ensures inputs for R2 score computation are valid.
228
+ """
229
+ y_true, y_pred = self.validate_regression_targets(y_true, y_pred)
230
+ if sample_weight is not None:
231
+ sample_weight = self.is_1d_array(sample_weight)
232
+ return y_true, y_pred, sample_weight
233
+
234
+
235
+ class Metrics:
236
+ def __init__(self):
237
+ self.validator = DataValidator()
238
+
239
+ def r2_score(self, y_true, y_pred, sample_weight=None):
240
+ """
241
+ Computes R2 score.
242
+ """
243
+ y_true, y_pred, sample_weight = self.validator.validate_r2_score_inputs(y_true, y_pred, sample_weight)
244
+
245
+ numerator = np.sum((y_true - y_pred) ** 2)
246
+ denominator = np.sum((y_true - np.mean(y_true)) ** 2)
247
+
248
+ if denominator == 0:
249
+ return 0.0
250
+ return 1 - (numerator / denominator)
251
+
252
+
253
+ if __name__ == '__main__':
254
+ # Example usage
255
+ validator = DataValidator()
256
+ metrics = Metrics()
257
+
258
+ # Test validation
259
+ arr = [[1], [2], [3]]
260
+ print("1D array:", validator.is_1d_array(arr))
261
+ print("Samples:", validator.check_samples(arr))
262
+
263
+ # Test R2 score
264
+ y_true = [3, -0.5, 2, 7]
265
+ y_pred = [2.5, 0.0, 2, 8]
266
+ print("R2 Score:", metrics.r2_score(y_true, y_pred))
@@ -0,0 +1,38 @@
1
+ def validate_segmentation_inputs(y_true, y_pred):
2
+ """
3
+ Validate the inputs for type and shape.
4
+ """
5
+ if not isinstance(y_true, (list, tuple)) or not isinstance(y_pred, (list, tuple)):
6
+ raise TypeError("Both y_true and y_pred must be lists or tuples.")
7
+
8
+ if len(y_true) != len(y_pred):
9
+ raise ValueError("Length of y_true and y_pred must be the same.")
10
+
11
+ if not all(isinstance(x, (int, float)) for x in y_true + y_pred):
12
+ raise TypeError("All elements in y_true and y_pred must be numeric.")
13
+
14
+ def dice_score(y_true, y_pred, threshold=0.5):
15
+ """
16
+ Compute the Dice Score.
17
+
18
+ Args:
19
+ y_true (list or tuple): Ground truth binary values.
20
+ y_pred (list or tuple): Predicted values (probabilities or binary).
21
+ threshold (float): Threshold to binarize y_pred if necessary.
22
+
23
+ Returns:
24
+ float: Dice Score.
25
+ """
26
+ validate_segmentation_inputs(y_true, y_pred)
27
+
28
+ # Binarize predictions based on threshold
29
+ y_pred = [1 if p >= threshold else 0 for p in y_pred]
30
+
31
+ # Calculate intersection and union
32
+ intersection = sum(yt * yp for yt, yp in zip(y_true, y_pred))
33
+ total = sum(y_true) + sum(y_pred)
34
+
35
+ if total == 0:
36
+ return 1.0 # Perfect match if both are completely empty
37
+
38
+ return 2 * intersection / total
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: Moral88
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: A library for regression evaluation metrics.
5
5
  Author: Morteza Alizadeh
6
6
  Author-email: alizadeh.c2m@gmail.com
@@ -3,6 +3,7 @@ README.md
3
3
  setup.py
4
4
  Moral88/__init__.py
5
5
  Moral88/regression.py
6
+ Moral88/segmentation.py
6
7
  Moral88.egg-info/PKG-INFO
7
8
  Moral88.egg-info/SOURCES.txt
8
9
  Moral88.egg-info/dependency_links.txt
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: Moral88
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: A library for regression evaluation metrics.
5
5
  Author: Morteza Alizadeh
6
6
  Author-email: alizadeh.c2m@gmail.com
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='Moral88',
5
- version='0.2.0',
5
+ version='0.3.0',
6
6
  description='A library for regression evaluation metrics.',
7
7
  author='Morteza Alizadeh',
8
8
  author_email='alizadeh.c2m@gmail.com',
@@ -1,139 +0,0 @@
1
- def mean_absolute_error(y_true, y_pred, normalize=True, threshold=None, method='mean', library='Moral88'):
2
- """
3
- Calculate Mean Absolute Error (MAE) or variants based on method and library.
4
-
5
- Parameters:
6
- - y_true (list or array): True values (required)
7
- - y_pred (list or array): Predicted values (required)
8
- - normalize (bool): If True, normalize the result (default: True)
9
- - threshold (tuple, optional): Apply a threshold to the predictions (default: None)
10
- - method (str): Method of calculation. Options: {'mean', 'sum', 'none'}. Default: 'mean'
11
- - library (str): Library to use for calculations. Options: {'Moral88', 'sklearn', 'torch', 'tensor', 'statsmodel', 'Dask-ML', 'MLlib'}. Default: 'Moral88'.
12
-
13
- Returns:
14
- - float or list: Calculated error based on selected method and library.
15
- """
16
- if library == 'Moral88':
17
- # Original implementation
18
- if threshold is not None:
19
- y_pred = [min(max(pred, threshold[0]), threshold[1]) for pred in y_pred]
20
-
21
- absolute_errors = [abs(y_t - y_p) for y_t, y_p in zip(y_true, y_pred)]
22
-
23
- if method == 'mean':
24
- result = sum(absolute_errors) / len(y_true)
25
- elif method == 'sum':
26
- result = sum(absolute_errors)
27
- elif method == 'none':
28
- result = absolute_errors
29
- else:
30
- raise ValueError("Invalid method. Choose from {'mean', 'sum', 'none'}.")
31
-
32
- if normalize and method != 'none':
33
- range_y = max(y_true) - min(y_true)
34
- result = result / max(abs(range_y), 1)
35
-
36
- return result
37
-
38
- elif library == 'sklearn':
39
- from sklearn.metrics import mean_absolute_error as sklearn_mae
40
- return sklearn_mae(y_true, y_pred)
41
-
42
- elif library == 'torch':
43
- import torch
44
- y_true_tensor = torch.tensor(y_true, dtype=torch.float32)
45
- y_pred_tensor = torch.tensor(y_pred, dtype=torch.float32)
46
- return torch.mean(torch.abs(y_true_tensor - y_pred_tensor)).item()
47
-
48
- elif library == 'tensorflow':
49
- import tensorflow as tf
50
- y_true_tensor = tf.convert_to_tensor(y_true, dtype=tf.float32)
51
- y_pred_tensor = tf.convert_to_tensor(y_pred, dtype=tf.float32)
52
- return tf.reduce_mean(tf.abs(y_true_tensor - y_pred_tensor)).numpy()
53
-
54
- # elif library == 'statsmodel':
55
- # raise NotImplementedError("Statsmodel does not have a built-in MAE implementation.")
56
-
57
- # elif library == 'Dask-ML':
58
- # raise NotImplementedError("Dask-ML support is not implemented yet.")
59
-
60
- # elif library == 'MLlib':
61
- # raise NotImplementedError("MLlib support is not implemented yet.")
62
-
63
- else:
64
- raise ValueError(f"Invalid library: {library}. Choose from {'Moral88', 'sklearn', 'torch', 'tensorflow'}.")
65
-
66
-
67
- def mean_squared_error(y_true, y_pred, normalize=True, threshold=None, method='mean', library='Moral88'):
68
- """
69
- Calculate Mean Squared Error (MSE) or variants based on method and library.
70
-
71
- Parameters:
72
- - y_true (list or array): True values (required)
73
- - y_pred (list or array): Predicted values (required)
74
- - normalize (bool): If True, normalize the result (default: True)
75
- - threshold (tuple, optional): Apply a threshold to the predictions (default: None)
76
- - method (str): Method of calculation. Options: {'mean', 'sum', 'none'}. Default: 'mean'
77
- - library (str): Library to use for calculations. Options: {'Moral88', 'sklearn', 'torch', 'tensor', 'statsmodel', 'Dask-ML', 'MLlib'}. Default: 'Moral88'.
78
-
79
- Returns:
80
- - float or list: Calculated error based on selected method and library.
81
- """
82
- if library == 'Moral88':
83
- # Original implementation
84
- if threshold is not None:
85
- y_pred = [min(max(pred, threshold[0]), threshold[1]) for pred in y_pred]
86
-
87
- squared_errors = [(y_t - y_p) ** 2 for y_t, y_p in zip(y_true, y_pred)]
88
-
89
- if method == 'mean':
90
- result = sum(squared_errors) / len(y_true)
91
- elif method == 'sum':
92
- result = sum(squared_errors)
93
- elif method == 'none':
94
- result = squared_errors
95
- else:
96
- raise ValueError("Invalid method. Choose from {'mean', 'sum', 'none'}.")
97
-
98
- if normalize and method != 'none':
99
- range_y = max(y_true) - min(y_true)
100
- result = result / max(abs(range_y), 1)
101
-
102
- return result
103
-
104
- elif library == 'sklearn':
105
- from sklearn.metrics import mean_squared_error as sklearn_mse
106
- return sklearn_mse(y_true, y_pred)
107
-
108
- elif library == 'torch':
109
- import torch
110
- y_true_tensor = torch.tensor(y_true, dtype=torch.float32)
111
- y_pred_tensor = torch.tensor(y_pred, dtype=torch.float32)
112
- return torch.mean((y_true_tensor - y_pred_tensor) ** 2).item()
113
-
114
- elif library == 'tensorflow':
115
- import tensorflow as tf
116
- y_true_tensor = tf.convert_to_tensor(y_true, dtype=tf.float32)
117
- y_pred_tensor = tf.convert_to_tensor(y_pred, dtype=tf.float32)
118
- return tf.reduce_mean(tf.square(y_true_tensor - y_pred_tensor)).numpy()
119
-
120
- # elif library == 'statsmodel':
121
- # raise NotImplementedError("Statsmodel does not have a built-in MSE implementation.")
122
-
123
- # elif library == 'Dask-ML':
124
- # raise NotImplementedError("Dask-ML support is not implemented yet.")
125
-
126
- # elif library == 'MLlib':
127
- # raise NotImplementedError("MLlib support is not implemented yet.")
128
-
129
- else:
130
- raise ValueError(f"Invalid library: {library}. Choose from {'Moral88', 'sklearn', 'torch', 'tensorflow'}.")
131
- def r_squared(y_true, y_pred):
132
- """
133
- Compute R-Squared
134
- """
135
- import numpy as np
136
- y_true, y_pred = np.array(y_true), np.array(y_pred)
137
- ss_total = np.sum((y_true - np.mean(y_true)) ** 2)
138
- ss_residual = np.sum((y_true - y_pred) ** 2)
139
- return 1 - (ss_residual / ss_total)
File without changes
File without changes
File without changes
File without changes