File size: 4,577 Bytes
246690c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3addf82
 
 
 
246690c
 
 
 
 
 
 
3addf82
 
 
 
 
 
 
 
 
 
 
 
 
 
246690c
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# Copyright 2023 The HuggingFace Evaluate Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Jaccard similarity metric."""

import evaluate
import datasets
from sklearn.metrics import jaccard_score
import numpy as np


_CITATION = """\
@article{jaccard1912distribution,
  title={The distribution of the flora in the alpine zone},
  author={Jaccard, Paul},
  journal={New phytologist},
  volume={11},
  number={2},
  pages={37--50},
  year={1912},
  publisher={Wiley Online Library}
}
"""

_DESCRIPTION = """\
Jaccard similarity is a statistic used for gauging the similarity and diversity of sample sets. 
The Jaccard coefficient measures similarity between finite sample sets, and is defined as the size of 
the intersection divided by the size of the union of the sample sets. This implementation uses 
scikit-learn's jaccard_score function.
"""

_KWARGS_DESCRIPTION = """
Calculates the Jaccard similarity between predictions and references using scikit-learn.
Args:
    predictions: 1d array-like, or label indicator array / sparse matrix
        Predicted labels, as returned by a classifier.
    references: 1d array-like, or label indicator array / sparse matrix
        Ground truth (correct) labels.
    labels: array-like of shape (n_classes,), default=None
        The set of labels to include when average != 'binary', and their order if average is None.
    pos_label: int, float, bool or str, default=1
        The class to report if average='binary' and the data is binary.
    average: {'micro', 'macro', 'samples', 'weighted', 'binary'} or None, default='binary'
        This parameter is required for multiclass/multilabel targets.
    sample_weight: array-like of shape (n_samples,), default=None
        Sample weights.
    zero_division: "warn", {0.0, 1.0}, default="warn"
        Sets the value to return when there is a zero division.
Returns:
    jaccard_similarity: float or ndarray of shape (n_unique_labels,)
        Jaccard similarity score.
Examples:
    >>> jaccard_metric = evaluate.load("jaccard_similarity")
    >>> predictions = [0, 2, 1, 3]
    >>> references = [0, 1, 2, 3]
    >>> results = jaccard_metric.compute(predictions=predictions, references=references, average='macro')
    >>> print(results)
    {'jaccard_similarity': 0.5}
"""


@evaluate.utils.file_utils.add_start_docstrings(_DESCRIPTION, _KWARGS_DESCRIPTION)
class JaccardSimilarity(evaluate.Metric):
    def _info(self):
        return evaluate.MetricInfo(
            module_type="metric",
            description=_DESCRIPTION,
            citation=_CITATION,
            inputs_description=_KWARGS_DESCRIPTION,
            features=datasets.Features({
                "predictions": datasets.Sequence(datasets.Value("int32")),
                "references": datasets.Sequence(datasets.Value("int32")),
            }),
            reference_urls=[
                "https://scikit-learn.org/stable/modules/generated/sklearn.metrics.jaccard_score.html",
                "https://en.wikipedia.org/wiki/Jaccard_index"
            ],
        )

    def _compute(self, predictions, references, labels=None, pos_label=1, average='binary', sample_weight=None, zero_division='warn'):
        predictions = np.array(predictions)
        references = np.array(references)

        # Handle different input shapes
        if predictions.ndim == 1 and references.ndim == 1:
            # Binary or multiclass case
            pass
        elif predictions.ndim == 2 and references.ndim == 2:
            # Multilabel case
            if average == 'binary':
                average = 'micro'  # 'binary' doesn't make sense for multilabel
        else:
            raise ValueError("Predictions and references should have the same shape")

        return {
            "jaccard_similarity": jaccard_score(
                references, 
                predictions, 
                labels=labels, 
                pos_label=pos_label, 
                average=average, 
                sample_weight=sample_weight, 
                zero_division=zero_division
            )
        }