source: orange-bioinformatics/_bioinformatics/widgets/prototypes/OWDataDistance.py @ 1636:10d234fdadb9

Revision 1636:10d234fdadb9, 11.4 KB checked in by mitar, 2 years ago (diff)

Restructuring because we will not be using namespaces.

Line 
1## Automatically adapted for numpy.oldnumeric Oct 04, 2007 by
2
3"""
4<name>Data Distance</name>
5<description>Computes a distance matrix between data files.</description>
6<icon>icons/ChipDistance.png</icon>
7<priority>1160</priority>
8<contact>Peter Juvan (peter.juvan@fri.uni-lj.si)</contact>
9"""
10
11from __future__ import absolute_import
12
13from qt import *
14from qtcanvas import *
15
16import numpy.oldnumeric as Numeric, numpy.oldnumeric.ma as MA
17
18import orange, statc
19from Orange.OrangeWidgets import OWGUI
20from Orange.OrangeWidgets.OWWidget import *
21
22from .OWDataFiles import DataFiles
23
24import warnings
25warnings.filterwarnings("ignore", "'strain'", orange.AttributeWarning)
26warnings.filterwarnings("ignore", "'dirname'", orange.AttributeWarning)
27
28##############################################################################
29# main class
30
31class OWDataDistance(OWWidget):
32    settingsList = ["Metrics"]
33
34    def __init__(self, parent=None, signalManager = None):
35        OWWidget.__init__(self, parent, signalManager, 'Data Distance') 
36       
37        self.inputs = [("Structured Data", DataFiles, self.chipdata)]
38        self.outputs = [("Distance Matrix", orange.SymMatrix)]
39
40        self.Metrics = 0
41        self.loadSettings()
42        self.data = []
43##        self.metrics = [("Euclidean", orange.ExamplesDistanceConstructor_Euclidean),
44##            ("Manhattan", orange.ExamplesDistanceConstructor_Manhattan),
45##            ("Hamming", orange.ExamplesDistanceConstructor_Hamming)]
46        self.metrics = [("Manhattan", distManhattan), ("Euclidean", distEuclidean), ("1 - (Pearson correlation coefficient)", distPearson), ("1 - (Spearman rank correlation coefficient)", distSpearman)]
47
48        # GUI
49        self.mainArea.setFixedWidth(0)
50        # Info box
51        box = QVGroupBox("Info", self.controlArea)
52        self.infoa = QLabel('No data on input.', box)
53        self.infob = QLabel('', box)
54        OWGUI.separator(self.controlArea)
55
56        # Distance metrics selection
57        items = [x[0] for x in self.metrics]
58        OWGUI.comboBox(self.controlArea, self, "Metrics", box="Distance Metrics", items=items,
59            tooltip="Metrics to measure distance between data sets.",
60            callback=self.onMetricsChange)
61
62        self.resize(384, 138)
63       
64
65    ##########################################################################
66    # handling of input/output signals
67
68##    def computeDistance(self, d1, d2, dist):
69##        """employs orange to compute distances (slower)
70##        """
71##        d = 0
72##        for i in range(len(d1)):
73##            d += dist(d1[i], d2[i])
74##        d = d / len(d1)
75##        return d
76
77    def computeDistance(self, d1, d2):
78        """employs MA to cumpute distances (faster)
79        """
80        return dist(d1.toNumpyMA("a")[0], d2.toNumpyMA("a")[0])
81
82
83    def computeMatrix(self):
84        if not self.data:
85            self.send("Distance Matrix", None)
86            return
87##        if self.Metrics == 0: # bug in orange, correct (remove normalize) once it is fixed
88##            dist = self.metrics[self.Metrics][1](self.data[0], normalize=0)
89##        else:
90##            dist = self.metrics[self.Metrics][1](self.data[0])           
91        matrix = orange.SymMatrix(len(self.data))
92        matrix.setattr('items', self.data)
93        self.progressBarInit()
94        pbStep = 100./(len(self.data)**2/2. - len(self.data)/2.)
95        for i in range(len(self.data)-1):
96            for j in range(i+1, len(self.data)):
97##                matrix[i, j] = self.computeDistance(self.data[i], self.data[j], dist)
98                matrix[i, j] = self.metrics[self.Metrics][1](MA.ravel(self.data[i].toNumpyMA("a")[0]), MA.ravel(self.data[j].toNumpyMA("a")[0]))
99                self.progressBarAdvance(pbStep)
100        self.progressBarFinished()
101        self.send("Distance Matrix", matrix)
102
103
104    def chipdata(self, data):
105        self.data = []
106        if data:
107            self.infob.setText("")
108            numFiles = reduce(lambda a,b: a+len(b[1]), data, 0)
109            lenSD = len(data)
110            self.infoa.setText("%d set%s, total of %d data file%s." % (lenSD, ["","s"][lenSD!=1], numFiles, ["","s"][numFiles!=1]))
111            numExamplesList = []
112            # construct a list of ExampleTable lengths and a list of attribute names
113            for (name, etList) in data:
114                for et in etList:
115                    setattr(et,"dirname",name)
116                    setattr(et,"strain",name)
117                    self.data.append(et)
118                    numExamplesList.append(len(et))
119            if len(self.data)>1:
120                # test that files contain the same attributes and equal number of examples
121                attrSorted = self.data[0].domain.attributes
122                attrSorted.sort()
123                numEx = len(self.data[0])
124                for et in self.data[1:]:
125                    attrSorted2 = et.domain.attributes
126                    attrSorted2.sort()
127                    if map(lambda x: x.name, attrSorted) != map(lambda x: x.name, attrSorted2):
128                        self.data = []
129                        self.infob.setText("Error: data files contain different attributes, aborting distance computation.")
130                        return
131                    if len(et) != numEx:
132                        self.data = []
133                        self.infob.setText("Error: data files contain unequal number of examples, aborting distance computation.")
134                        return
135                # compute distances
136                pb = OWGUI.ProgressBar(self, iterations=len(self.data))
137                self.computeMatrix()
138                pb.finish()
139
140            else:
141                self.data = []
142                self.infob.setText('Error: not enough data, aborting distance computation.')
143        else:
144            self.infoa.setText('No data on input.')
145
146
147    def onMetricsChange(self):
148        if self.data and len(self.data)>1:
149            self.computeMatrix()
150
151
152
153###########################################################################
154# Distance Metrics
155###########################################################################
156
157def distManhattan(x,y):
158    """normalized Manhattan distance
159    """
160    x = MA.asarray(x)
161    y = MA.asarray(y)
162    assert MA.rank(x) == MA.rank(y) == 1
163    sumWeights = MA.add.reduce(MA.logical_not(MA.logical_or(MA.getmaskarray(x), MA.getmaskarray(y))).astype(Numeric.Float))
164    return MA.add.reduce(MA.absolute(x-y)) / sumWeights
165
166
167def distManhattanW(x,y,w):
168    """normalized weighted Manhattan distance
169    """
170    x = MA.asarray(x)
171    y = MA.asarray(y)
172    w = MA.asarray(w)
173    assert MA.rank(x) == MA.rank(y) == MA.rank(w) == 1
174    sumWeights = MA.add.reduce(w * MA.logical_not(MA.logical_or(MA.getmaskarray(x), MA.getmaskarray(y))).astype(Numeric.Float))
175    return MA.add.reduce(w * MA.absolute(x-y)) / sumWeights
176
177
178def distEuclidean(x,y):
179    """normalized euclidean distance
180    """
181    x = MA.asarray(x)
182    y = MA.asarray(y)
183    assert MA.rank(x) == MA.rank(y) == 1
184    sumWeights = MA.add.reduce(MA.logical_not(MA.logical_or(MA.getmaskarray(x), MA.getmaskarray(y))).astype(Numeric.Float))
185    return MA.sqrt(MA.add.reduce((x-y)**2) / sumWeights)
186
187
188def distEuclideanW(x,y,w):
189    """normalized weighted euclidean distance
190    """
191    x = MA.asarray(x)
192    y = MA.asarray(y)
193    w = MA.asarray(w)
194    assert MA.rank(x) == MA.rank(y) == MA.rank(w) == 1
195    sumWeights = MA.add.reduce(w * MA.logical_not(MA.logical_or(MA.getmaskarray(x), MA.getmaskarray(y))).astype(Numeric.Float))
196    return MA.sqrt(MA.add.reduce(w * (x-y)**2) / sumWeights)
197
198
199def distPearson(x,y):
200    """distance corresponding to 1 - pearson's correlation coefficient for arrays x,y
201    returns distance: 1 - pearson_r
202    """
203    x = MA.asarray(x)
204    y = MA.asarray(y)
205    assert MA.rank(x) == MA.rank(y) == 1
206    cond = MA.logical_not(MA.logical_or(MA.getmaskarray(x), MA.getmaskarray(y)))
207    return 1 - statc.pearsonr(MA.compress(cond,x).tolist(), MA.compress(cond,y).tolist())[0]
208
209
210def distPearsonW(x,y,w):
211    """weighted distance corresponding to 1 - pearson's correlation coefficient for arrays x,y and weights w
212    returns distance: 1 - pearson_r
213    """
214    #TINY = 1.0e-20
215    # ones for non-masked places at x,y and w
216    x = MA.asarray(x)
217    y = MA.asarray(y)
218    w = MA.asarray(w)
219    assert MA.rank(x) == MA.rank(y) == MA.rank(w) == 1
220    mask = MA.logical_or(MA.logical_or(MA.getmaskarray(x), MA.getmaskarray(y)), MA.getmaskarray(w))
221    # set mask to w that is equal to the mask from x, y and w
222    w = MA.masked_array(w, mask=mask)
223    n_w_mean = MA.add.reduce(w)    # n * mean(w)
224    x_w = x*w       # x * w
225    y_w = y*w       # y * w
226    x_wmean = MA.divide(MA.add.reduce(x_w), n_w_mean)     # weighted_mean(x)
227    y_wmean = MA.divide(MA.add.reduce(y_w), n_w_mean)     # weighted_mean(x)   
228    r_num = MA.add.reduce(x*y*w) - n_w_mean*x_wmean*y_wmean
229    r_den = MA.sqrt((MA.add.reduce(x_w*x) - n_w_mean*x_wmean**2) * (MA.add.reduce(y_w*y) - n_w_mean*y_wmean**2))
230    return 1 - MA.divide(r_num, r_den)
231
232
233def distSpearman(x,y):
234    """distance corresponding to 1 - spearman's correlation coefficient for arrays x,y
235    returns distance: 1 - spearman_r
236    """
237    x = MA.asarray(x)
238    y = MA.asarray(y)
239    assert MA.rank(x) == MA.rank(y) == 1
240    cond = MA.logical_not(MA.logical_or(MA.getmaskarray(x), MA.getmaskarray(y)))
241    return 1 - statc.spearmanr(MA.compress(cond,x).tolist(), MA.compress(cond,y).tolist())[0]
242
243def distSpearmanW(x,y,w):
244    """weighted distance corresponding to 1 - spearman's correlation coefficient for arrays x,y and weights w
245    returns distance: 1 - spearman_r
246    """
247    distSpearFunc = _distSpearmanW_NU
248    for var in (x,y,w):
249        if type(var) == MA.array and MA.count(var) != Numeric.multiply.reduce(var.shape):
250            distSpearFunc = _distSpearmanW_MA
251            break
252    return distSpearFunc(x,y,w)
253
254
255def _distSpearmanW_NU(x,y,w):
256    """x,y,w must be Numeric
257    """
258    x = Numeric.asarray(x)
259    y = Numeric.asarray(y)
260    w = Numeric.asarray(w)
261    assert Numeric.rank(x) == Numeric.rank(y) == Numeric.rank(w) == 1
262    rankx = Numeric.array(statc.rankdata(x.tolist()))
263    ranky = Numeric.array(statc.rankdata(y.tolist()))
264    return distPearsonW(rankx,ranky,w)
265
266
267def _distSpearmanW_MA(x,y,w):
268    """if any of x,y,w is a MA array containing masked values
269    """
270    x = MA.asarray(x)
271    y = MA.asarray(y)
272    w = MA.asarray(w)
273    assert MA.rank(x) == MA.rank(y) == MA.rank(w) == 1
274    cond = MA.logical_not(MA.logical_or(MA.logical_or(MA.getmaskarray(x), MA.getmaskarray(y)), MA.getmaskarray(w))) 
275    # with MA use compress before tolist() !
276    rankx = Numeric.array(statc.rankdata(MA.compress(cond, x).tolist()))
277    ranky = Numeric.array(statc.rankdata(MA.compress(cond, y).tolist()))
278    return distPearsonW(rankx,ranky,MA.compress(cond,w))
279
280###########################################################################
281# testing
282###########################################################################
283
284if __name__=="__main__":
285    from . import OWDataFiles
286    from Orange.orng import orngSignalManager
287    signalManager = orngSignalManager.SignalManager(0)
288    a=QApplication(sys.argv)
289    ow=OWDataDistance(signalManager = signalManager)
290    signalManager.addWidget(ow)
291    a.setMainWidget(ow)
292    ow.show()
293    ds = OWDataFiles.OWDataFiles(signalManager = signalManager)
294    signalManager.addWidget(ds)
295    ds.loadData("potato.sub100")
296    signalManager.setFreeze(1)
297    signalManager.addLink(ds, ow, 'Structured Data', 'Structured Data', 1)
298    signalManager.setFreeze(0)
299    a.exec_loop()
300    ow.saveSettings()
Note: See TracBrowser for help on using the repository browser.