2013-04-09 13 views
5

sto cercando di accelerare il seguente codice Python:Accelerare pitone ciclo

for j in range(4,len(var_s),3): 
    mag_list.append(float(var_s[j])) 
mag_list = [value for value in mag_list if value != 99.] 
med_mag = np.median(mag_list) 

C'è un bel modo di combinare i due per-loop in uno? In questo modo, è molto lento. Quello di cui ho bisogno è estrarre ogni terza voce dalla lista var_s, cominciando dalle quinte, se il valore di quella voce non è uguale a 99. Della lista risultante, ho bisogno della mediana. Grazie!

+0

'med_mag = np.median ([v per v in map (float, var_s [4 :: 3]) se v! = 99])'. Non sono sicuro se è più veloce, ma è più breve. Droogans

+0

Quali tipi di dati sono i vari 'var_s'? Hai davvero bisogno di costruire un float da ognuno di essi? – mgilson

+1

Avete un set di dati di esempio su cui eseguire un benchmarking? Hai la mia curiosità =) –

risposta

12

Probabilmente si potrebbe provare:

mag_list = [value for value in var_s[4::3] if value != 99.] 

seconda var_s, si potrebbe fare meglio utilizzando itertools.islice(var_s,4,None,3), ma che avrebbe sicuramente bisogno di essere cronometrato di sapere.

Forse si farebbe ancora meglio se si bloccato con numpy tutta la strada:

vs = np.array(var_s[4::3],dtype=np.float64) #could slice after array conversion too ... 
med_mag = np.median(vs[vs!=99.]) 

Di nuovo, questo dovrebbe essere a tempo per vedere come eseguita in relazione agli altri.

+0

Potresti volerlo cast anche in un float? 'float (valore) per valore in var_s [4 :: 3] se value! = 99. Inoltre, non è necessario memorizzare la lista intermedia se tutto ciò di cui ha bisogno è la mediana. – Moshe

+0

@Moshe - Buon punto, non me ne sono accorto. – mgilson

+0

Usando questo ottengo il seguente errore quando provo a ottenere la mediana di mag_list. Qualche idea su come risolverlo? 'med_mag = np.median (mag_list) File" /usr/lib64/python2.6/site-packages/numpy/lib/function_base.py ", riga 2995, in media media di ritorno (ordinato [indicizzatore], asse = axis, out = out) File "/usr/lib64/python2.6/site-packages/numpy/core/fromnumeric.py ", riga 2488, in media out = out, keepdims = keepdims) File" /usr/lib64/python2.6/site-packages/numpy/core/_methods.py ", riga 51, in _mean out = out, keepdims = keepdims) TypeError: impossibile eseguire la riduzione con il tipo flessibile ' – frixhax

1
for j in range(4,len(var_s),3): 
    value = float(var_s[j]) 
    if value != 99: 
     mag_list.append(value) 
med_mag = np.median(mag_list) 
4
mag_list = filter(lambda x: x != 99, var_s[4::3]) 

Ok, ecco alcuni timeit prove, tutte in Python 2.7.2:

Il setup:

>>> from random import seed, random 
>>> from timeit import Timer 
>>> from itertools import islice, ifilter, imap 
>>> seed(1234); var_s = [random() for _ in range(100)] 

Utilizzando un ciclo for:

>>> def using_for_loop(): 
...  mag_list = [] 
...  for j in xrange(4, len(var_s), 3): 
...    value = float(var_s[j]) 
...    if value != 99: mag_list.append(value) 
... 
>>> Timer(using_for_loop).timeit() 
11.596584796905518 

Utilizzando mappa e filtro:

>>> def using_map_filter(): 
...  map(float, filter(lambda x: x != 99, var_s[4::3])) 
... 
>>> Timer(using_map_filter).timeit() 
8.643505096435547 

Utilizzando iSlice, imap, IFilter:

>>> def using_itertools(): 
...  list(imap(float, ifilter(lambda x: x != 99, islice(var_s, 4, None, 3)))) 
... 
>>> Timer(using_itertools).timeit() 
11.311019897460938 

Usando una lista di comprensione e iSlice:

>>> def using_list_comp(): 
...  [float(v) for v in islice(var_s, 4, None, 3) if v != 99] 
... 
>>> Timer(using_list_comp).timeit() 
8.52650499343872 
>>> 

In conclusione, utilizzando una comprensione lista con iSlice è il più veloce, seguito dal solo leggermente uso più lento della mappa e del filtro.

+0

Questo è probabilmente più lento se non di una lista di comprensione, a causa del ripetuto ca Fino alla funzione lambda - Le chiamate alla funzione Python sono relativamente costose. Inoltre, per far fluire il cast lì è necessario utilizzare qualcosa come 'map (float, filter (...))', eseguendo il loop due volte anziché una volta, rendendo questo * meno * probabilmente più veloce. La mappa – lvc

+0

restituisce un generatore (almeno in Python 3), quindi non preoccuparti del "ciclo due volte". – William

+0

Come, fa 'filter()', ma vedo il tuo punto @ lvc. –