source: orange-bioinformatics/Orange/bioinformatics/widgets/prototypes/OWDataDistance.py @ 1625:cefeb35cbfc9

Revision 1625:cefeb35cbfc9, 11.2 KB checked in by mitar, 2 years ago (diff)

Moving files around.

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