mlquantify 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl

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.
@@ -907,10 +907,140 @@ class PCC(AggregativeQuantifier):
907
907
 
908
908
 
909
909
 
910
+ class PACC(AggregativeQuantifier):
911
+ """
912
+ Probabilistic Adjusted Classify and Count (PACC).
913
+ This method extends the Adjusted Classify and Count (AC) approach
914
+ by leveraging the average class-conditional confidences obtained
915
+ from a probabilistic classifier instead of relying solely on true
916
+ positive and false positive rates.
917
+
918
+ Parameters
919
+ ----------
920
+ learner : BaseEstimator
921
+ A scikit-learn compatible classifier to be used for quantification.
922
+ threshold : float, optional
923
+ The decision threshold for classification. Default is 0.5.
924
+
925
+ Attributes
926
+ ----------
927
+ learner : BaseEstimator
928
+ A scikit-learn compatible classifier.
929
+ threshold : float
930
+ Decision threshold for classification. Default is 0.5.
931
+ tpr : float
932
+ True positive rate computed during the fitting process.
933
+ fpr : float
934
+ False positive rate computed during the fitting process.
935
+
936
+ See Also
937
+ --------
938
+ ThresholdOptimization : Base class for threshold-based quantification methods.
939
+ ACC : Adjusted Classify and Count quantification method.
940
+ CC : Classify and Count quantification method.
941
+
942
+ References
943
+ ----------
944
+ A. Bella, C. Ferri, J. Hernández-Orallo and M. J. Ramírez-Quintana, "Quantification via Probability Estimators," 2010 IEEE International Conference on Data Mining, Sydney, NSW, Australia, 2010, pp. 737-742, doi: 10.1109/ICDM.2010.75. Available at: https://ieeexplore.ieee.org/abstract/document/5694031
910
945
 
946
+ Examples
947
+ --------
948
+ >>> from mlquantify.methods.aggregative import PACC
949
+ >>> from mlquantify.utils.general import get_real_prev
950
+ >>> from sklearn.datasets import load_breast_cancer
951
+ >>> from sklearn.svm import SVC
952
+ >>> from sklearn.model_selection import train_test_split
953
+ >>>
954
+ >>> features, target = load_breast_cancer(return_X_y=True)
955
+ >>>
956
+ >>> X_train, X_test, y_train, y_test = train_test_split(features, target, test_size=0.2, random_state=42)
957
+ >>>
958
+ >>> pacc = PACC(learner=SVC(probability=True))
959
+ >>> pacc.fit(X_train, y_train)
960
+ >>> y_pred = pacc.predict(X_test)
961
+ >>> y_pred
962
+ {0: 0.4664886119311328, 1: 0.5335113880688672}
963
+ >>> get_real_prev(y_test)
964
+ {0: 0.3991228070175439, 1: 0.6008771929824561}
965
+ """
911
966
 
967
+ def __init__(self, learner: BaseEstimator=None, threshold: float = 0.5):
968
+ self.learner = learner
969
+ self.threshold = threshold
970
+ self.mean_pos = None
971
+ self.mean_neg = None
972
+
973
+ @property
974
+ def is_probabilistic(self) -> bool:
975
+ return True
976
+
977
+ @property
978
+ def is_multiclass(self) -> bool:
979
+ return False
912
980
 
981
+ def _fit_method(self, X, y):
982
+ # Get predicted labels and probabilities
983
+ if mq.arguments["y_labels"] is not None and mq.arguments["posteriors_train"] is not None:
984
+ y_labels = mq.arguments["y_labels"]
985
+ probabilities = mq.arguments["posteriors_train"]
986
+ else:
987
+ y_labels, probabilities = get_scores(X, y, self.learner, self.cv_folds, self.learner_fitted)
988
+
989
+ # Adjust thresholds and compute true and false positive rates
990
+
991
+ self.mean_pos = np.mean(probabilities[y_labels == self.classes[1], 1])
992
+ self.mean_neg = np.mean(probabilities[y_labels != self.classes[1], 1])
993
+
994
+ return self
995
+
996
+
997
+ def _predict_method(self, X):
998
+ """
999
+ Predicts the class prevalence using the mean class-conditional
1000
+ probabilities from a probabilistic classifier.
913
1001
 
1002
+ Parameters
1003
+ ----------
1004
+ X : array-like or sparse matrix of shape (n_samples, n_features)
1005
+ The input data for prediction.
1006
+
1007
+ Returns
1008
+ -------
1009
+ dict
1010
+ A dictionary with class labels as keys and their respective
1011
+ prevalence estimates as values.
1012
+
1013
+ Notes
1014
+ -----
1015
+ The prevalence is adjusted using the formula:
1016
+ prevalence = |mean_score - FPR| / (TPR - FPR),
1017
+ where mean_score is the average probability for the positive class.
1018
+
1019
+ Raises
1020
+ ------
1021
+ ZeroDivisionError
1022
+ If `TPR - FPR` equals zero, indicating that the classifier's
1023
+ performance does not vary across the threshold range.
1024
+ """
1025
+ prevalences = {}
1026
+
1027
+ # Calculate probabilities for the positive class
1028
+ probabilities = self.predict_learner(X)[:, 1]
1029
+
1030
+ # Compute the mean score for the positive class
1031
+ mean_scores = np.mean(probabilities)
1032
+
1033
+ # Adjust prevalence based on TPR and FPR
1034
+ if self.mean_pos - self.mean_neg == 0:
1035
+ prevalence = mean_scores
1036
+ else:
1037
+ prevalence = np.clip(abs(mean_scores - self.mean_neg) / (self.mean_pos - self.mean_neg), 0, 1)
1038
+
1039
+ # Map the computed prevalence to the class labels
1040
+ prevalences[self.classes[0]] = 1 - prevalence
1041
+ prevalences[self.classes[1]] = prevalence
1042
+
1043
+ return prevalences
914
1044
 
915
1045
 
916
1046
  class PWK(AggregativeQuantifier):
@@ -1012,7 +1142,6 @@ class PWK(AggregativeQuantifier):
1012
1142
  from . import threshold_optimization
1013
1143
 
1014
1144
  ACC = threshold_optimization.ACC
1015
- PACC = threshold_optimization.PACC
1016
1145
  T50 = threshold_optimization.T50
1017
1146
  MAX = threshold_optimization.MAX
1018
1147
  X_method = threshold_optimization.X_method
@@ -659,157 +659,6 @@ class MS2(ThresholdOptimization):
659
659
 
660
660
  return np.asarray(prevalences)
661
661
 
662
- class PACC(ThresholdOptimization):
663
- """
664
- Probabilistic Adjusted Classify and Count (PACC).
665
- This method extends the Adjusted Classify and Count (AC) approach
666
- by leveraging the average class-conditional confidences obtained
667
- from a probabilistic classifier instead of relying solely on true
668
- positive and false positive rates.
669
-
670
- Parameters
671
- ----------
672
- learner : BaseEstimator
673
- A scikit-learn compatible classifier to be used for quantification.
674
- threshold : float, optional
675
- The decision threshold for classification. Default is 0.5.
676
-
677
- Attributes
678
- ----------
679
- learner : BaseEstimator
680
- A scikit-learn compatible classifier.
681
- threshold : float
682
- Decision threshold for classification. Default is 0.5.
683
- tpr : float
684
- True positive rate computed during the fitting process.
685
- fpr : float
686
- False positive rate computed during the fitting process.
687
-
688
- See Also
689
- --------
690
- ThresholdOptimization : Base class for threshold-based quantification methods.
691
- ACC : Adjusted Classify and Count quantification method.
692
- CC : Classify and Count quantification method.
693
-
694
- References
695
- ----------
696
- A. Bella, C. Ferri, J. Hernández-Orallo and M. J. Ramírez-Quintana, "Quantification via Probability Estimators," 2010 IEEE International Conference on Data Mining, Sydney, NSW, Australia, 2010, pp. 737-742, doi: 10.1109/ICDM.2010.75. Available at: https://ieeexplore.ieee.org/abstract/document/5694031
697
-
698
- Examples
699
- --------
700
- >>> from mlquantify.methods.aggregative import PACC
701
- >>> from mlquantify.utils.general import get_real_prev
702
- >>> from sklearn.datasets import load_breast_cancer
703
- >>> from sklearn.svm import SVC
704
- >>> from sklearn.model_selection import train_test_split
705
- >>>
706
- >>> features, target = load_breast_cancer(return_X_y=True)
707
- >>>
708
- >>> X_train, X_test, y_train, y_test = train_test_split(features, target, test_size=0.2, random_state=42)
709
- >>>
710
- >>> pacc = PACC(learner=SVC(probability=True))
711
- >>> pacc.fit(X_train, y_train)
712
- >>> y_pred = pacc.predict(X_test)
713
- >>> y_pred
714
- {0: 0.4664886119311328, 1: 0.5335113880688672}
715
- >>> get_real_prev(y_test)
716
- {0: 0.3991228070175439, 1: 0.6008771929824561}
717
- """
718
-
719
- def __init__(self, learner: BaseEstimator=None, threshold: float = 0.5):
720
- super().__init__(learner)
721
- self.threshold = threshold
722
-
723
- def _predict_method(self, X):
724
- """
725
- Predicts the class prevalence using the mean class-conditional
726
- probabilities from a probabilistic classifier.
727
-
728
- Parameters
729
- ----------
730
- X : array-like or sparse matrix of shape (n_samples, n_features)
731
- The input data for prediction.
732
-
733
- Returns
734
- -------
735
- dict
736
- A dictionary with class labels as keys and their respective
737
- prevalence estimates as values.
738
-
739
- Notes
740
- -----
741
- The prevalence is adjusted using the formula:
742
- prevalence = |mean_score - FPR| / (TPR - FPR),
743
- where mean_score is the average probability for the positive class.
744
-
745
- Raises
746
- ------
747
- ZeroDivisionError
748
- If `TPR - FPR` equals zero, indicating that the classifier's
749
- performance does not vary across the threshold range.
750
- """
751
- prevalences = {}
752
-
753
- # Calculate probabilities for the positive class
754
- probabilities = self.predict_learner(X)[:, 1]
755
-
756
- # Compute the mean score for the positive class
757
- mean_scores = np.mean(probabilities)
758
-
759
- # Adjust prevalence based on TPR and FPR
760
- if self.tpr - self.fpr == 0:
761
- prevalence = mean_scores
762
- else:
763
- prevalence = np.clip(abs(mean_scores - self.fpr) / (self.tpr - self.fpr), 0, 1)
764
-
765
- # Map the computed prevalence to the class labels
766
- prevalences[self.classes[0]] = 1 - prevalence
767
- prevalences[self.classes[1]] = prevalence
768
-
769
- return prevalences
770
-
771
- def best_tprfpr(self, thresholds: np.ndarray, tprs: np.ndarray, fprs: np.ndarray) -> tuple:
772
- """
773
- Finds the true positive rate (TPR) and false positive rate (FPR)
774
- corresponding to the specified decision threshold.
775
-
776
- Parameters
777
- ----------
778
- thresholds : np.ndarray
779
- An array of threshold values.
780
- tprs : np.ndarray
781
- An array of true positive rates corresponding to the thresholds.
782
- fprs : np.ndarray
783
- An array of false positive rates corresponding to the thresholds.
784
-
785
- Returns
786
- -------
787
- tuple
788
- A tuple containing the specified threshold, TPR, and FPR.
789
-
790
- Raises
791
- ------
792
- IndexError
793
- If the specified threshold is not found in the `thresholds` array.
794
- """
795
- # Locate TPR and FPR for the specified threshold
796
- tpr = tprs[thresholds == self.threshold][0]
797
- fpr = fprs[thresholds == self.threshold][0]
798
- return (self.threshold, tpr, fpr)
799
-
800
-
801
-
802
-
803
- def best_tprfpr(self, thresholds:np.ndarray, tprs: np.ndarray, fprs: np.ndarray) -> tuple:
804
- tpr = tprs[thresholds == self.threshold][0]
805
- fpr = fprs[thresholds == self.threshold][0]
806
- return (self.threshold, tpr, fpr)
807
-
808
-
809
-
810
-
811
-
812
-
813
662
 
814
663
 
815
664
  class T50(ThresholdOptimization):
@@ -26,12 +26,9 @@ def convert_columns_to_arrays(df, columns:list = ['PRED_PREVS', 'REAL_PREVS']):
26
26
  return df
27
27
 
28
28
 
29
-
30
-
31
-
32
- def generate_artificial_indexes(y, prevalence: list, sample_size:int, classes:list):
29
+ def get_indexes_with_prevalence(y, prevalence: list, sample_size:int):
33
30
  """
34
- Generate indexes for a stratified sample based on the prevalence of each class.
31
+ Get indexes for a stratified sample based on the prevalence of each class.
35
32
 
36
33
  Parameters
37
34
  ----------
@@ -48,10 +45,13 @@ def generate_artificial_indexes(y, prevalence: list, sample_size:int, classes:li
48
45
  -------
49
46
  list
50
47
  List of indexes for the stratified sample.
51
- """
48
+ """
49
+ classes = np.unique(y)
50
+
52
51
  # Ensure the sum of prevalences is 1
53
52
  assert np.isclose(sum(prevalence), 1), "The sum of prevalences must be 1"
54
53
  # Ensure the number of prevalences matches the number of classes
54
+ assert len(prevalence) == len(classes), "The number of prevalences must match the number of classes"
55
55
 
56
56
  sampled_indexes = []
57
57
  total_sampled = 0
@@ -78,6 +78,43 @@ def generate_artificial_indexes(y, prevalence: list, sample_size:int, classes:li
78
78
 
79
79
 
80
80
 
81
+ def kraemer_sampling(n_dim: int, n_prev: int, n_iter: int = 1) -> np.ndarray:
82
+ """
83
+ Uniform sampling from the unit simplex using Kraemer's algorithm.
84
+
85
+ Parameters
86
+ ----------
87
+ n_dim : int
88
+ Number of dimensions.
89
+ n_prev : int
90
+ Size of the sample.
91
+ n_iter : int
92
+ Number of iterations.
93
+
94
+ Returns
95
+ -------
96
+ np.ndarray
97
+ Array of sampled prevalences.
98
+ """
99
+
100
+ def _sampling(n_dim: int, n_prev: int) -> np.ndarray:
101
+ if n_dim == 2:
102
+ u = np.random.rand(n_prev)
103
+ return np.vstack([1 - u, u]).T
104
+ else:
105
+ u = np.random.rand(n_prev, n_dim - 1)
106
+ u.sort(axis=-1) # sort each row
107
+ _0s = np.zeros((n_prev, 1))
108
+ _1s = np.ones((n_prev, 1))
109
+ a = np.hstack([_0s, u])
110
+ b = np.hstack([u, _1s])
111
+ return b - a
112
+
113
+ # repeat n_iter times
114
+ prevs = _sampling(n_dim, n_prev)
115
+
116
+ return np.repeat(prevs, n_iter, axis=0) if n_iter > 1 else prevs
117
+
81
118
 
82
119
  def generate_artificial_prevalences(n_dim: int, n_prev: int, n_iter: int) -> np.ndarray:
83
120
  """Generates n artificial prevalences with n dimensions.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mlquantify
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Quantification Library
5
5
  Home-page: https://github.com/luizfernandolj/QuantifyML/tree/master
6
6
  Maintainer: Luiz Fernando Luth Junior
@@ -40,9 +40,9 @@ ___
40
40
 
41
41
  ## Latest Release
42
42
 
43
- - **Version 0.0.11.6**: Inicial beta version. For a detailed list of changes, check the [changelog](#).
44
- - In case you need any help, refer to the [wiki](https://github.com/luizfernandolj/mlquantify/wiki).
45
- - Explore the [API documentation](#) for detailed developer information.
43
+ - **Version 0.1.3**: Inicial beta version. For a detailed list of changes, check the [changelog](#).
44
+ - In case you need any help, refer to the [User Guide](https://luizfernandolj.github.io/mlquantify/user_guide.html).
45
+ - Explore the [API documentation](https://luizfernandolj.github.io/mlquantify/api/index.html) for detailed developer information.
46
46
  - See also the library in the pypi site in [pypi mlquantify](https://pypi.org/project/mlquantify/)
47
47
 
48
48
  ___
@@ -70,7 +70,7 @@ ___
70
70
  | **21 Quantification Methods** | Methods for quantification, such as classify & Count Correct methods, Threshold Optimization, Mixture Models and more.|
71
71
  | **Dynamic class management** | All methods are dynamic, and handles multiclass and binary problems, in case of binary it makes One-Vs-All (OVA) automatically. |
72
72
  | **Model Selection** | Criteria and processes used to select the best model, such as grid-search for the case of quantification|
73
- | **Evaluation Metrics** | Specific metrics used to evaluate quantification performance, (e.g., AE, BIAS, NAE, SE, KLD, etc.). |
73
+ | **Evaluation Metrics** | Specific metrics used to evaluate quantification performance, (e.g., AE, MAE, NAE, SE, KLD, etc.). |
74
74
  | **Evaluation Protocols** | Evaluation protocols used, based on sampling generation (e.g., APP, NPP, etc.).. |
75
75
  | **Plotting Results** | Tools and techniques used to visualize results, such as the protocol results.|
76
76
  | **Comprehensive Documentation** | Complete documentation of the project, including code, data, and results. |
@@ -82,7 +82,10 @@ ___
82
82
  This code first loads the breast cancer dataset from _sklearn_, which is then split into training and testing sets. It uses the _Expectation Maximisation Quantifier (EMQ)_ with a RandomForest classifier to predict class prevalence. After training the model, it evaluates performance by calculating and printing the absolute error and bias between the real and predicted prevalences.
83
83
 
84
84
  ```python
85
- import mlquantify as mq
85
+ from mlquantify.methods import EMQ
86
+ from mlquantify.evaluation.measures import absolute_error, mean_absolute_error
87
+ from mlquantify.utils import get_real_prev
88
+
86
89
  from sklearn.ensemble import RandomForestClassifier
87
90
  from sklearn.datasets import load_breast_cancer
88
91
  from sklearn.model_selection import train_test_split
@@ -94,19 +97,19 @@ features, target = load_breast_cancer(return_X_y=True)
94
97
  X_train, X_test, y_train, y_test = train_test_split(features, target, test_size=0.3)
95
98
 
96
99
  #Create the model, here it is the Expectation Maximisation Quantifier (EMQ) with a classifier
97
- model = mq.methods.EMQ(RandomForestClassifier())
100
+ model = EMQ(RandomForestClassifier())
98
101
  model.fit(X_train, y_train)
99
102
 
100
103
  #Predict the class prevalence for X_test
101
104
  pred_prevalence = model.predict(X_test)
102
- real_prevalence = mq.utils.get_real_prev(y_test)
105
+ real_prevalence = get_real_prev(y_test)
103
106
 
104
107
  #Get the error for the prediction
105
- ae = mq.evaluation.absolute_error(real_prevalence, pred_prevalence)
106
- bias = mq.evaluation.bias(real_prevalence, pred_prevalence)
108
+ ae = absolute_error(real_prevalence, pred_prevalence)
109
+ mae = mean_absolute_error(real_prevalence, pred_prevalence)
107
110
 
108
- print(f"Mean Squared Error (MSE) -> {ae:.4f}")
109
- print(f"Bias -> {bias}")
111
+ print(f"Absolute Error -> {ae}")
112
+ print(f"Mean Absolute Error -> {mae}")
110
113
  ```
111
114
 
112
115
  ___
@@ -125,7 +128,7 @@ ___
125
128
 
126
129
  ## Documentation
127
130
 
128
- ##### API is avaliable [here](#)
131
+ ##### API is avaliable [here](https://luizfernandolj.github.io/mlquantify/api/index.html)
129
132
 
130
133
  - [Methods](https://github.com/luizfernandolj/mlquantify/wiki/Methods)
131
134
  - [Model Selection](https://github.com/luizfernandolj/mlquantify/wiki/Model-Selection)
@@ -6,17 +6,17 @@ mlquantify/classification/__init__.py,sha256=3FGf-F4SOM3gByUPsWdnBzjyC_31B3Mtzuo
6
6
  mlquantify/classification/methods.py,sha256=yDSbpoqM3hfF0a9ATzKqfG9S-44x-0Rq0lkAVJKTIEs,5006
7
7
  mlquantify/evaluation/__init__.py,sha256=x1grng0n_QeZpVBU8-pwagYdBMkbMRILtrp1qk_bLvk,447
8
8
  mlquantify/evaluation/measures.py,sha256=fIKyxxlD8em3oaj4u_BeXmNyUQG_A0vXWY8APPgNoJ0,6579
9
- mlquantify/evaluation/protocol.py,sha256=OsOXm_vf7sYlw9pQv08WxAvvgzo10bAqiDM-1cpz7nQ,24020
9
+ mlquantify/evaluation/protocol.py,sha256=__tzRyqW4cJz4Fl87TInf7dXxIJ6bSaYaSaw-SdkNmM,10365
10
10
  mlquantify/methods/__init__.py,sha256=ya3Mn7bcz2r3oaIT7yVR4iJkAfgEAwF4xDK54C0rZ7U,536
11
- mlquantify/methods/aggregative.py,sha256=rL_xlX2nYECrxFSjBJNlxj6h3b-iIs7l_XgxIRSYHpw,34164
11
+ mlquantify/methods/aggregative.py,sha256=F5Z-tGA9OcZgMBLKOeaos6wIgvvnDeriZ4y0TyMpDrc,39051
12
12
  mlquantify/methods/meta.py,sha256=sZWQHUGkm6iiqujmIpHDL_8tDdKQ161bzD5mcpXLWEY,19066
13
13
  mlquantify/methods/mixture_models.py,sha256=si2Pzaka5Kbva4QKBzLolvb_8V0ZEjp68UBAiOwl49s,35166
14
14
  mlquantify/methods/non_aggregative.py,sha256=xaBu21TUtiYkOEUKO16NaNMwdNa6-SNjfBsc5PpIMyI,4815
15
- mlquantify/methods/threshold_optimization.py,sha256=-iOcP5YcXZd0XZHGvbmcoE72hXR6D9YCoTnr1l80-9k,35796
15
+ mlquantify/methods/threshold_optimization.py,sha256=NYGKbYvtfmiBeU8wpTiFCdURkijcPRZtybPOt6vtXbY,30489
16
16
  mlquantify/utils/__init__.py,sha256=logWrL6B6mukP8tvYm_UPEdO9eNA-J-ySILr7-syDoc,44
17
- mlquantify/utils/general.py,sha256=Li5ix_dy19dUhYNgiUsNHdqqnSVYvznUBUuyr-zYSPI,7554
17
+ mlquantify/utils/general.py,sha256=wKJSmwF1KfSlSrDm0KTf92FMvB62BBOxf2Se9HyeWYE,8668
18
18
  mlquantify/utils/method.py,sha256=RL4vBJGl5_6DZ59Bs62hdNXI_hnoDIWilMMyMPiOjBg,12631
19
- mlquantify-0.1.2.dist-info/METADATA,sha256=2j3pqrm5djMAPm7bKTIjBjtg71OzAbFpwC-_ofOoSlc,4940
20
- mlquantify-0.1.2.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
21
- mlquantify-0.1.2.dist-info/top_level.txt,sha256=tGEkYkbbFElwULvqENjam3u1uXtyC1J9dRmibsq8_n0,11
22
- mlquantify-0.1.2.dist-info/RECORD,,
19
+ mlquantify-0.1.4.dist-info/METADATA,sha256=UtNxYnZnSt6HS0B8JsW5A5tvxlxFUH_GODjF1AXXsSY,5166
20
+ mlquantify-0.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ mlquantify-0.1.4.dist-info/top_level.txt,sha256=tGEkYkbbFElwULvqENjam3u1uXtyC1J9dRmibsq8_n0,11
22
+ mlquantify-0.1.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5