# source:orange/Orange/distance/__init__.py@9759:71c48283a01c

Revision 9759:71c48283a01c, 9.1 KB checked in by anze <anze.staric@…>, 2 years ago (diff)

Fixed failed merge attempt.

Line
1import Orange
2
3from Orange.core import \
4    DistanceMap, \
5    DistanceMapConstructor, \
6    ExamplesDistance as Distance, \
7    ExamplesDistance_Normalized as DistanceNormalized, \
8    ExamplesDistanceConstructor as DistanceConstructor, \
9    ExamplesDistance_Hamming as HammingDistance, \
10    ExamplesDistance_DTW as DTWDistance, \
11    ExamplesDistance_Euclidean as EuclideanDistance, \
12    ExamplesDistance_Manhattan as ManhattanDistance, \
13    ExamplesDistance_Maximal as MaximalDistance, \
14    ExamplesDistance_Relief as ReliefDistance, \
15    ExamplesDistanceConstructor_DTW as DTW, \
16    ExamplesDistanceConstructor_Euclidean as Euclidean, \
17    ExamplesDistanceConstructor_Hamming as Hamming, \
18    ExamplesDistanceConstructor_Manhattan as Manhattan, \
19    ExamplesDistanceConstructor_Maximal as Maximal, \
20    ExamplesDistanceConstructor_Relief as Relief
21
22from Orange import statc
23from Orange.misc import progress_bar_milestones
24
25import numpy
26from numpy import linalg
27
28class PearsonR(DistanceConstructor):
29    """Constructs an instance of :obj:`PearsonRDistance`. Not all the data needs to be given."""
30
31    def __new__(cls, data=None, **argkw):
32        self = DistanceConstructor.__new__(cls, **argkw)
33        self.__dict__.update(argkw)
34        if data:
35            return self.__call__(data)
36        else:
37            return self
38
39    def __call__(self, table):
40        indxs = [i for i, a in enumerate(table.domain.attributes) \
41                 if a.varType==Orange.data.Type.Continuous]
42        return PearsonRDistance(domain=table.domain, indxs=indxs)
43
44class PearsonRDistance(Distance):
45    """
46    `Pearson correlation coefficient
47    <http://en.wikipedia.org/wiki/Pearson_product-moment\
48    _correlation_coefficient>`_
49    """
50
51    def __init__(self, **argkw):
52        self.__dict__.update(argkw)
53
54    def __call__(self, e1, e2):
55        """
56        :param e1: data instances.
57        :param e2: data instances.
58
59        Returns Pearson's disimilarity between e1 and e2,
60        i.e. (1-r)/2 where r is Sprearman's rank coefficient.
61        """
62        X1 = []
63        X2 = []
64        for i in self.indxs:
65            if not(e1[i].isSpecial() or e2[i].isSpecial()):
66                X1.append(float(e1[i]))
67                X2.append(float(e2[i]))
68        if not X1:
69            return 1.0
70        try:
71            return (1.0 - statc.pearsonr(X1, X2)[0]) / 2.
72        except:
73            return 1.0
74
75class SpearmanR(DistanceConstructor):
76    """Constructs an instance of SpearmanR. Not all the data needs to be given."""
77
78    def __new__(cls, data=None, **argkw):
79        self = DistanceConstructor.__new__(cls, **argkw)
80        self.__dict__.update(argkw)
81        if data:
82            return self.__call__(data)
83        else:
84            return self
85
86    def __call__(self, table):
87        indxs = [i for i, a in enumerate(table.domain.attributes) \
88                 if a.varType==Orange.data.Type.Continuous]
89        return SpearmanRDistance(domain=table.domain, indxs=indxs)
90
91class SpearmanRDistance(Distance):
92
93    """`Spearman's rank correlation coefficient
94    <http://en.wikipedia.org/wiki/Spearman%27s_rank_\
95    correlation_coefficient>`_"""
96
97    def __init__(self, **argkw):
98        self.__dict__.update(argkw)
99
100    def __call__(self, e1, e2):
101        """
102        :param e1: data instances.
103        :param e2: data instances.
104
105        Returns Sprearman's disimilarity between e1 and e2,
106        i.e. (1-r)/2 where r is Sprearman's rank coefficient.
107        """
108        X1 = []; X2 = []
109        for i in self.indxs:
110            if not(e1[i].isSpecial() or e2[i].isSpecial()):
111                X1.append(float(e1[i]))
112                X2.append(float(e2[i]))
113        if not X1:
114            return 1.0
115        try:
116            return (1.0 - statc.spearmanr(X1, X2)[0]) / 2.
117        except:
118            return 1.0
119
120class Mahalanobis(DistanceConstructor):
121    """ Construct instance of Mahalanobis. """
122
123    def __new__(cls, data=None, **argkw):
124        self = DistanceConstructor.__new__(cls, **argkw)
125        self.__dict__.update(argkw)
126        if data:
127            return self.__call__(data)
128        else:
129            return self
130
131    # Check attributtes a, b, c
132    def __call__(self, table, a=None, b=None, c=None, **argkw):
133        # Process data
134        dc = Orange.core.DomainContinuizer()
135        dc.classTreatment = Orange.core.DomainContinuizer.Ignore
136        dc.continuousTreatment = Orange.core.DomainContinuizer.NormalizeBySpan
137        dc.multinomialTreatment = Orange.core.DomainContinuizer.NValues
138
139        newdomain = dc(table)
140        newtable = table.translate(newdomain)
141
142        data, cls, _ = newtable.to_numpy()
143
144        covariance_matrix = numpy.cov(data, rowvar=0, bias=1)
145        inverse_covariance_matrix = linalg.pinv(covariance_matrix, rcond=1e-10)
146
147        return MahalanobisDistance(domain=newdomain, icm=inverse_covariance_matrix)
148
149class MahalanobisDistance(Distance):
150    """`Mahalanobis distance
151    <http://en.wikipedia.org/wiki/Mahalanobis_distance>`_"""
152
153    def __init__(self, domain, icm, **argkw):
154        self.domain = domain
155        self.icm = icm
156        self.__dict__.update(argkw)
157
158    def __call__(self, e1, e2):
159        """
160        :param e1: data instances.
161        :param e2: data instances.
162
163        Returns Mahalanobis distance between e1 and e2.
164        """
165        e1 = Orange.data.Instance(self.domain, e1)
166        e2 = Orange.data.Instance(self.domain, e2)
167
168        diff = []
169        for i in range(len(self.domain.attributes)):
170            diff.append(e1[i].value - e2[i].value) if not(e1[i].isSpecial() or e2[i].isSpecial()) else 0.0
171        diff = numpy.asmatrix(diff)
172        res = diff * self.icm * diff.transpose()
173        return res[0,0]**0.5
174
175
176class PearsonRAbsolute(PearsonR):
177    """ Construct an instance of PearsonRAbsolute example distance estimator.
178    """
179    def __call__(self, data):
180        indxs = [i for i, a in enumerate(data.domain.attributes) \
181                 if a.varType==Orange.data.Type.Continuous]
182        return PearsonRAbsoluteDistance(domain=data.domain, indxs=indxs)
183
184
185class PearsonRAbsoluteDistance(PearsonRDistance):
186    """ An example distance estimator using absolute value of Pearson
187    correlation coefficient.
188    """
189    def __call__(self, e1, e2):
190        """
191        Return absolute Pearson's dissimilarity between e1 and e2,
192        i.e.
193
194        .. math:: (1 - abs(r))/2
195
196        where r is Pearson's correlation coefficient.
197        """
198        X1 = []; X2 = []
199        for i in self.indxs:
200            if not(e1[i].isSpecial() or e2[i].isSpecial()):
201                X1.append(float(e1[i]))
202                X2.append(float(e2[i]))
203        if not X1:
204            return 1.0
205        try:
206            return (1.0 - abs(statc.pearsonr(X1, X2)[0]))
207        except:
208            return 1.0
209
210
211class SpearmanRAbsolute(SpearmanR):
212    """ Construct an instance of SpearmanRAbsolute example distance estimator.
213    """
214    def __call__(self, data):
215        indxs = [i for i, a in enumerate(data.domain.attributes) \
216                 if a.varType==Orange.data.Type.Continuous]
217        return SpearmanRAbsoluteDistance(domain=data.domain, indxs=indxs)
218
219
220class SpearmanRAbsoluteDistance(SpearmanRDistance):
221    def __call__(self, e1, e2):
222        """
223        Return absolute Spearman's dissimilarity between e1 and e2,
224        i.e.
225
226        .. math:: (1 - abs(r))/2
227
228        where r is Spearman's correlation coefficient.
229        """
230        X1 = []; X2 = []
231        for i in self.indxs:
232            if not(e1[i].isSpecial() or e2[i].isSpecial()):
233                X1.append(float(e1[i]))
234                X2.append(float(e2[i]))
235        if not X1:
236            return 1.0
237        try:
238            return (1.0 - abs(statc.spearmanr(X1, X2)[0]))
239        except:
240            return 1.0
241
242def _pairs(seq, same = False):
243    """ Return all pairs from elements of `seq`.
244    """
245    seq = list(seq)
246    same = 0 if same else 1
247    for i in range(len(seq)):
248        for j in range(i + same, len(seq)):
249            yield seq[i], seq[j]
250
251def distance_matrix(data, distance_constructor=Euclidean, progress_callback=None):
252    """ A helper function that computes an :obj:`Orange.data.SymMatrix` of all
253    pairwise distances between instances in `data`.
254
255    :param data: A data table
256    :type data: :obj:`Orange.data.Table`
257
258    :param distance_constructor: An DistanceConstructor instance (defaults to :obj:`Euclidean`).
259    :type distance_constructor: :obj:`Orange.distances.DistanceConstructor`
260
261    :param progress_callback: A function (taking one argument) to use for
262        reporting the on the progress.
263    :type progress_callback: function
264
265    :rtype: :class:`Orange.data.SymMatrix`
266
267    """
268    matrix = Orange.data.SymMatrix(len(data))
269    dist = distance_constructor(data)
270
271    iter_count = matrix.dim * (matrix.dim - 1) / 2
272    milestones = progress_bar_milestones(iter_count, 100)
273
274    for count, ((i, ex1), (j, ex2)) in enumerate(_pairs(enumerate(data))):
275        matrix[i, j] = dist(ex1, ex2)
276        if progress_callback and count in milestones:
277            progress_callback(100.0 * count / iter_count)
278
279    return matrix
Note: See TracBrowser for help on using the repository browser.