J'ai essayé d'accélérer le code Python, y compris l'instruction if avec Numba et Cython

introduction

Notes sur l'accélération du code Python avec Numba Donc, j'ai trouvé que Numba est efficace pour accélérer la fonction d'index technique à l'aide de l'instruction for, mais il existe d'autres indicateurs qui utilisent beaucoup l'instruction if.

L'un d'eux est Parabolic SAR. Ce n'est pas un indicateur particulièrement inhabituel, mais plutôt populaire. Cependant, puisque le mode ascendant et le mode descendant sont commutés et que la largeur du pas change, il ne peut pas être décrit par l'instruction for seule. C'était la dernière fois que nous portions les indicateurs techniques de MetaTrader sur Python.

Cette fois, c'est un mémo pour accélérer cela.

Code parabolique SAR Python

import numpy as np
import pandas as pd
dataM1 = pd.read_csv('DAT_ASCII_EURUSD_M1_2015.csv', sep=';',
                     names=('Time','Open','High','Low','Close', ''),
                     index_col='Time', parse_dates=True)

def iSAR(df, step, maximum):
    last_period = 0
    dir_long = True
    ACC = step
    SAR = df['Close'].copy()
    for i in range(1,len(df)):
        last_period += 1    
        if dir_long == True:
            Ep1 = df['High'][i-last_period:i].max()
            SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
            Ep0 = max([Ep1, df['High'][i]])
            if Ep0 > Ep1 and ACC+step <= maximum: ACC+=step
            if SAR[i] > df['Low'][i]:
                dir_long = False
                SAR[i] = Ep0
                last_period = 0
                ACC = step
        else:
            Ep1 = df['Low'][i-last_period:i].min()
            SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
            Ep0 = min([Ep1, df['Low'][i]])
            if Ep0 < Ep1 and ACC+step <= maximum: ACC+=step
            if SAR[i] < df['High'][i]:
                dir_long = True
                SAR[i] = Ep0
                last_period = 0
                ACC = step
    return SAR

%timeit y = iSAR(dataM1, 0.02, 0.2)

L'instruction for est unique, mais cela prend un certain temps.

1 loop, best of 3: 1min 19s per loop

Accélérez avec Numba

Tout d'abord, accélérons avec Numba. Changez simplement le tableau pandas en un tableau numpy et ajoutez @ jit.

from numba import jit
@jit
def iSARjit(df, step, maximum):
    last_period = 0
    dir_long = True
    ACC = step
    SAR = df['Close'].values.copy()
    High = df['High'].values
    Low = df['Low'].values
    for i in range(1,len(SAR)):
        last_period += 1    
        if dir_long == True:
            Ep1 = High[i-last_period:i].max()
            SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
            Ep0 = max([Ep1, High[i]])
            if Ep0 > Ep1 and ACC+step <= maximum: ACC+=step
            if SAR[i] > Low[i]:
                dir_long = False
                SAR[i] = Ep0
                last_period = 0
                ACC = step
        else:
            Ep1 = Low[i-last_period:i].min()
            SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
            Ep0 = min([Ep1, Low[i]])
            if Ep0 < Ep1 and ACC+step <= maximum: ACC+=step
            if SAR[i] < High[i]:
                dir_long = True
                SAR[i] = Ep0
                last_period = 0
                ACC = step
    return SAR

%timeit y = iSARjit(dataM1, 0.02, 0.2)
1 loop, best of 3: 1.43 s per loop

C'est environ 55 fois plus rapide. Il y a peu de modifications de code, donc c'est un très bon résultat.

Accélérez avec Cython

Ensuite, essayez d'accélérer avec Cython. Je pensais que Cython était un problème à configurer, mais avec le notebook Jupyter, il était assez facile à installer. Toutefois, comme il utilise un compilateur externe, vous devez installer Visual C ++. Je devais correspondre à la version d'Anaconda que j'avais construite, j'ai donc installé le compilateur suivant cette fois.

Visual Studio Community 2015

Le premier est lorsque vous définissez uniquement Cython sans modifier le code.

%load_ext Cython
%%cython
cimport numpy
cimport cython
def iSAR_c0(df, step, maximum):
    last_period = 0
    dir_long = True
    ACC = step
    SAR = df['Close'].values.copy()
    High = df['High'].values
    Low = df['Low'].values
    for i in range(1,len(SAR)):
        last_period += 1    
        if dir_long == True:
            Ep1 = High[i-last_period:i].max()
            SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
            Ep0 = max([Ep1, High[i]])
            if Ep0 > Ep1 and ACC+step <= maximum: ACC+=step
            if SAR[i] > Low[i]:
                dir_long = False
                SAR[i] = Ep0
                last_period = 0
                ACC = step
        else:
            Ep1 = Low[i-last_period:i].min()
            SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
            Ep0 = min([Ep1, Low[i]])
            if Ep0 < Ep1 and ACC+step <= maximum: ACC+=step
            if SAR[i] < High[i]:
                dir_long = True
                SAR[i] = Ep0
                last_period = 0
                ACC = step
    return SAR
%timeit y = iSAR_c0(dataM1, 0.02, 0.2)

résultat

1 loop, best of 3: 1.07 s per loop

Cython est un peu plus rapide avec le même code.

Ensuite, lors de l'ajout de la déclaration de type de variable avec cdef.

%%cython
cimport numpy
cimport cython
def iSARnew(df, double step, double maximum):
    cdef int last_period = 0
    dir_long = True
    cdef double ACC = step
    cdef numpy.ndarray[numpy.float64_t, ndim=1] SAR = df['Close'].values.copy()
    cdef numpy.ndarray[numpy.float64_t, ndim=1] High = df['High'].values
    cdef numpy.ndarray[numpy.float64_t, ndim=1] Low = df['Low'].values
    cdef double Ep0, Ep1
    cdef int i, N=len(SAR)
    for i in range(1,N):
        last_period += 1    
        if dir_long == True:
            Ep1 = max(High[i-last_period:i])
            SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
            Ep0 = max([Ep1, High[i]])
            if Ep0 > Ep1 and ACC+step <= maximum: ACC+=step
            if SAR[i] > Low[i]:
                dir_long = False
                SAR[i] = Ep0
                last_period = 0
                ACC = step
        else:
            Ep1 = min(Low[i-last_period:i])
            SAR[i] = SAR[i-1]+ACC*(Ep1-SAR[i-1])
            Ep0 = min([Ep1, Low[i]])
            if Ep0 < Ep1 and ACC+step <= maximum: ACC+=step
            if SAR[i] < High[i]:
                dir_long = True
                SAR[i] = Ep0
                last_period = 0
                ACC = step
    return SAR
%timeit y = iSARnew(dataM1, 0.02, 0.2)

Le résultat est

1 loop, best of 3: 533 ms per loop

était. C'est environ deux fois plus rapide. Cela peut être plus rapide si vous le réglez, mais cela peut rendre votre code moins lisible, alors c'est tout.

Résumé

Dans le cas de l'instruction for uniquement, Numba a également pour effet d'accélérer considérablement, mais lorsque l'instruction if est également incluse, l'effet est réduit. Si vous voulez le rendre un peu plus rapide, vous pouvez utiliser Cython, avec quelques modifications de code.

Recommended Posts

J'ai essayé d'accélérer le code Python, y compris l'instruction if avec Numba et Cython
Remarques sur l'accélération du code Python avec Numba
J'ai installé et utilisé Numba avec Python3.5
J'ai essayé la différenciation jacobienne et partielle avec python
J'ai essayé la synthèse de fonctions et le curry avec python
Chargement / affichage et accélération de gif avec python [OpenCV]
J'ai essayé fp-growth avec python
J'ai essayé de gratter avec Python
J'ai essayé gRPC avec Python
J'ai essayé de gratter avec du python
J'ai essayé la gestion du suivi avec l'API Twitter et Python (facile)
J'ai essayé de créer une interface graphique à trois yeux côte à côte avec Python et Tkinter
Accélérez grossièrement Python avec numba
J'ai joué avec PyQt5 et Python3
J'ai essayé d'exécuter prolog avec python 3.8.2.
J'ai essayé la communication SMTP avec Python
J'ai essayé de faire un processus d'exécution périodique avec Selenium et Python
J'ai essayé de savoir si ReDoS est possible avec Python
J'ai essayé de détecter facilement les points de repère du visage avec python et dlib
Mayungo's Python Learning Episode 7: J'ai essayé d'imprimer avec if, elif, else
Que faire si ipython et python démarrent avec des versions différentes
J'ai essayé le rendu non réaliste avec Python + opencv
J'ai essayé d'obtenir le code d'authentification de l'API Qiita avec Python.
J'ai essayé un langage fonctionnel avec Python
J'ai essayé la récurrence avec Python ② (séquence de nombres Fibonatch)
J'ai essayé de vérifier et d'analyser l'accélération de Python par Cython
J'ai essayé de mettre à jour le calendrier Google avec des rendez-vous CSV à l'aide de Python et de l'API Google
# J'ai essayé quelque chose comme Vlookup avec Python # 2
J'ai essayé de "lisser" l'image avec Python + OpenCV
J'ai essayé des centaines de millions de SQLite avec python
J'ai essayé le web scraping en utilisant python et sélénium
J'ai essayé de "différencier" l'image avec Python + OpenCV
J'ai essayé la détection d'objets en utilisant Python et OpenCV
J'ai essayé Flask avec des conteneurs distants de VS Code
J'ai essayé L-Chika avec Razpai 4 (édition Python)
J'ai essayé de jouer en connectant PartiQL et MongoDB
J'ai essayé d'obtenir des données CloudWatch avec Python
J'ai essayé d'utiliser mecab avec python2.7, ruby2.3, php7
J'ai essayé de sortir LLVM IR avec Python
J'ai essayé de "binariser" l'image avec Python + OpenCV
J'ai essayé d'exécuter faiss avec python, Go, Rust
J'ai essayé d'automatiser la fabrication des sushis avec python
J'ai essayé d'exécuter Deep Floor Plan avec Python 3.6.10.
J'ai essayé d'envoyer un email avec SendGrid + Python
J'ai essayé d'automatiser la mise à jour de l'article du blog Livedoor avec Python et sélénium.
J'ai essayé différentes choses avec Python: le grattage (Beautiful Soup + Selenium + PhantomJS) et l'analyse morphologique
Traitement d'image avec Python (j'ai essayé de le binariser en art mosaïque 0 et 1)
J'ai essayé de comparer la vitesse de traitement avec dplyr de R et pandas de Python
J'ai essayé de lire et d'enregistrer automatiquement avec VOICEROID2 2
J'ai essayé pipenv et asdf pour le contrôle de version Python
Je veux gérer l'optimisation avec python et cplex
J'ai essayé d'implémenter Mine Sweeper sur un terminal avec python
J'ai essayé de démarrer avec le script python de blender_Part 01
J'ai essayé de toucher un fichier CSV avec Python