diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e663818..b1f1265d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Integer overflow bug fixed - `numpy.trapz` deprecation bug fixed - Test system modified +- Interpretation functions `NaN` bug fixed ## [4.5] - 2025-10-15 ### Added - `optimal_thresholds` method in `ROCCurve` class diff --git a/Test/function_test.py b/Test/function_test.py index 859ca9f0..59a29c6b 100644 --- a/Test/function_test.py +++ b/Test/function_test.py @@ -513,10 +513,16 @@ 'Negligible' >>> Q_analysis(0.75) 'Strong' +>>> Q_analysis(float('nan')) +'None' >>> MCC_analysis(0.9) 'Very Strong' +>>> MCC_analysis(float('nan')) +'None' >>> V_analysis(0.8) 'Very Strong' +>>> V_analysis(float('nan')) +'None' >>> kappa_analysis_fleiss(0.75) 'Excellent' >>> kappa_analysis_koch(-0.1) @@ -533,12 +539,16 @@ 'Almost Perfect' >>> kappa_analysis_koch(1.2) 'None' +>>> kappa_analysis_koch(float('nan')) +'None' >>> kappa_analysis_fleiss(0.4) 'Intermediate to Good' >>> kappa_analysis_fleiss(0.75) 'Excellent' >>> kappa_analysis_fleiss(1.2) 'Excellent' +>>> kappa_analysis_fleiss(float('nan')) +'None' >>> kappa_analysis_altman(-0.2) 'Poor' >>> kappa_analysis_altman(0.2) @@ -551,6 +561,8 @@ 'Very Good' >>> kappa_analysis_altman(1.2) 'None' +>>> kappa_analysis_altman(float('nan')) +'None' >>> kappa_analysis_fleiss(0.2) 'Poor' >>> kappa_analysis_cicchetti(0.3) @@ -563,6 +575,8 @@ 'Excellent' >>> kappa_analysis_cicchetti(1.2) 'None' +>>> kappa_analysis_cicchetti(float('nan')) +'None' >>> lambda_analysis(0) 'None' >>> lambda_analysis(0.1) @@ -577,12 +591,16 @@ 'Very Strong' >>> lambda_analysis(1) 'Perfect' +>>> lambda_analysis(float('nan')) +'None' >>> alpha_analysis(0) 'Low' >>> alpha_analysis(0.667) 'Tentative' >>> alpha_analysis(0.8) 'High' +>>> alpha_analysis(float('nan')) +'None' >>> pearson_C_analysis(0) 'None' >>> pearson_C_analysis(0.05) @@ -593,6 +611,8 @@ 'Medium' >>> pearson_C_analysis(0.3) 'Strong' +>>> pearson_C_analysis(float('nan')) +'None' >>> PLR_analysis("None") 'None' >>> PLR_analysis(1) @@ -603,6 +623,8 @@ 'Fair' >>> PLR_analysis(11) 'Good' +>>> PLR_analysis(float('nan')) +'None' >>> DP_analysis(0.2) 'Poor' >>> DP_analysis(1.5) @@ -611,6 +633,8 @@ 'Fair' >>> DP_analysis(10) 'Good' +>>> DP_analysis(float('nan')) +'None' >>> AUC_analysis(0.5) 'Poor' >>> AUC_analysis(0.65) @@ -623,6 +647,10 @@ 'Excellent' >>> AUC_analysis(1.0) 'Excellent' +>>> AUC_analysis(float('nan')) +'None' +>>> NLR_analysis(float('nan')) +'None' >>> PC_AC1_calc(1, 1, 1) 'None' >>> assert isclose(PC_AC1_calc({1: 123, 2: 2}, {1: 120, 2: 5}, {1: 125, 2: 125}), 0.05443200000000002, abs_tol=ABS_TOL, rel_tol=REL_TOL) diff --git a/pycm/interpret.py b/pycm/interpret.py index cc348645..7bfd2bbd 100644 --- a/pycm/interpret.py +++ b/pycm/interpret.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- """Interpretation functions.""" +import numpy as np + def Q_analysis(Q: float) -> str: """ @@ -9,6 +11,8 @@ def Q_analysis(Q: float) -> str: :param Q: Yule's Q """ try: + if np.isnan(Q): + return "None" if Q < 0.25: return "Negligible" if Q >= 0.25 and Q < 0.5: @@ -27,6 +31,8 @@ def MCC_analysis(MCC: float) -> str: :param MCC: Matthews correlation coefficient """ try: + if np.isnan(MCC): + return "None" if MCC < 0.3: return "Negligible" if MCC >= 0.3 and MCC < 0.5: @@ -47,6 +53,8 @@ def NLR_analysis(NLR: float) -> str: :param NLR: negative likelihood ratio """ try: + if np.isnan(NLR): + return "None" if NLR < 0.1: return "Good" if NLR >= 0.1 and NLR < 0.2: @@ -65,6 +73,8 @@ def V_analysis(V: float) -> str: :param V: Cramer's V """ try: + if np.isnan(V): + return "None" if V < 0.1: return "Negligible" if V >= 0.1 and V < 0.2: @@ -87,6 +97,8 @@ def PLR_analysis(PLR: float) -> str: :param PLR: positive likelihood ratio """ try: + if np.isnan(PLR): + return "None" if PLR < 1: return "Negligible" if PLR >= 1 and PLR < 5: @@ -105,6 +117,8 @@ def DP_analysis(DP: float) -> str: :param DP: discriminant power """ try: + if np.isnan(DP): + return "None" if DP < 1: return "Poor" if DP >= 1 and DP < 2: @@ -123,6 +137,8 @@ def AUC_analysis(AUC: float) -> str: :param AUC: area under the ROC curve """ try: + if np.isnan(AUC): + return "None" if AUC < 0.6: return "Poor" if AUC >= 0.6 and AUC < 0.7: @@ -143,6 +159,8 @@ def kappa_analysis_cicchetti(kappa: float) -> str: :param kappa: kappa number """ try: + if np.isnan(kappa): + return "None" if kappa < 0.4: return "Poor" if kappa >= 0.4 and kappa < 0.59: @@ -163,6 +181,8 @@ def kappa_analysis_koch(kappa: float) -> str: :param kappa: kappa number """ try: + if np.isnan(kappa): + return "None" if kappa < 0: return "Poor" if kappa >= 0 and kappa < 0.2: @@ -187,6 +207,8 @@ def kappa_analysis_fleiss(kappa: float) -> str: :param kappa: kappa number """ try: + if np.isnan(kappa): + return "None" if kappa < 0.4: return "Poor" if kappa >= 0.4 and kappa < 0.75: @@ -203,6 +225,8 @@ def kappa_analysis_altman(kappa: float) -> str: :param kappa: kappa number """ try: + if np.isnan(kappa): + return "None" if kappa < 0.2: return "Poor" if kappa >= 0.20 and kappa < 0.4: @@ -225,6 +249,8 @@ def lambda_analysis(lambda_: float) -> str: :param lambda_: lambda (A or B) value """ try: + if np.isnan(lambda_): + return "None" if 0 < lambda_ < 0.2: return "Very Weak" if 0.2 <= lambda_ < 0.4: @@ -249,6 +275,8 @@ def alpha_analysis(alpha: float) -> str: :param alpha: Krippendorff's alpha value """ try: + if np.isnan(alpha): + return "None" if alpha < 0.667: return "Low" if 0.667 <= alpha < 0.8: @@ -267,6 +295,8 @@ def pearson_C_analysis(pearson_C: float) -> str: :param pearson_C: Pearson's coefficient value """ try: + if np.isnan(pearson_C): + return "None" if 0 < pearson_C < 0.1: return "Not Appreciable" if 0.1 <= pearson_C < 0.2: