Eu tenho duas matrizes numpy de formas diferentes, mas com o mesmo comprimento (dimensão inicial). Quero embaralhar cada um deles, de modo que os elementos correspondentes continuem a corresponder - ou seja, embaralhe-os em uníssono com relação aos seus principais índices.
Este código funciona e ilustra meus objetivos:
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
Por exemplo:
>>> 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]))
No entanto, isso parece desajeitado, ineficiente e lento, e exige uma cópia das matrizes - eu prefiro embaralhá-las no lugar, pois elas são muito grandes.
Existe uma maneira melhor de fazer isso? Execução mais rápida e menor uso de memória são meus principais objetivos, mas um código elegante também seria bom.
Um outro pensamento que eu tinha era o seguinte:
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)
Isso funciona ... mas é um pouco assustador, pois vejo pouca garantia de que continuará funcionando - não parece o tipo de coisa que é garantida para sobreviver em uma versão numpy, por exemplo.
Respostas:
Sua solução "assustadora" não me parece assustadora. A chamada
shuffle()
de duas seqüências do mesmo comprimento resulta no mesmo número de chamadas para o gerador de números aleatórios, e esses são os únicos elementos "aleatórios" no algoritmo de reprodução aleatória. Ao redefinir o estado, você garante que as chamadas para o gerador de números aleatórios fornecerão os mesmos resultados na segunda chamada parashuffle()
, para que todo o algoritmo gere a mesma permutação.Se você não gostar disso, uma solução diferente seria armazenar seus dados em uma matriz em vez de duas desde o início, e criar duas visualizações nessa matriz única, simulando as duas matrizes que você tem agora. Você pode usar a matriz única para embaralhar e as visualizações para todos os outros fins.
Exemplo: Vamos assumir as matrizes
a
e ter a seguinteb
aparência:Agora podemos construir uma única matriz contendo todos os dados:
Agora criamos visualizações simulando o original
a
eb
:Os dados de
a2
eb2
são compartilhados comc
. Para embaralhar as duas matrizes simultaneamente, usenumpy.random.shuffle(c)
.No código de produção, você iria, claro, tentar evitar a criação do original
a
eb
em tudo e imediatamente criarc
,a2
eb2
.Esta solução pode ser adaptada ao caso
a
eb
ter diferentes tipos.fonte
numpy.random.shuffle()
opera em seqüências mutáveis arbitrárias, como listas Python ou matrizes NumPy. A forma da matriz não importa, apenas o comprimento da sequência. É muito improvável que isso mude na minha opinião.Você pode usar a indexação de array do NumPy :
Isso resultará na criação de matrizes separadas por uníssono.
fonte
>>> t = timeit.Timer(stmt = "<function>(a,b)", setup = "import numpy as np; a,b = np.arange(4), np.arange(4*20).reshape((4,20))")>>> t.timeit()
e recebi 38 segundos para a versão do OP e 27,5 segundos para a minha, para 1 milhão de chamadas cada.a.shape
é(31925, 405)
eb.shape
é(31925,)
.Para saber mais, consulte http://scikit-learn.org/stable/modules/generated/sklearn.utils.shuffle.html
fonte
Solução muito simples:
as duas matrizes x, y agora são aleatoriamente embaralhadas da mesma maneira
fonte
James escreveu em 2015 uma solução sklearn que é útil. Mas ele adicionou uma variável de estado aleatória, que não é necessária. No código abaixo, o estado aleatório de numpy é automaticamente assumido.
fonte
fonte
Misture aleatoriamente qualquer número de matrizes, no local, usando apenas NumPy.
E pode ser usado assim
Algumas coisas a serem observadas:
Após a reprodução aleatória, os dados podem ser divididos usando
np.split
ou referenciados usando fatias - dependendo do aplicativo.fonte
RandomState
poderia ser usado fora do loop. Veja a resposta defor
loop é se é necessário reatribuir ou reenviar o estado aleatório. Com o número de matrizes sendo passado para uma função de reprodução aleatória que espera ser pequena, eu não esperaria uma diferença de desempenho entre as duas. Mas sim, o rstate pode ser atribuído fora do loop e processado novamente dentro do loop em cada iteração.você pode criar uma matriz como:
embaralhe:
Agora use este s como argumento de suas matrizes. os mesmos argumentos embaralhados retornam os mesmos vetores embaralhados.
fonte
Uma maneira pela qual o embaralhamento no local pode ser feito para listas conectadas é usar uma semente (pode ser aleatória) e usar numpy.random.shuffle para fazer o embaralhamento.
É isso aí. Isso embaralha ambos aeb exatamente da mesma maneira. Isso também é feito no local, o que é sempre uma vantagem.
EDIT, não use np.random.seed () use np.random.RandomState
Ao chamá-lo, basta passar qualquer semente para alimentar o estado aleatório:
Resultado:
Edit: Corrigido código para re-seedear o estado aleatório
fonte
RandomState
muda de estado na primeira chamada ea
eb
não são embaralhadas em uníssono.Há uma função conhecida que pode lidar com isso:
Apenas definir test_size como 0 evitará dividir e fornecer dados aleatórios. Embora seja geralmente usado para dividir dados de trem e teste, eles também são embaralhados.
Da documentação
fonte
Digamos que temos duas matrizes: a e b.
Podemos primeiro obter índices de linha permutando a primeira dimensão
Em seguida, use a indexação avançada. Aqui estamos usando os mesmos índices para embaralhar as duas matrizes em uníssono.
Isso é equivalente a
fonte
Se você quiser evitar copiar matrizes, sugiro que, em vez de gerar uma lista de permutações, você percorra todos os elementos da matriz e troque aleatoriamente para outra posição na matriz
Isso implementa o algoritmo de reprodução aleatória de Knuth-Fisher-Yates.
fonte
len(a)
porreversed(range(1, len(a)))
. Mas não será muito eficiente de qualquer maneira.Parece uma solução muito simples:
fonte
Com um exemplo, é isso que estou fazendo:
fonte
combo = zip(images, labels); shuffle(combo); im, lab = zip(*combo)
, apenas mais lento. Como você está usando o Numpy de qualquer maneira, uma solução ainda mais rápida seria compactar as matrizes usando o Numpycombo = np.c_[images, labels]
, embaralhar e descompactar novamenteimages, labels = combo.T
. Supondo quelabels
eimages
sejam matrizes Numpy unidimensionais do mesmo comprimento, essa será facilmente a solução mais rápida. Se eles são multidimensionais, veja minha resposta acima.Estendi o random.shuffle () do python para pegar um segundo argumento:
Dessa forma, posso ter certeza de que o embaralhamento acontece no local e a função não é muito longa ou complicada.
fonte
Basta usar
numpy
...Primeiro mescle as duas matrizes de entrada 1D array é labels (y) e 2D array é data (x) e as embaralha com o
shuffle
método NumPy . Finalmente divida-os e volte.fonte