De référence pour la vectorisé solutions
Nous sommes à la recherche de la référence vectorisé solutions dans ce post. Maintenant, la vectorisation essaie d'éviter la boucle que nous allions parcourir chaque ligne et de faire le déplacement. Ainsi, le programme d'installation pour le tableau d'entrée comporte un plus grand nombre de lignes.
Approches -
def app1(a): # @Daniel F's soln
i, j = np.nonzero(a.astype(bool))
k = np.argsort(i + np.random.rand(i.size))
a[i,j] = a[i,j[k]]
return a
def app2(x): # @kazemakase's soln
r, c = np.where(x != 0)
n = c.size
perm = np.random.permutation(n)
i = np.argsort(perm + r * n)
x[r, c] = x[r, c[i]]
return x
def app3(a): # @Divakar's soln
m,n = a.shape
rand_idx = np.random.rand(m,n).argsort(axis=1)
b = a[np.arange(m)[:,None], rand_idx]
a[a!=0] = b[b!=0]
return a
from scipy.ndimage.measurements import labeled_comprehension
def app4(a): # @FabienP's soln
def func(array, idx):
r[idx] = np.random.permutation(array)
return True
labels, idx = nz = a.nonzero()
r = a[nz]
labeled_comprehension(a[nz], labels + 1, np.unique(labels + 1),\
func, int, 0, pass_positions=True)
a[nz] = r
return a
L'analyse comparative de la procédure #1
Pour une juste analyse comparative, il semble raisonnable d'utiliser l'OP de l'échantillon et simplement la pile de ceux que plus de lignes pour obtenir un plus grand ensemble de données. Ainsi, avec cette configuration, nous pouvons créer deux cas, avec 2 millions de dollars et 20 millions de lignes de jeux de données.
Cas n ° 1 : Grand jeu de données avec 2*1000,000
lignes
In [174]: a = np.array([[2,3,1,0],[0,0,2,1]])
In [175]: a = np.vstack([a]*1000000)
In [176]: %timeit app1(a)
...: %timeit app2(a)
...: %timeit app3(a)
...: %timeit app4(a)
...:
1 loop, best of 3: 264 ms per loop
1 loop, best of 3: 422 ms per loop
1 loop, best of 3: 254 ms per loop
1 loop, best of 3: 14.3 s per loop
Cas #2 : Plus grand ensemble de données avec 2*10,000,000
lignes
In [177]: a = np.array([[2,3,1,0],[0,0,2,1]])
In [178]: a = np.vstack([a]*10000000)
# app4 skipped here as it was slower on the previous smaller dataset
In [179]: %timeit app1(a)
...: %timeit app2(a)
...: %timeit app3(a)
...:
1 loop, best of 3: 2.86 s per loop
1 loop, best of 3: 4.62 s per loop
1 loop, best of 3: 2.55 s per loop
L'analyse comparative de la procédure #2 : un Vaste
Pour couvrir tous les cas de la variable pourcentage de non-zéros dans le tableau d'entrée, nous sommes en couvrant une évaluation comparative des scénarios. Aussi, depuis app4
semblait beaucoup plus lente que les autres, pour un examen plus approfondi nous sauter ce dans cette section.
Fonction d'assistance à la configuration d'entrée de gamme :
def in_data(n_col, nnz_ratio):
# max no. of elems that my system can handle, i.e. stretching it to limits.
# The idea is to use this to decide the number of rows and always use
# max. possible dataset size
num_elem = 10000000
n_row = num_elem//n_col
a = np.zeros((n_row, n_col),dtype=int)
L = int(round(a.size*nnz_ratio))
a.ravel()[np.random.choice(a.size, L, replace=0)] = np.random.randint(1,6,L)
return a
Chronométrage et le traçage de script (Utilise IPython fonctions magiques. Donc, doit être exécuté opon de copier et de coller sur console IPython) -
import matplotlib.pyplot as plt
# Setup input params
nnz_ratios = np.array([0.2, 0.4, 0.6, 0.8])
n_cols = np.array([4, 5, 8, 10, 15, 20, 25, 50])
init_arr1 = np.zeros((len(nnz_ratios), len(n_cols) ))
init_arr2 = np.zeros((len(nnz_ratios), len(n_cols) ))
init_arr3 = np.zeros((len(nnz_ratios), len(n_cols) ))
timings = {app1:init_arr1, app2:init_arr2, app3:init_arr3}
for i,nnz_ratio in enumerate(nnz_ratios):
for j,n_col in enumerate(n_cols):
a = in_data(n_col, nnz_ratio=nnz_ratio)
for func in timings:
res = %timeit -oq func(a)
timings[func][i,j] = res.best
print func.__name__, i, j, res.best
fig = plt.figure(1)
colors = ['b','k','r']
for i in range(len(nnz_ratios)):
ax = plt.subplot(2,2,i+1)
for f,func in enumerate(timings):
ax.plot(n_cols,
[time for time in timings[func][i]],
label=str(func.__name__), color=colors[f])
ax.set_xlabel('No. of cols')
ax.set_ylabel('time [seconds]')
ax.grid(which='both')
ax.legend()
plt.tight_layout()
plt.title('Percentage non-zeros : '+str(int(100*nnz_ratios[i])) + '%')
plt.subplots_adjust(wspace=0.2, hspace=0.2)
Les Timings de la sortie -
Observations :
Approches #1, #2 n' argsort
sur le non-zéro éléments à travers l'ensemble du tableau d'entrée. En tant que tel, il fonctionne mieux avec moins de pourcentage de non-zéros.
Approche n ° 3 crée des nombres aléatoires de la même forme que le tableau d'entrée, puis il reçoit argsort
indices par ligne. Ainsi, pour un nombre donné de non-zéros dans l'entrée, les horaires sont plus raides-ish que les deux premières approches.
Conclusion :
Approche n ° 1 semble être assez bien jusqu'à 60% de non-zéro. Pour plus de non-zéros et si la ligne-les longueurs sont de petite taille, de l'approche n ° 3 semble exercer décemment.