Skip to content

Commit

Permalink
feat : distance method added #349 #350
Browse files Browse the repository at this point in the history
  • Loading branch information
sepandhaghighi committed Dec 29, 2022
1 parent 48f5d92 commit 06f8d0e
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
129 changes: 129 additions & 0 deletions pycm/pycm_distance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# -*- coding: utf-8 -*-
"""Distance/Similarity functions."""
from __future__ import division
from enum import Enum
import math

class DistanceType(Enum):
"""
Distance metric type class.
>>> pycm.DistanceType.AMPLE
"""

AMPLE = "AMPLE"
Anderberg = "Anderberg"
AndresMarzoDelta = "AndresMarzoDelta"
BaroniUrbaniBuserI = "BaroniUrbaniBuserI"
BaroniUrbaniBuserII = "BaroniUrbaniBuserII"

def AMPLE_calc(TP, FP, FN, TN):
"""
Calculate AMPLE.
:param TP: true positive
:type TP: int
:param TN: true negative
:type TN: int
:param FP: false positive
:type FP: int
:param FN: false negative
:type FN: int
:return: AMPLE as float
"""
try:
part1 = TP/(TP + FP)
part2 = FN/(FN + TN)
return abs(part1 - part2)
except Exception:
return "None"

def Anderberg_calc(TP, FP, FN, TN):
"""
Calculate Anderberg's D.
:param TP: true positive
:type TP: int
:param TN: true negative
:type TN: int
:param FP: false positive
:type FP: int
:param FN: false negative
:type FN: int
:return: Anderberg's D as float
"""
try:
part1 = max(TP, FP) + max(FN, TN) + max(TP, FN) + max(FP, TN)
part2 = max(TP + FP, FP + TN) + max(TP + FP, FN + TN)
n = TP + FP + FN + TN
return (part1 - part2) / (2 * n)
except Exception:
return "None"


def AndresMarzoDelta_calc(TP, FP, FN, TN):
"""
Calculate Andres & Marzo's Delta.
:param TP: true positive
:type TP: int
:param TN: true negative
:type TN: int
:param FP: false positive
:type FP: int
:param FN: false negative
:type FN: int
:return: Andres & Marzo's Delta as float
"""
try:
part1 = TP + TN - 2 * math.sqrt(FP * FN)
n = TP + FP + FN + TN
return part1 / n
except Exception:
return "None"

def BaroniUrbaniBuserI_calc(TP, FP, FN, TN):
"""
Calculate Baroni-Urbani & Buser I.
:param TP: true positive
:type TP: int
:param TN: true negative
:type TN: int
:param FP: false positive
:type FP: int
:param FN: false negative
:type FN: int
:return: Baroni-Urbani & Buser I as float
"""
try:
part1 = math.sqrt(TP * TN) + TP
part2 = part1 + FP + FN
return part1 / part2
except Exception:
return "None"

def BaroniUrbaniBuserII_calc(TP, FP, FN, TN):
"""
Calculate Baroni-Urbani & Buser II.
:param TP: true positive
:type TP: int
:param TN: true negative
:type TN: int
:param FP: false positive
:type FP: int
:param FN: false negative
:type FN: int
:return: Baroni-Urbani & Buser II as float
"""
try:
part1 = math.sqrt(TP * TN) + TP - FP - FN
part2 = math.sqrt(TP * TN) + TP + FP + FN
return part1 / part2
except Exception:
return "None"



DISTANCE_MAPPER = {DistanceType.AMPLE: AMPLE_calc, DistanceType.Anderberg: Anderberg_calc, DistanceType.AndresMarzoDelta: AndresMarzoDelta_calc, DistanceType.BaroniUrbaniBuserI:
BaroniUrbaniBuserI_calc, DistanceType.BaroniUrbaniBuserII: BaroniUrbaniBuserII_calc}
16 changes: 16 additions & 0 deletions pycm/pycm_obj.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .pycm_handler import __obj_assign_handler__, __obj_file_handler__, __obj_matrix_handler__, __obj_vector_handler__, __obj_array_handler__
from .pycm_class_func import F_calc, IBA_calc, TI_calc, NB_calc, sensitivity_index_calc
from .pycm_overall_func import weighted_kappa_calc, weighted_alpha_calc, alpha2_calc, brier_score_calc
from .pycm_distance import DistanceType, DISTANCE_MAPPER
from .pycm_output import *
from .pycm_util import *
from .pycm_param import *
Expand Down Expand Up @@ -591,6 +592,21 @@ def NB(self, w=1):
except Exception:
return {}

def distance(self, metric):
"""
Calculate distance/similarity for all classes.
:param metric: metric
:type metric: DistanceType
:return: result as float
"""
distance_dict = {}
if not isinstance(metric, DistanceType):
pycmMatrixError(DISTANCE_METRIC_TYPE_ERROR)
for i in self.classes:
distance_dict[i] = DISTANCE_MAPPER[metric](TP = self.TP[i], FP = self.FP[i], FN = self.FN[i], TN = self.TN[i])
return distance_dict

def CI(
self,
param,
Expand Down
2 changes: 2 additions & 0 deletions pycm/pycm_param.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@

CURVE_NONE_WARNING = "The curve axes contain non-numerical value(s)."

DISTANCE_METRIC_TYPE_ERROR = "The metric type must be DistanceType"

CLASS_NUMBER_THRESHOLD = 10

BALANCE_RATIO_THRESHOLD = 3
Expand Down

0 comments on commit 06f8d0e

Please sign in to comment.