Python è adatto per un'applicazione di modellazione statistica alla ricerca di migliaia di eventi passati?

2

Attualmente sto lavorando a un progetto con un partner in cui analizziamo grandi serie di dati di eventi sportivi del passato. Ci sono circa 30.000 eventi all'anno e abbiamo dati storici per cinque anni. Pertanto, stiamo analizzando 150.000 eventi.

Ho scritto la nostra prima versione in Python con una strong dipendenza da Pandas (ottimo strumento, tra l'altro). Tuttavia, ogni volta che aggiungo un "fattore" o un calcolo al processo, rallenta un bel po '. In poche parole, può leggere tutti i vari file di dati e le query di dati di cui abbiamo bisogno a una velocità di 25 eventi al secondo.

Il problema è che una volta che comincio a lavorare con i dati, cade velocemente. Se aggiungo un semplice calcolo, scende a 24 ... e ogni calcolo dopo di ciò scende di nuovo.

Con solo 10-12 "fattori" calcolati dai dati (non stiamo parlando di loop complessi o di qualcosa di pazzesco), è ora fino a 6 eventi al secondo. ... e stiamo a malapena a grattare la superficie. A questo ritmo, ci vorranno giorni in questo modo per superare tutti gli eventi da 150k!

Ho ottimizzato le nostre query di dati, letture di file flat ecc. In realtà non sono questo il problema. Posso vivere con 15-20 eventi al secondo. Tuttavia, non posso vivere con tali drastici rallentamenti ogni volta che viene aggiunto un nuovo calcolo fattoriale.

Ho letto molto in cui Python come linguaggio interpretato è lento ecc., ma la mia domanda agli esperti là fuori - quale linguaggio dovrebbe essere fatto in questo progetto?

ESEMPIO ...

Uno dei principali "DataFrames" che sto utilizzando tramite Pandas è abbastanza grande. 350 righe x 70 colonne, ad esempio. Anche quando cerchi di moltiplicare semplicemente il valore di una colonna per un'altra ...

 data['value'] = data['col1'] * data['col2']

... Vedo ciò che potrei considerare un calo significativo delle prestazioni. È molto sconcertante e molto frustrante. Capisco che questo sia un grande insieme di dati, ma non posso credere che questo sia qualcosa di così folle che Python potrebbe rallentare la scansione.

Se leggo solo i file di dati e non li faccio affatto, legge 67 eventi in 2.807 secondi. Se aggiungo un semplice calcolo dove eseguo il codice come nell'esempio precedente, rallenta a 2.877 secondi. Sulla base delle nostre ricerche, è necessario aggiungere oltre 100 calcoli sui dati .... quindi 7 secondi di rallentamento? Sembra troppo difficile da credere.

    
posta TravisVOX 07.02.2014 - 17:01
fonte

3 risposte

3

Lavoro su una piattaforma che usa Python per testare ed eseguire dati di mercato. Per il solo prezzo azionario ci sono circa ~ 98.000 eventi per ogni equity all'anno, quindi quando si ha a che fare con un singolo titolo si ha un profilo simile per i nostri set di dati.

(La suddetta piattaforma è Quantopian, link .)

Usiamo anche i panda per la maggior parte delle nostre strutture dati, e anche se è difficile confrontarli senza confrontare anche le macchine utilizzate, il numero di calcoli fatti per evento ... siamo in grado di elaborare alcuni ordini di grandezza più eventi al secondo; quindi non ci possono essere motivi per rinunciare ai panda, ancora.

(Il backtester utilizzato dal nostro sito è opensourced, link se ti piacerebbe vedere come usiamo i panda in tutto; ovviamente, abbiamo ancora i colli di bottiglia da battere!))

Da quello che posso vedere con il modo in cui utilizzi il tuo set di dati, questo suggerimento può aiutarti.

Se possibile, evita di scrivere i tuoi calcoli nel dataset DataFrame.

Un corollario di questo è, se possibile, evitare l'indicizzazione nei loop interni.

Sebbene potente ed espressivo, l'indicizzazione di un DataFrame ha una penalizzazione delle prestazioni; molto come l'accesso a un dizionario Python creerà una penalità di ricerca.

Scrivere i dati nel DataFrame sarà più costoso. Quindi se il tuo programma può semplicemente usare la serie che viene restituita moltiplicando quelle due colonne, potresti vedere alcuni vantaggi nell'assegnare quella Serie alla sua stessa variabile invece di rimetterlo in DataFrame.

Per illustrare, di seguito sono riportati alcuni passaggi da un notebook IPython che passo dopo passo ottiene i valori DataFrame dei panda sempre più vicini all'utilizzo di un np.ndarray raw. Ciò che segue non è inteso come un libro di cucina, ma per mostrare dove sia la scrittura che l'indicizzazione nel DataFrame possono danneggiare le prestazioni. Inoltre, non sarei sorpreso se c'è qualcosa nell'API pandas di cui non sono a conoscenza, il che rende l'assegnazione della colonna molto più performante, cosa che invalida il mio consiglio.

In [1]:
# Create a DataFrame with 3 columns and 350 random values each.
data = pd.DataFrame(randn(350, 3), columns=['col1', 'col2', 'value'])

In [2]:
# Time original example
%timeit data['value'] = data['col1'] * data['col2']
10000 loops, best of 3: 170 µs per loop

In [3]:
# Time without writing the example back into the DataFrame
# The value variable will be a pd.Series
%timeit value = data['col1'] * data['col2']
10000 loops, best of 3: 43.9 µs per loop

# Extract the pd.Series before inner loop 
col1 = data['col1']
col2 = data['col2']

In [25]:
# Time without writing the example back into the DataFrame
# The value variable will be a pd.Series
%timeit value = col1 * col2
10000 loops, best of 3: 32.3 µs per loop

In [4]:
# Time with using the underlying numpy arrays.
# The value variable will be a np.ndarray
%timeit value = data['col1'].values * data['col2'].values
100000 loops, best of 3: 15.9 µs per loop

In [5]:
# Extract the numpy arrays before inner loop 
col1_v = data['col1'].values
col2_v = data['col2'].values

In [6]:
# Time just the multiplication of two np.ndarrays 
%timeit col1_v * col2_v
1000000 loops, best of 3: 1.5 µs per loop
    
risposta data 10.02.2014 - 05:17
fonte
8

Python è molto veloce per questo scopo. A seconda del tipo di analisi che stai eseguendo, mi aspetterei di gestire facilmente centinaia o persino migliaia di eventi al secondo.

Il tuo rallentamento è molto probabilmente algoritmico. Non è sufficiente ottimizzare pezzi del puzzle, devi ottimizzare il sistema nel suo insieme scegliendo appropriate strutture dati e algoritmi.

Una volta ho incontrato del codice che funzionava molto lentamente, ma guardando solo uno strato non sembrava doverlo fare. Sembrava essere un semplice attraversamento di liste collegate con al massimo 64 nodi, che è O (n) con un n piuttosto piccolo. Bene, questa funzione ha chiamato un'altra funzione O (n), che ha chiamato un'altra funzione O (n), e così via su 6 livelli. Ciò ha provocato un algoritmo O (n 6 ) che nessuno ha notato prima perché guardava solo uno strato alla volta, e lo eseguiva su dati che erano casualmente in cortocircuito.

Quindi guarda il tuo sistema nel suo insieme. Stai leggendo gli stessi file più e più volte o caching in modo appropriato? Stai eseguendo gli stessi join o altri calcoli più e più volte o preelaborando e memoizzando i tuoi dati per un uso futuro? Stai assumendo che gli strati inferiori di chiamate di funzione siano lineari o costanti quando non lo sono? Puoi riorganizzare l'ordine delle operazioni per renderlo più veloce? Puoi creare indici per velocizzare determinate ricerche?

Questi sono i tipi di problemi che devi risolvere prima di iniziare a esaminare gli aumenti di velocità che potresti ottenere dal passaggio a un'altra lingua. Se è difficile risolvere in Python, immagina quanto sarà difficile risolverlo in un linguaggio di programmazione non familiare.

    
risposta data 07.02.2014 - 19:51
fonte
4

Dovresti usare la lingua che ti è più comoda e che ti consente di manipolare i dati nel modo che desideri. Python ha un numero di librerie scientifiche che ti permettono di fare proprio questo.

Per quanto riguarda i problemi di prestazioni, non lo saprai fino a quando non ci sarai arrivato. E per quanto piccolo di un set di dati come stai parlando, puoi sempre gettare più hardware su di esso. E sì, 150k eventi è piccolo.

Dovresti anche esaminare gli strumenti di analisi statica / analisi delle prestazioni per identificare cosa potresti ottimizzare all'interno del tuo codice. Se sei nuovo in Python, probabilmente stai facendo degli errori (non sentirti male, siamo stati tutti lì). Quindi c'è molto spazio per l'ottimizzazione. Passare a un'altra lingua non risolverà questi problemi. In altre parole, non incolpare lo strumento finché non si è sicuri di aver rimosso qualsiasi errore dell'operatore.

    
risposta data 07.02.2014 - 17:07
fonte

Leggi altre domande sui tag