2014-09-13 3 views
2

Je cherche à optimiser un programme que j'ai écrit et je suis vraiment confronté à des obstacles. J'ai tellement de questions, je ne sais pas par où commencer mais, pour les débutants, je vais essayer de le simplifier à un obstacle que je n'arrive pas à surmonter.Le moyen le plus rapide de sommer des colonnes individuelles

Le code que j'écris est un petit générateur d'horaires pour le travail qui nécessite une couverture 24/7. Chaque quart couvre une période de deux semaines (certains postes tournent sur une période de deux semaines, mais les exigences de couverture doivent être maintenues - c'est pourquoi je dois utiliser 14 jours). Pour le moment, j'essaie de trouver le moyen le plus rapide de vérifier si une combinaison de postes s'additionne au bon nombre de personnes un jour donné. On me dit Numpy est super rapide à ce genre de choses, mais quand je lance ce qui suit:

import numpy as np 
import time 

c_ar = np.array([1,1,1,1,0,0,0,1,1,1,1,0,0,0]) 
d_ar = np.array([0,0,0,1,1,1,1,0,0,0,1,1,1,1]) 
e_ar = np.array([0,0,0,1,1,1,1,0,0,0,1,1,1,1]) 
m_ar = np.array([0,1,1,0,1,1,0,0,1,1,0,1,1,0]) 
p_ar = np.array([1,1,0,0,0,1,1,1,1,0,0,0,1,1]) 

t0 = time.time() 
x = c_ar[0] + d_ar[0] + e_ar[0] + m_ar[0] + p_ar[0] 
t1 = time.time() 
print t1-t0 

Je reviens:

2.19345092773e-05

Cependant, si je exécutez:

c = [1,1,1,1,0,0,0,1,1,1,1,0,0,0] 
d = [0,0,0,1,1,1,1,0,0,0,1,1,1,1] 
e = [0,0,0,1,1,1,1,0,0,0,1,1,1,1] 
m = [0,1,1,0,1,1,0,0,1,1,0,1,1,0] 
p = [1,1,0,0,0,1,1,1,1,0,0,0,1,1] 

t2 = time.time() 
y = c[0] + d[0] + e[0] + m[0] + p[0] 
t3 = time.time() 
print t3-t2 

Je reviens:

1.90734863281e-06

Suis-je manque quelque chose au sujet Numpy qui rendrait plus rapide que mon exemple? Aussi, existe-t-il un moyen encore plus rapide que les deux méthodes que j'ai utilisées plus haut?

+0

Plus un pour la question intéressante. –

Répondre

1

Mettez toutes les données dans un tableau numpy, puis appelez numpy.sum une fois:

arr.sum(axis=0) 

Les tableaux NumPy ne sont pas plus rapide que le code Python normal lorsque tout ce que vous utilisez pour accéder à des valeurs est l'élément individuel -Par point, comme cela se fait ici:

c_ar[0] + d_ar[0] + e_ar[0] + m_ar[0] + p_ar[0] 

en outre, pour les tableaux ce petit code Python régulier peut être plus rapide que d'utiliser des tableaux numpy:

c = [1,1,1,1,0,0,0,1,1,1,1,0,0,0] 
d = [0,0,0,1,1,1,1,0,0,0,1,1,1,1] 
e = [0,0,0,1,1,1,1,0,0,0,1,1,1,1] 
m = [0,1,1,0,1,1,0,0,1,1,0,1,1,0] 
p = [1,1,0,0,0,1,1,1,1,0,0,0,1,1] 
arr = np.row_stack([c,d,e,m,p]) 

In [226]: %timeit c[0] + d[0] + e[0] + m[0] + p[0] 
10000000 loops, best of 3: 189 ns per loop 

In [231]: %timeit arr[:,0].sum() 
100000 loops, best of 3: 4.73 µs per loop 

In [239]: %timeit [c[i] + d[i] + e[i] + m[i] + p[i] for i in range(len(c))] 
100000 loops, best of 3: 3.68 µs per loop 

In [240]: %timeit arr.sum(axis=0) 
100000 loops, best of 3: 5.04 µs per loop 
+0

Merci! Les tableaux que j'ai affaire sont généralement 11 ou 12 lignes avec 14 colonnes. Je vais donner à ces suggestions un coup de feu et voir ce qui se passe – user3833942

+0

Par ailleurs, [utilisez le module timeit] (http://stackoverflow.com/q/8220801/190597) pour comparer le code. Utiliser 'time.time()' sans répétitions [peut produire des résultats trompeurs] (http://stackoverflow.com/q/1622943/190597). Mais dans tous les cas, sauf si vous avez affaire à des tableaux significativement plus grands, il n'est pas clair que NumPy sera plus rapide que le code Python. – unutbu

+0

Je m'en souviendrai certainement! Merci encore. – user3833942

1

Ne soyez pas si soucieux de vitesse que la lisibilité et directement en utilisant les fonctions comme ils sont donnés mieux que vous pouvez. Les implémentations peuvent varier, mais si vous faites sémantiquement la bonne chose, à long terme, vous avez pris la bonne décision. Optimisez seulement au coût de ces choses si vous profilez votre code et déterminez qu'il soit un goulot d'étranglement cher.

>>> np.array([[1, 1], [1, 1], [1, 1]]) 
array([[1, 1], 
     [1, 1], 
     [1, 1]]) 
>>> np.array([[1,1],[1,1], [1,1]]).sum(axis=0) 
array([3, 3]) 

Si vous devez conserver dimensionnalité:

>>> np.array([[1,1],[1,1], [1,1]]).sum(axis=0, keepdims=True) 
array([[3, 3]]) 

Une raison pour laquelle vous pouvez faire est de concaténer la somme comme une ligne:

>>> arr = np.array([[1,1],[1,1], [1,1]]) 
>>> np.vstack((arr, arr.sum(axis=0, keepdims=True))) 
array([[1, 1], 
     [1, 1], 
     [1, 1], 
     [3, 3]]) 
+0

Merci! Je vais essayer ça. – user3833942

0

Probablement beaucoup dépend comment vous présentez vos données et ce que vous voulez en faire. Il n'est pas nécessaire de convertir en un tableau numpy juste pour récapituler.Avec cette configuration:

import numpy as np 

a = [1,1,1,1,0,0,0,1,1,1,1,0,0,0] 
.... 
l = [0,0,0,1,1,1,1,0,0,0,1,1,1,1] 

arr = np.row_stack([a, b, c, d, e, f, g, h, i, j, k, l]) 

Je reçois avec Python

>>> %timeit [sum(col) for col in zip(a, b, c, d, e, f, g, h, i, j, k, l)] 
100000 loops, best of 3: 8.84 µs per loop 

Numpy

>>> %timeit arr.sum(0) 
100000 loops, best of 3: 6.71 µs per loop 

j'ai vécu Cython être plus rapide en prenant des sommes de petits tableaux, mais seulement lorsque vous travaillez au sein de Cython et ne pas appeler souvent à partir de python. C'est à dire que si vous déplacez un tas de calculs vers Cython, vous feriez mieux d'utiliser une petite routine d'addition plutôt que d'utiliser une routine numpy. Une auto en fonction cython sumcols se trouve être plus lent lorsque appelé de python

%timeit sumcols(arr) 
100000 loops, best of 3: 9.86 µs per loop 

Rappelez-vous que si vous aviez des lignes longues, un tableau transposé pourrait être plus rapide, parce que les tableaux sont numpy Row-Major Order par défaut. Cela ne fait pas de différence dans ce cas.

>>> arr_T = arr.transpose(1, 0).copy() 
>>> %timeit arr_T.sum(1) 
100000 loops, best of 3: 6.59 µs per loop 
Questions connexes