comparison python/utils.py @ 370:97e8fa0ee9a1

work in progress for complete alignment
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Mon, 15 Jul 2013 18:18:44 -0400
parents 027e254f0b53
children 924e38c9f70e
comparison
equal deleted inserted replaced
369:027e254f0b53 370:97e8fa0ee9a1
136 for i in xrange(len(ref[0])): 136 for i in xrange(len(ref[0])):
137 print('{0}-{1} & {2:0.3} & {3:0.3} \\\\'.format(self.categories[i],self.categories[i+1],ref[1][i], ref[0][i])) 137 print('{0}-{1} & {2:0.3} & {3:0.3} \\\\'.format(self.categories[i],self.categories[i+1],ref[1][i], ref[0][i]))
138 138
139 139
140 ######################### 140 #########################
141 # sequence section
142 #########################
143
144 class LCSS:
145 '''Class that keeps the LCSS parameters
146 and puts together the various computations'''
147 def __init__(self, similarityFunc, delta = float('inf'), aligned = False, lengthFunc = min):
148 self.similarityFunc = similarityFunc
149 self.aligned = aligned
150 self.delta = delta
151 self.lengthFunc = lengthFunc
152
153 def similarities(self, l1, l2):
154 from numpy import zeros, int as npint
155 n1 = len(l1)
156 n2 = len(l2)
157 self.similarityTable = zeros((n1+1,n2+1), dtype = npint)
158 for i in xrange(1,n1+1):
159 for j in xrange(max(1,i-self.delta),min(n2+1,i+self.delta+1)):
160 if self.similarityFunc(l1[i-1], l2[j-1]):
161 self.similarityTable[i,j] = self.similarityTable[i-1,j-1]+1
162 else:
163 self.similarityTable[i,j] = max(self.similarityTable[i-1,j], self.similarityTable[i,j-1])
164
165 def subSequence(self, i, j):
166 '''Returns the subsequence of two sequences
167 http://en.wikipedia.org/wiki/Longest_common_subsequence_problem'''
168 if i == 0 or j == 0:
169 return []
170 elif self.similarityTable[i][j] == self.similarityTable[i][j-1]:
171 return self.subSequence(i, j-1)
172 elif self.similarityTable[i][j] == self.similarityTable[i-1][j]:
173 return self.subSequence(i-1, j)
174 else:
175 return self.subSequence(i-1, j-1) + [(i-1,j-1)]
176
177 def computeLCSS(self, l1, l2, computeSubSequence = False):
178 '''returns the longest common subsequence similarity
179 based on the threshold on distance between two elements of lists l1, l2
180 similarityFunc returns True or False whether the two points are considered similar
181
182 eg distance(p1, p2) < epsilon
183 '''
184 from numpy import argmax
185 self.similarities(l1, l2)
186 imax = argmax(self.similarityTable[:,-1])
187 jmax = argmax(self.similarityTable[-1,:])
188 if computeSubSequence:
189 if self.similarityTable[imax, -1] > self.similarityTable[-1, jmax]:
190 lcss = self.similarityTable[imax, -1]
191 self.subSequenceIndices = self.subSequence(imax, len(l2))
192 else:
193 lcss = self.similarityTable[imax, -1]
194 self.subSequenceIndices = self.subSequence(len(l1), jmax)
195 return lcss
196 else:
197 return max(self.similarityTable[imax, -1], self.similarityTable[-1, jmax])
198
199 def compute(self, _l1, _l2, computeSubSequence = False):
200 '''returns the best matching if using a finite delta by shiftinig the series alignments'''
201 if self.aligned:
202 if len(_l2) < len(_l1): # l1 is the shortest
203 l1 = _l2
204 l2 = _l1
205 else:
206 l1 = _l1
207 l2 = _l2
208 n1 = len(l1)
209 n2 = len(l2)
210 # for i in xrange(min(delta,n1), max(n1+n2-delta, n2+1)): # i is the alignment of the end of l1 in l2
211 # print l1[min(-i-1,n1):] # min(n1+n2-i,n1)
212 # print l2[max(0,i-n1):]
213 # print LCSS(l1[min(-i-1,n1):], l2[max(0,i-n1):], similarityFunc, delta)
214 lcss = [self.computeLCSS(l1[min(-i-1,n1):], l2[max(0,i-n1):]) for i in xrange(min(self.delta,n1), max(n1+n2-self.delta, n2+1))]
215 return max(lcss)
216 else:
217 return self.computeLCSS(_l1, _l2, computeSubSequence)
218
219 def get(self, l1, l2, computeSubSequence = False):
220 '''get methods are to be shadowed in child classes '''
221 return self.compute(l1, l2, computeSubSequence)
222
223 def computeAlignement(self):
224 from numpy import mean
225 return mean([j-i for i,j in self.subSequenceIndices])
226
227 def computeNormalized(self, l1, l2):
228 ''' compute the normalized LCSS
229 ie, the LCSS divided by the min or mean of the indicator lengths (using lengthFunc)
230 lengthFunc = lambda x,y:float(x,y)/2'''
231 return float(self.compute(l1, l2))/self.lengthFunc(len(l1), len(l2))
232
233 def getNormalized(self, l1, l2):
234 return self.computeNormalized(l1, l2)
235
236 def computeDistance(self, l1, l2):
237 ''' compute the LCSS distance'''
238 return 1-self.computeNormalized(l1, l2)
239
240 def getDistance(self, l1, l2):
241 return self.computeDistance(l1, l2)
242
243 #########################
244 # maths section 141 # maths section
245 ######################### 142 #########################
143
144 def argMaxDict(d):
145 return max(d.iterkeys(), key=(lambda key: d[key]))
246 146
247 def framesToTime(nFrames, frameRate, initialTime = (0.,0.,0.)): 147 def framesToTime(nFrames, frameRate, initialTime = (0.,0.,0.)):
248 'returns hour, minutes and seconds' 148 'returns hour, minutes and seconds'
249 from math import floor 149 from math import floor
250 from datetime import time 150 from datetime import time
303 xx = arange(min(x), max(x),(max(x)-min(x))/1000) 203 xx = arange(min(x), max(x),(max(x)-min(x))/1000)
304 plot(xx, [poly(z) for z in xx]) 204 plot(xx, [poly(z) for z in xx])
305 return coef 205 return coef
306 206
307 ######################### 207 #########################
208 # sequence section
209 #########################
210
211 class LCSS:
212 '''Class that keeps the LCSS parameters
213 and puts together the various computations'''
214 def __init__(self, similarityFunc, delta = float('inf'), aligned = False, lengthFunc = min):
215 self.similarityFunc = similarityFunc
216 self.aligned = aligned
217 self.delta = delta
218 self.lengthFunc = lengthFunc
219 self.alignmentShift = 0
220
221 def similarities(self, l1, l2):
222 from numpy import zeros, int as npint
223 n1 = len(l1)
224 n2 = len(l2)
225 self.similarityTable = zeros((n1+1,n2+1), dtype = npint)
226 for i in xrange(1,n1+1):
227 for j in xrange(max(1,i-self.delta),min(n2+1,i+self.delta+1)):
228 if self.similarityFunc(l1[i-1], l2[j-1]):
229 self.similarityTable[i,j] = self.similarityTable[i-1,j-1]+1
230 else:
231 self.similarityTable[i,j] = max(self.similarityTable[i-1,j], self.similarityTable[i,j-1])
232
233 def subSequence(self, i, j):
234 '''Returns the subsequence of two sequences
235 http://en.wikipedia.org/wiki/Longest_common_subsequence_problem'''
236 if i == 0 or j == 0:
237 return []
238 elif self.similarityTable[i][j] == self.similarityTable[i][j-1]:
239 return self.subSequence(i, j-1)
240 elif self.similarityTable[i][j] == self.similarityTable[i-1][j]:
241 return self.subSequence(i-1, j)
242 else:
243 return self.subSequence(i-1, j-1) + [(i-1,j-1)]
244
245 def computeLCSS(self, l1, l2, computeSubSequence = False):
246 '''returns the longest common subsequence similarity
247 based on the threshold on distance between two elements of lists l1, l2
248 similarityFunc returns True or False whether the two points are considered similar
249
250 eg distance(p1, p2) < epsilon
251 '''
252 from numpy import argmax
253 self.similarities(l1, l2)
254 imax = argmax(self.similarityTable[:,-1])
255 jmax = argmax(self.similarityTable[-1,:])
256 if computeSubSequence:
257 if self.similarityTable[imax, -1] > self.similarityTable[-1, jmax]:
258 self.similarityTable = self.similarityTable[:imax+1, :]
259 self.subSequenceIndices = self.subSequence(imax, len(l2))
260 else:
261 self.similarityTable = self.similarityTable[:, :jmax+1]
262 self.subSequenceIndices = self.subSequence(len(l1), jmax)
263 return self.similarityTable[-1,-1]
264 else:
265 return max(self.similarityTable[imax, -1], self.similarityTable[-1, jmax])
266
267 def _compute(self, _l1, _l2, computeSubSequence = False):
268 '''returns the best matching if using a finite delta by shiftinig the series alignments'''
269 if self.aligned:
270 from numpy import argmax
271 if len(_l2) < len(_l1): # l1 is the shortest
272 l1 = _l2
273 l2 = _l1
274 else:
275 l1 = _l1
276 l2 = _l2
277 n1 = len(l1)
278 n2 = len(l2)
279 # for i in xrange(min(delta,n1), max(n1+n2-delta, n2+1)): # i is the alignment of the end of l1 in l2
280 # print l1[min(-i-1,n1):] # min(n1+n2-i,n1)
281 # print l2[max(0,i-n1):]
282 # print LCSS(l1[min(-i-1,n1):], l2[max(0,i-n1):], similarityFunc, delta)
283 lcssValues = {}
284 similarityTables = {}
285 for i in xrange(min(self.delta,n1), max(n1+n2-self.delta, n2+1), max(1,self.delta)):
286 print l1[min(-i-1,n1):] # min(n1+n2-i,n1)
287 print l2[max(0,i-n1):]
288 lcssValues[i] = self.computeLCSS(l1[min(-i-1,n1):], l2[max(0,i-n1):])
289 print i, lcssValues[i]
290 similarityTables[i] = self.similarityTable
291 imax = argMaxDict(lcssValues)
292 self.similarityTable = similarityTables[imax]
293 self.subSequenceIndices = self.subSequence(self.similarityTable.shape[0]-1, self.similarityTable.shape[1]-1)
294 self.alignmentShift = max(0,imax-n1)-min(-imax-1,n1)
295 return lcssValues[imax]
296 else:
297 return self.computeLCSS(_l1, _l2, computeSubSequence)
298
299 def compute(self, l1, l2, computeSubSequence = False):
300 '''get methods are to be shadowed in child classes '''
301 return self._compute(l1, l2, computeSubSequence)
302
303 def computeAlignement(self):
304 from numpy import mean
305 return mean([j-i for i,j in self.subSequenceIndices])+self.alignmentShift
306
307 def _computeNormalized(self, l1, l2):
308 ''' compute the normalized LCSS
309 ie, the LCSS divided by the min or mean of the indicator lengths (using lengthFunc)
310 lengthFunc = lambda x,y:float(x,y)/2'''
311 return float(self.compute(l1, l2))/self.lengthFunc(len(l1), len(l2))
312
313 def computeNormalized(self, l1, l2):
314 return self._computeNormalized(l1, l2)
315
316 def _computeDistance(self, l1, l2):
317 ''' compute the LCSS distance'''
318 return 1-self.computeNormalized(l1, l2)
319
320 def computeDistance(self, l1, l2):
321 return self._computeDistance(l1, l2)
322
323 #########################
308 # plotting section 324 # plotting section
309 ######################### 325 #########################
310 326
311 def plotPolygon(poly, options = ''): 327 def plotPolygon(poly, options = ''):
312 'Plots shapely polygon poly' 328 'Plots shapely polygon poly'