J'ai deux tableaux numpy de formes différentes, mais de même longueur (dimension principale). Je souhaite mélanger chacun d’eux, de sorte que les éléments correspondants continuent de correspondre, c’est-à-dire les mélanger à l’unisson en ce qui concerne leurs indices principaux.
Ce code fonctionne et illustre mes objectifs:
def shuffle_in_unison(a, b):
assert len(a) == len(b)
shuffled_a = numpy.empty(a.shape, dtype=a.dtype)
shuffled_b = numpy.empty(b.shape, dtype=b.dtype)
permutation = numpy.random.permutation(len(a))
for old_index, new_index in enumerate(permutation):
shuffled_a[new_index] = a[old_index]
shuffled_b[new_index] = b[old_index]
return shuffled_a, shuffled_b
Par exemple:
>>> a = numpy.asarray([[1, 1], [2, 2], [3, 3]])
>>> b = numpy.asarray([1, 2, 3])
>>> shuffle_in_unison(a, b)
(array([[2, 2],
[1, 1],
[3, 3]]), array([2, 1, 3]))
Cependant, cela semble fastidieux, inefficace et lent, et cela nécessite de faire une copie des tableaux - je préfère les mélanger sur place, car ils seront assez volumineux.
Y a-t-il une meilleure façon de s'y prendre? Une exécution plus rapide et une utilisation réduite de la mémoire sont mes objectifs principaux, mais un code élégant serait également agréable.
Une autre pensée que j'avais était la suivante:
def shuffle_in_unison_scary(a, b):
rng_state = numpy.random.get_state()
numpy.random.shuffle(a)
numpy.random.set_state(rng_state)
numpy.random.shuffle(b)
Cela fonctionne ... mais c'est un peu effrayant, car je ne vois aucune garantie que cela continuera à fonctionner - cela ne ressemble pas au genre de chose qui est garanti pour survivre avec la version numpy, par exemple.
Votre solution "effrayante" ne me semble pas effrayante. L'appel de shuffle()
pour deux séquences de même longueur entraîne le même nombre d'appels au générateur de nombres aléatoires, et il s'agit des seuls éléments "aléatoires" de l'algorithme de lecture aléatoire. En réinitialisant l'état, vous vous assurez que les appels au générateur de nombres aléatoires donneront les mêmes résultats lors du deuxième appel à shuffle()
, de sorte que tout l'algorithme générera la même permutation.
Si vous n'aimez pas cela, une solution différente serait de stocker vos données dans un tableau au lieu de deux dès le début, et de créer deux vues dans ce tableau unique simulant les deux tableaux que vous avez maintenant. Vous pouvez utiliser le tableau unique pour le brassage et les vues pour toutes les autres fins.
Exemple: supposons que les tableaux a
et b
ressemblent à ceci:
a = numpy.array([[[ 0., 1., 2.],
[ 3., 4., 5.]],
[[ 6., 7., 8.],
[ 9., 10., 11.]],
[[ 12., 13., 14.],
[ 15., 16., 17.]]])
b = numpy.array([[ 0., 1.],
[ 2., 3.],
[ 4., 5.]])
Nous pouvons maintenant construire un seul tableau contenant toutes les données:
c = numpy.c_[a.reshape(len(a), -1), b.reshape(len(b), -1)]
# array([[ 0., 1., 2., 3., 4., 5., 0., 1.],
# [ 6., 7., 8., 9., 10., 11., 2., 3.],
# [ 12., 13., 14., 15., 16., 17., 4., 5.]])
Maintenant, nous créons des vues simulant l'original a
et b
:
a2 = c[:, :a.size//len(a)].reshape(a.shape)
b2 = c[:, a.size//len(a):].reshape(b.shape)
Les données de a2
Et de b2
Sont partagées avec c
. Pour mélanger les deux tableaux simultanément, utilisez numpy.random.shuffle(c)
.
Dans le code de production, vous devriez bien sûr éviter de créer les a
et b
originaux et créer immédiatement c
, a2
Et b2
.
Cette solution pourrait être adaptée au cas où a
et b
ont des types différents.
Vous pouvez utiliser NumPy's indexation de tableaux :
def unison_shuffled_copies(a, b):
assert len(a) == len(b)
p = numpy.random.permutation(len(a))
return a[p], b[p]
Cela se traduira par la création de tableaux séparés mélangés à l'unisson.
X = np.array([[1., 0.], [2., 1.], [0., 0.]])
y = np.array([0, 1, 2])
from sklearn.utils import shuffle
X, y = shuffle(X, y, random_state=0)
Pour en savoir plus, voir http://scikit-learn.org/stable/modules/generated/sklearn.utils.shuffle.html
Solution très simple:
randomize = np.arange(len(x))
np.random.shuffle(randomize)
x = x[randomize]
y = y[randomize]
les deux tableaux x, y sont maintenant tous les deux brassés de manière aléatoire de la même manière
James a écrit en 2015 un sklearn solution qui est utile. Mais il a ajouté une variable d'état aléatoire, ce qui n'est pas nécessaire. Dans le code ci-dessous, l'état aléatoire de numpy est automatiquement supposé.
X = np.array([[1., 0.], [2., 1.], [0., 0.]])
y = np.array([0, 1, 2])
from sklearn.utils import shuffle
X, y = shuffle(X, y)
Mélangez un nombre quelconque de matrices ensemble, sur place, en utilisant uniquement NumPy.
import numpy as np
def shuffle_arrays(arrays, set_seed=-1):
"""Shuffles arrays in-place, in the same order, along axis=0
Parameters:
-----------
arrays : List of NumPy arrays.
set_seed : Seed value if int >= 0, else seed is random.
"""
assert all(len(arr) == len(arrays[0]) for arr in arrays)
seed = np.random.randint(0, 2**(32 - 1) - 1) if set_seed < 0 else set_seed
for arr in arrays:
rstate = np.random.RandomState(seed)
rstate.shuffle(arr)
Et peut être utilisé comme ça
a = np.array([1, 2, 3, 4, 5])
b = np.array([10,20,30,40,50])
c = np.array([[1,10,11], [2,20,22], [3,30,33], [4,40,44], [5,50,55]])
shuffle_arrays([a, b, c])
Quelques points à noter:
Après la lecture aléatoire, les données peuvent être fractionnées à l'aide de np.split
ou référencé à l'aide de tranches - en fonction de l'application.
vous pouvez faire un tableau comme:
s = np.arange(0, len(a), 1)
puis mélangez-le:
np.random.shuffle(s)
maintenant, utilisez ceci comme argument de vos tableaux. les mêmes arguments mélangés renvoient les mêmes vecteurs mélangés.
x_data = x_data[s]
x_label = x_label[s]
from np.random import permutation
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data #numpy array
y = iris.target #numpy array
# Data is currently unshuffled; we should shuffle
# each X[i] with its corresponding y[i]
perm = permutation(len(X))
X = X[perm]
y = y[perm]
Une façon de procéder au brassage sur place pour les listes connectées consiste à utiliser une graine (elle peut être aléatoire) et à utiliser numpy.random.shuffle pour effectuer le brassage.
# Set seed to a random number if you want the shuffling to be non-deterministic.
def shuffle(a, b, seed):
np.random.seed(seed)
np.random.shuffle(a)
np.random.seed(seed)
np.random.shuffle(b)
C'est ça. Cela mélangera a et b exactement de la même manière. Cela se fait également sur place, ce qui est toujours un avantage.
def shuffle(a, b, seed):
Rand_state = np.random.RandomState(seed)
Rand_state.shuffle(a)
Rand_state.seed(seed)
Rand_state.shuffle(b)
Lorsque vous l'appelez, transmettez simplement une graine pour alimenter l'état aléatoire:
a = [1,2,3,4]
b = [11, 22, 33, 44]
shuffle(a, b, 12345)
Sortie:
>>> a
[1, 4, 2, 3]
>>> b
[11, 44, 22, 33]
Edit: code fixe pour ré-ensemencer l'état aléatoire
Il existe une fonction bien connue qui peut gérer ceci:
from sklearn.model_selection import train_test_split
X, _, Y, _ = train_test_split(X,Y, test_size=0.0)
Si vous définissez test_size sur 0, vous éviterez les fractionnements et vous donnerons des données mélangées. Bien qu'il soit généralement utilisé pour séparer les données de train et de test, il les mélange également.
De documentation
Diviser des tableaux ou matrices en trains aléatoires et tester des sous-ensembles
Utilitaire rapide qui encapsule la validation d'entrée et les actions suivantes (ShuffleSplit (). Split (X, y)) et l'application permettant de saisir des données en un seul appel pour le fractionnement (et éventuellement le sous-échantillonnage) des données dans un doubleur.
Disons que nous avons deux tableaux: a et b.
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
b = np.array([[9,1,1],[6,6,6],[4,2,0]])
On peut d'abord obtenir des index de lignes en permutant la première dimension
indices = np.random.permutation(a.shape[0])
[1 2 0]
Ensuite, utilisez l'indexation avancée. Ici, nous utilisons les mêmes indices pour mélanger les deux tableaux à l’unisson.
a_shuffled = a[indices[:,np.newaxis], np.arange(a.shape[1])]
b_shuffled = b[indices[:,np.newaxis], np.arange(b.shape[1])]
Ceci est équivalent à
np.take(a, indices, axis=0)
[[4 5 6]
[7 8 9]
[1 2 3]]
np.take(b, indices, axis=0)
[[6 6 6]
[4 2 0]
[9 1 1]]
J'ai étendu random.shuffle () de python pour prendre un deuxième argument:
def shuffle_together(x, y):
assert len(x) == len(y)
for i in reversed(xrange(1, len(x))):
# pick an element in x[:i+1] with which to exchange x[i]
j = int(random.random() * (i+1))
x[i], x[j] = x[j], x[i]
y[i], y[j] = y[j], y[i]
De cette façon, je peux être sûr que le brassage a lieu sur place et que la fonction n’est pas trop longue ni compliquée.
Avec un exemple, voici ce que je fais:
combo = []
for i in range(60000):
combo.append((images[i], labels[i]))
shuffle(combo)
im = []
lab = []
for c in combo:
im.append(c[0])
lab.append(c[1])
images = np.asarray(im)
labels = np.asarray(lab)
Si vous souhaitez éviter de copier des tableaux, je vous suggère alors de ne pas générer une liste de permutation, mais de parcourir tous les éléments du tableau et de les échanger de manière aléatoire vers un autre emplacement du tableau.
for old_index in len(a):
new_index = numpy.random.randint(old_index+1)
a[old_index], a[new_index] = a[new_index], a[old_index]
b[old_index], b[new_index] = b[new_index], b[old_index]
Ceci implémente l'algorithme de mélange de Knuth-Fisher-Yates.