2016-02-06 1 views
3

J'ai commencé à travailler avec numba aujourd'hui, principalement parce que j'ai une boucle for-imbriquée qui peut prendre du temps avec du code python régulier.Numba JIT changer les résultats si les valeurs sont imprimées

J'ai une version macports de python-2.7 avec LLVM-3.6 et la version pépin de Numba (tout est à jour)

Voici le code que je utilise:

import pandas as pd 
from numba import jit 
from numpy import nan, full 

@jit 
def movingAverage(adj_close, maxMA): 
    ma = full([len(adj_close), maxMA], nan, dtype=float64) 
    ind = range(1, len(adj_close)+1) 
    for d in ind: 
     m = max(0, d-maxMA-1) 
     adj = adj_close[d-1:m:-1] if (m or d==maxMA+1) else adj_close[d-1::-1] 
     cs = adj.cumsum() 
     for i in range(len(adj)): 
      ma[d-1][i] = (cs[i]/(i+1)) 
     print ma 
    return ma 

Je calcule une moyenne mobile pour l'entrée adj_close jusqu'à maxMA jours.

adj_close est un tableau de valeurs, une valeur par jour

I a commencé par la création d'ma, un support pour les valeurs qui vont être calculée. Et travailler les Vaules pour chaque jour individuellement (notez que le premier jour ne peut avoir une moyenne impliquant 1 jour, le second, 2 et ainsi de suite jusqu'à la MAXMA)

Si je entrée quelque chose comme adj_close = array(range(5), dtype=float64) et maxMA = 3 obtenir le bonne réponse comme suit:

array([[ 0., nan, nan], 
     [ 1., 0.5, nan], 
     [ 2., 1.5, 1.], 
     [ 3., 2.5, 2.], 
     [ 4., 3.5, 3.]]) 

Toutefois, si je prends la ligne print ma, juste avant le retour de ma fonction, il retourne seulement une partie de la réponse:

array([[ nan, nan, nan], 
     [ nan, nan, nan], 
     [ nan, nan, nan], 
     [ 3., 2.5, 2.], 
     [ 4., 3.5, 3.]]) 

Pourquoi est-il ainsi? Pourquoi @jit a-t-il besoin de l'impression entre ces boucles pour obtenir la bonne réponse? Que puis-je faire pour me débarrasser de l'instruction d'impression (ce qui augmente considérablement le temps d'exécution)?


Edit: Je suis d'accepter la suggestion @JoshAdel et a ouvert un issue au github de Numba. J'accepte donc @MSeifert réponse que la solution de contournement a résolu le problème pour moi.

+1

On dirait un bug pour moi. Je posterais quelque chose aux problèmes de Numba sur github puisque vous avez un exemple minimal qui démontre le problème. – JoshAdel

+0

Malheureusement, je reçois la bonne réponse quand je l'exécute (Python3, et peut-être une version différente de Numba). Cependant, je me demande si changer votre ligne d'indexation à 'ma [d-1, i] = ...' aiderait. Je pense que @MSeifert a raison sur le mode python vs nopython, et je me souviens que le mode nopython ne traite pas de l'indexation séquentielle (c'est-à-dire [a] [b] ') très bien. – DavidW

Répondre

1

Je pense que numba fait quelque chose d'étrange ici, mais probablement en raison du mélange de python et nopython. Si j'utilise Python 3.5 les retours sont identiques avec et sans print.

Pour python 2.7 Je pense que le problème est dû au fait que la boucle for est compilée en mode nopython (sans impression) ou en mode python (avec impression). Mais ensuite converti en python quand il quitte la boucle. Mais c'est juste deviner. Mais je l'ai essayé avec:

import pandas as pd 
from numba import jit 
from numpy import nan, full 
import numpy as np 

@jit 
def movingAverage(adj_close, maxMA): 
    ma = full([len(adj_close), maxMA], nan, dtype=np.float64) 
    ind = range(1, len(adj_close)+1) 
    for d in ind: 
     m = max(0, d-maxMA-1) 
     adj = adj_close[d-1:m:-1] if (m or d==maxMA+1) else adj_close[d-1::-1] 
     cs = adj.cumsum() 
     for i in range(len(adj)): 
      ma[d-1][i] = (cs[i]/(i+1)) 
     if d == ind[-1]: 
      return ma # notice that I return it after the last loop but before the loop terminates. 
    #return ma 

et il ne retourne:

array([[ 0., nan, nan], 
     [ 1., 0.5, nan], 
     [ 2., 1.5, 1.], 
     [ 3., 2.5, 2.], 
     [ 4., 3.5, 3.]]) 

C'est cependant pas une façon très EFFIENT à cause du recalcul de len(adj_close)+1. Cela pourrait être stocké quelque part.

+0

au lieu d'utiliser 'if d == len (adj_close) + 1:' je peux utiliser 'si d == ind [-1]' au même résultat sans le recalcul – pekapa

+0

J'ai modifié la réponse, je ne sais pas si une telle recherche de liste est plus rapide que le calcul, elle semble plus rapide, surtout pour les petites entrées. – MSeifert

+0

les valeurs typiques sont de l'ordre de 200.000 pour 'len (adj_close)' et 'maxMA = 1000'. Pour cela, il faut 1min16s pour fonctionner avec 'if d == ind [-1]' (même chose pour le stocker ailleurs) et 1min20s avec 'if d == len (adj_close) + 1' – pekapa