@@ -610,17 +610,54 @@ def multilabel_confusion_matrix(
610
610
return np .array ([tn , fp , fn , tp ]).T .reshape (- 1 , 2 , 2 )
611
611
612
612
613
+ def _metric_handle_division (* , numerator , denominator , metric , zero_division ):
614
+ """Helper to handle zero-division.
615
+
616
+ Parameters
617
+ ----------
618
+ numerator : numbers.Real
619
+ The numerator of the division.
620
+ denominator : numbers.Real
621
+ The denominator of the division.
622
+ metric : str
623
+ Name of the caller metric function.
624
+ zero_division : {0.0, 1.0, "warn"}
625
+ The strategy to use when encountering 0-denominator.
626
+
627
+ Returns
628
+ -------
629
+ result : numbers.Real
630
+ The resulting of the division
631
+ is_zero_division : bool
632
+ Whether or not we encountered a zero division. This value could be
633
+ required to early return `result` in the "caller" function.
634
+ """
635
+ if np .isclose (denominator , 0 ):
636
+ if zero_division == "warn" :
637
+ msg = f"{ metric } is ill-defined and set to 0.0. Use the `zero_division` "
638
+ "param to control this behavior."
639
+ warnings .warn (msg , UndefinedMetricWarning , stacklevel = 2 )
640
+ return _check_zero_division (zero_division ), True
641
+ return numerator / denominator , False
642
+
643
+
613
644
@validate_params (
614
645
{
615
646
"y1" : ["array-like" ],
616
647
"y2" : ["array-like" ],
617
648
"labels" : ["array-like" , None ],
618
649
"weights" : [StrOptions ({"linear" , "quadratic" }), None ],
619
650
"sample_weight" : ["array-like" , None ],
651
+ "zero_division" : [
652
+ StrOptions ({"warn" }),
653
+ Options (Real , {0.0 , 1.0 , np .nan }),
654
+ ],
620
655
},
621
656
prefer_skip_nested_validation = True ,
622
657
)
623
- def cohen_kappa_score (y1 , y2 , * , labels = None , weights = None , sample_weight = None ):
658
+ def cohen_kappa_score (
659
+ y1 , y2 , * , labels = None , weights = None , sample_weight = None , zero_division = "warn"
660
+ ):
624
661
r"""Compute Cohen's kappa: a statistic that measures inter-annotator agreement.
625
662
626
663
This function computes Cohen's kappa [1]_, a score that expresses the level
@@ -653,12 +690,20 @@ class labels [2]_.
653
690
``y1`` or ``y2`` are used.
654
691
655
692
weights : {'linear', 'quadratic'}, default=None
656
- Weighting type to calculate the score. `None` means no weighted;
657
- "linear" means linear weighted ; "quadratic" means quadratic weighted .
693
+ Weighting type to calculate the score. `None` means not weighted;
694
+ "linear" means linear weighting ; "quadratic" means quadratic weighting .
658
695
659
696
sample_weight : array-like of shape (n_samples,), default=None
660
697
Sample weights.
661
698
699
+ zero_division : {"warn", 0.0, 1.0, np.nan}, default="warn"
700
+ Sets the return value when there is a zero division. This is the case when both
701
+ labelings `y1` and `y2` both exclusively contain the 0 class (e. g.
702
+ `[0, 0, 0, 0]`) (or if both are empty). If set to "warn", returns `0.0`, but a
703
+ warning is also raised.
704
+
705
+ .. versionadded:: 1.6
706
+
662
707
Returns
663
708
-------
664
709
kappa : float
@@ -688,7 +733,18 @@ class labels [2]_.
688
733
n_classes = confusion .shape [0 ]
689
734
sum0 = np .sum (confusion , axis = 0 )
690
735
sum1 = np .sum (confusion , axis = 1 )
691
- expected = np .outer (sum0 , sum1 ) / np .sum (sum0 )
736
+
737
+ numerator = np .outer (sum0 , sum1 )
738
+ denominator = np .sum (sum0 )
739
+ expected , is_zero_division = _metric_handle_division (
740
+ numerator = numerator ,
741
+ denominator = denominator ,
742
+ metric = "cohen_kappa_score()" ,
743
+ zero_division = zero_division ,
744
+ )
745
+
746
+ if is_zero_division :
747
+ return expected
692
748
693
749
if weights is None :
694
750
w_mat = np .ones ([n_classes , n_classes ], dtype = int )
@@ -701,8 +757,18 @@ class labels [2]_.
701
757
else :
702
758
w_mat = (w_mat - w_mat .T ) ** 2
703
759
704
- k = np .sum (w_mat * confusion ) / np .sum (w_mat * expected )
705
- return 1 - k
760
+ numerator = np .sum (w_mat * confusion )
761
+ denominator = np .sum (w_mat * expected )
762
+ score , is_zero_division = _metric_handle_division (
763
+ numerator = numerator ,
764
+ denominator = denominator ,
765
+ metric = "cohen_kappa_score()" ,
766
+ zero_division = zero_division ,
767
+ )
768
+
769
+ if is_zero_division :
770
+ return score
771
+ return 1 - score
706
772
707
773
708
774
@validate_params (
0 commit comments