2012-01-07 10 views
11

Ho dato un'occhiata a diverse dicussioni su diversi siti e nessuno di loro mi ha dato una soluzione. Questo pezzo di codice richiede più di 5 secondi per eseguire:Come velocizzare il loop python

for i in xrange(100000000): 
    pass 

sto lavorando su un problema di ottimizzazione intero e devo usare un O (n log n) algoritmo edit: un O (n²/4) algoritmo, dove n sta per tutti gli elementi della matrice, cioè, nel seguente codice, n * m = 10000. Quindi, per una matrice 100 * 100 con 10000 elementi, il risultato sarà quasi 25000000 iterazioni.. Il suo codice può essere riassunta in questo modo:

m = 100 
n = 100 
for i in xrange(m): 
    for j in xrange(n): 
    for i2 in xrange(i + 1, m): 
     for j2 in xrange(j + 1, n): 
     if myarray[i][j] == myarray[i2][j2] and myarray[i2][j] == myarray[i][j2]: 
      return [i, j], [i2, j2] 

Devo rinunciare con Python e tornare a Java o C?

Io lavoro con Python 2.7 e Psyco non è disponibile. PyPy non supporta Tkinter out of the box e sto usando Tkinter.

Quindi, migliorerebbero la velocità di loop? Ci sono altre soluzioni?

+0

hai provato a implementare questo con gli array numpy se è possibile? – joaquin

+1

PyPy certamente accelera tali loop. – delnan

+3

Puoi accelerare i tuoi loop tutto quello che vuoi, il codice sopra non è O (n log n). –

risposta

3

Mi dispiace dirtelo, ma non si tratta di ottimizzazione. Indipendentemente dalla lingua o dall'implementazione scelta, questo algoritmo non è O(n*log n) nel caso peggiore e medio. Si consiglia di leggere su how the Big-O notation works e sviluppare un algoritmo migliore.

+0

Ok è O (n²/4), non O (n log n), ma non ci sono altri algoritmi e questo è un problema di ottimizzazione (vedi modifica nel post principale per i dettagli). –

9

È ancora possibile utilizzare la notazione Python e avere la velocità di C, utilizzando il progetto Cython. Un primo passo sarebbe quello di convertire il ciclo in ciclo C: è fatta automaticamente digitando tutte le variabili utilizzate nel ciclo:

cdef int m = 100 
cdef int n = 100 
cdef int i, j, i2, j2 
for i in xrange(m): 
    for j in xrange(n): 
    for i2 in xrange(i + 1, m): 
     for j2 in xrange(j + 1, n): 

Per La parte successiva, sarebbe ancora meglio se che myarray sarebbe pura Array C, quindi nessun comparaison ricco in Python né accesso ad array. Con l'array di pitone, è possibile rimuovere la ricca comparaison facendo comparaison nativo (se avete letto nella propria matrice):

 cdef double a, b, c, d 
     a = myarray[i][j] 
     b = myarray[i2][j2] 
     c = myarray[i2][j] 
     d = myarray[i][j2] 

     if a == b and c == d: 
      return [i, j], [i2, j2] 

Si può vedere come l'ottimizzazione stanno eseguendo cython -a yourfile.pyx, quindi aprire il yourfile.html generare. Vedrai come Cython ha ottimizzato il tuo codice e rimosso il sovraccarico di Python.

+0

Ok, grazie, proverò Cython perché ho bisogno di un grande incremento di velocità. –

+0

Ancora, grazie, ci proverò. –

+0

Questa pagina illustra i vantaggi di cython con un problema simile a quello di cui sto parlando: http://www.korokithakis.net/posts/optimizing-python-with-cython/ –

11

Non è lo stile di codifica più grazioso, ma i tempi disperati richiedono una codifica disperata. Provare a girare i vostri cicli annidati annidati in un unico grande generatore di espressione:

try: 
    i,j,i2,j2 = ((i,j,i2,j2) 
     for i in xrange(m) 
      for j in xrange(n) 
      for i2 in xrange(i + 1, m) 
       for j2 in xrange(j + 1, n) 
       if myarray[i][j] == myarray[i2][j2] and 
        myarray[i2][j] == myarray[i][j2]).next() 
    return [i,j],[i2,j2] 
except StopIteration: 
    return None 
+0

Ok, ci proverò adesso. –

+0

Non ha migliorato la velocità ma una bella espressione comunque. –

+0

Forse nessun segno di spunta, ma che ne dite di un upvote? – PaulMcG

1

dispiace l'espr generatore non ha funzionato. Ecco uno schema diverso che prima collima tutti i valori come, e poi cerca i gruppi rettangolari:

from collections import defaultdict 
from itertools import permutations 
def f3(myarray): 
    tally = defaultdict(list) 
    for i,row in enumerate(myarray): 
     for j,n in enumerate(row): 
      tally[n].append((i,j)) 

    # look for rectangular quads in each list 
    for k,v in tally.items(): 
     for quad in permutations(v,4): 
      # sort quad so that we can get rectangle corners 
      quad = sorted(quad) 
      (i1,j1),(i2,j2) = quad[0], quad[-1] 

      # slice out opposite corners to see if we have a rectangle 
      others = quad[1:3] 

      if [(i1,j2),(i2,j1)] == others: 
       return [i1,j1],[i2,j2] 
+0

ci provo subito –

+0

grazie, l'ho provato e ho imparato alcune cose sulla sintassi di Python, ma non è andato più veloce delle altre cose. –

+0

Se si dispone di un array sparse e si desidera solo valori di corrispondenza diversi da zero, è possibile saltare tutti i test di permutazione delle celle zero precedendo il comando 'for quad in permutations (v, 4):' istruzione con 'se k == 0: continua'. – PaulMcG

1

ho guardato più volte attraverso il vostro codice e se ho capito bene, la vostra marcatura vostri rettangoli con due diversi angoli marcatori . Mi dispiace se la mia risposta è più un commento per chiarire la tua posizione quindi una risposta davvero.

Answer-Part:: Se si sta cercando un algoritmo appropriato, prendere in considerazione un algoritmo della linea di scansione. Ho trovato un esempio here @SO per una "soluzione rettangolo più grande".

La mia domanda per te è, cosa stai veramente cercando?

  1. modo migliore per risolvere il ciclo for dilemma
  2. migliore lingua per il vostro algoritmo
  3. un algoritmo più veloce per trovare i rettangoli

Devo anche sottolineare, che Paolo e il vostro prodotto soluzione risultati diversi, perché Pauls presuppone che gli angoli siano contrassegnati da stessi valori e si assume che gli angoli siano contrassegnati da due valori diversi!

ho preso il tempo e la libertà di illustrare con un c & sceneggiatura brutta p: Esso mette a confronto sia algoritmo creando un 2D-campo e la riempie di caratteri string.lowercase e si rivolge agli angoli in maiuscolo-caratteri.

from random import choice 
from string import lowercase 
from collections import defaultdict 
from itertools import permutations 
from copy import deepcopy 

m,n = 20, 20 
myarray = [[choice(lowercase) for x in xrange(m)] for y in xrange(n)] 

def markcorners(i,j,i2,j2): 
    myarray[i][j] = myarray[i][j].upper() 
    myarray[i2][j] = myarray[i2][j].upper() 
    myarray[i2][j2] = myarray[i2][j2].upper() 
    myarray[i][j2] = myarray[i][j2].upper() 

def printrect(): 
    for row in myarray: 
     print ''.join(row) 
    print '*'*m 

def paul_algo(): 
    tally = defaultdict(list) 
    for i,row in enumerate(myarray): 
     for j,n in enumerate(row): 
      tally[n].append((i,j)) 

    # look for rectangular quads in each list 
    for k,v in tally.items(): 
     for quad in permutations(v,4): 
      # sort quad so that we can get rectangle corners 
      quad = sorted(quad) 
      (i1,j1),(i2,j2) = quad[0], quad[-1] 

      # slice out opposite corners to see if we have a rectangle 
      others = quad[1:3] 

      if [(i1,j2),(i2,j1)] == others: 
       markcorners(i1,j1,i2,j2) 

def xavier_algo(): 
    for i in xrange(m): 
     for j in xrange(n): 
      for i2 in xrange(i + 1, m): 
       for j2 in xrange(j + 1, n): 
        if myarray[i][j] == myarray[i2][j2] and myarray[i2][j] == myarray[i][j2]: 
         markcorners(i,j,i2,j2) 

savearray = deepcopy(myarray) 
printrect() 

xavier_algo() 
printrect() 

myarray = deepcopy(savearray) 
paul_algo() 
printrect() 
+0

Ciao. Grazie per la tua risposta. Ho bisogno che i valori degli angoli opposti siano diversi. Un algoritmo migliore sarebbe bello. Daro 'un'occhiata a quello che indichi domani. Ho dormito adesso perché è un po 'tardi qui. –

+0

Ho dato un'occhiata al algo che hai suggerito.Ben pensato, ma non si adatta alle mie esigenze che sono particolari. Non ho bisogno di trovare il rettangolo più grande, ma devo trovarli tutti con angoli opposti che hanno lo stesso valore. Viene utilizzato in una funzione di vicinato in una ricerca tabu per un problema di ottimizzazione discreto. –