Mercurial > hg > nsaunier > traffic-intelligence
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' |
