J'ai un tableau numpy de taille 46928x28x28 et je veux diviser aléatoirement ce tableau en deux sous-matrices de tailles (41928x28x28) et (5000x28x28). Par conséquent, pour sélectionner aléatoirement des lignes dans le tableau initial. Le code que j'ai essayé jusqu'à présent (pour calculer les index des deux sous-tableaux) est le suivant:

ind = np.random.randint(input_matrix.shape[0], size=(5000,))
rest = np.array([i for i in range(0,input_matrix.shape[0]) if i not in ind])
rest = np.array(rest)

Cependant, de manière surprenante, la forme de ind est (5000,) tandis que la forme du reste est (42192,). Qu'est-ce que je fais mal dans ce cas?

10
konstantin 23 mai 2018 à 17:58

3 réponses

Meilleure réponse

L'erreur est que randint donne des indices répétés. Vous pouvez le tester en imprimant len(set(ind)) et vous verrez qu'il est inférieur à 5000.

Pour utiliser la même idée, remplacez simplement la première ligne par

ind = np.random.choice(range(input_matrix.shape[0]), size=(5000,), replace=False)

Cela étant dit, la deuxième ligne de votre code est assez lente en raison de l'itération sur la liste. Il serait beaucoup plus rapide de définir les indices souhaités avec un vecteur de booléens, ce qui vous permettrait d'utiliser l'opérateur de négation ~.

choice = np.random.choice(range(matrix.shape[0]), size=(5000,), replace=False)    
ind = np.zeros(matrix.shape[0], dtype=bool)
ind[choice] = True
rest = ~ind

Sur ma machine, cette méthode est exactement aussi rapide que l'implémentation de train_test_split de scikit.learn, ce qui me fait penser que les deux font exactement la même chose.

7
Gianluca Micchi 23 mai 2018 à 16:35

Je suis d'accord avec le commentaire selon lequel train_test_split pourrait être la voie à suivre. Cependant, comme il s'agit du tag numpy, voici une numpy façon de faire les choses, ce qui est assez rapide:

# recreate random array:
x = np.random.random((46928,28,28))

# pick your indices for sample 1 and sample 2:
s1 = np.random.choice(range(x.shape[0]), 41928, replace=False)
s2 = list(set(range(x.shape[0])) - set(s1))

# extract your samples:
sample1 = x[s1, :, :]
sample2 = x[s2, :, :]

Votre sortie:

>>> sample1.shape
(41928, 28, 28)
>>> sample2.shape
(5000, 28, 28)

Horaires:

Par simple curiosité, j'ai chronométré cette méthode numpy par rapport à sklearn.model_selection.train_test_split et obtenu peu de différence. train_test_split est plus rapide, mais seulement par un tout petit peu. Dans tous les cas, je maintiens que train_test_split est la meilleure option.

Méthode numpy: 0,26082248413999876 secondes en moyenne

Méthode train_test_split: 0,22217219217000092 secondes en moyenne

3
sacuL 23 mai 2018 à 15:22

Une façon consiste à essayer d'utiliser train_test_split à partir de sklearn documentation:

import numpy as np
from sklearn.model_selection import train_test_split

# creating matrix
input_matrix = np.arange(46928*28*28).reshape((46928,28,28))
print('Input shape: ', input_matrix.shape)
# splitting into two matrices of second matrix by size
second_size = 5000/46928

X1, X2 = train_test_split(input_matrix, test_size=second_size)

print('X1 shape: ', X1.shape)
print('X2 shape: ', X2.shape)

Résultat:

Input shape:  (46928, 28, 28)
X1 shape:  (41928, 28, 28)
X2 shape:  (5000, 28, 28)
7
student 23 mai 2018 à 15:09