Moral88 0.1.0__py3-none-any.whl → 0.3.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Moral88/regression.py CHANGED
@@ -1,25 +1,266 @@
1
- # Moral88/regression.py
2
1
  import numpy as np
3
2
 
4
- def mean_absolute_error(y_true, y_pred):
3
+ def validate_inputs(y_true, y_pred):
5
4
  """
6
- Compute MAE (Mean Absolute Error)
5
+ Validate the inputs for type and length.
7
6
  """
8
- y_true, y_pred = np.array(y_true), np.array(y_pred)
9
- return np.mean(np.abs(y_true - y_pred))
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.")
10
9
 
11
- def mean_squared_error(y_true, y_pred):
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):
12
20
  """
13
- Compute MSE (Mean Squared Error)
21
+ Calculate Mean Absolute Error (MAE) for single or multi-dimensional data.
14
22
  """
15
- y_true, y_pred = np.array(y_true), np.array(y_pred)
16
- return np.mean((y_true - y_pred) ** 2)
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'}.")
17
46
 
18
- def r_squared(y_true, y_pred):
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):
19
73
  """
20
- Compute R-Squared
74
+ Calculate Mean Squared Error (MSE) for single or multi-dimensional data.
21
75
  """
22
- y_true, y_pred = np.array(y_true), np.array(y_pred)
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
+
23
138
  ss_total = np.sum((y_true - np.mean(y_true)) ** 2)
24
139
  ss_residual = np.sum((y_true - y_pred) ** 2)
25
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.1.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
@@ -0,0 +1,8 @@
1
+ Moral88/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ Moral88/regression.py,sha256=kfWQcdtdZVlHW_iIRbS9_rNrKJOYNiT9RaeYpVIvl7I,9355
3
+ Moral88/segmentation.py,sha256=v0yqxdrKbM9LM7wVKLjJ4HrhrSrilNNeWS6-oK_27Ag,1363
4
+ Moral88-0.3.0.dist-info/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ Moral88-0.3.0.dist-info/METADATA,sha256=rKJtI5aX0pT3DSORLtFmsMPYB8fiAbGNQKmEndRNPtI,407
6
+ Moral88-0.3.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
7
+ Moral88-0.3.0.dist-info/top_level.txt,sha256=-dyn5iTprnSUHbtMpvRO-prJsIoaRxao7wlfCHLSsv4,8
8
+ Moral88-0.3.0.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- Moral88/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- Moral88/regression.py,sha256=5Rtc3EduWt8FZmyu9mLCqwoA1s4Hb7ToGh5yev_1rO0,727
3
- Moral88-0.1.0.dist-info/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- Moral88-0.1.0.dist-info/METADATA,sha256=eERIH5OJsirY5Wa6DvSpLrWj9wTobBSRAnHMWs3BGro,407
5
- Moral88-0.1.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
6
- Moral88-0.1.0.dist-info/top_level.txt,sha256=-dyn5iTprnSUHbtMpvRO-prJsIoaRxao7wlfCHLSsv4,8
7
- Moral88-0.1.0.dist-info/RECORD,,