Numpy: ENH: Alternativa para `random.shuffle`, com um argumento` axis`.

Criado em 11 out. 2014  ·  35Comentários  ·  Fonte: numpy/numpy

Seria bom ter uma alternativa para numpy.random.shuffle que aceite um argumento axis e que embaralhe independentemente as fatias unidimensionais. Aqui está uma implementação que chamarei de disarrange . Funciona, mas seria bom ter uma implementação C mais eficiente.

def disarrange(a, axis=-1):
    """
    Shuffle `a` in-place along the given axis.

    Apply numpy.random.shuffle to the given axis of `a`.
    Each one-dimensional slice is shuffled independently.
    """
    b = a.swapaxes(axis, -1)
    # Shuffle `b` in-place along the last axis.  `b` is a view of `a`,
    # so `a` is shuffled in place, too.
    shp = b.shape[:-1]
    for ndx in np.ndindex(shp):
        np.random.shuffle(b[ndx])
    return

Exemplo:

In [156]: a = np.arange(20).reshape(4,5)

In [157]: a
Out[157]: 
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])

In [158]: disarrange(a, axis=-1)

In [159]: a
Out[159]: 
array([[ 2,  0,  4,  3,  1],
       [ 8,  6,  7,  9,  5],
       [11, 14, 13, 10, 12],
       [19, 18, 16, 17, 15]])

In [160]: a = np.arange(20).reshape(4,5)

In [161]: disarrange(a, axis=0)

In [162]: a
Out[162]: 
array([[ 5, 11,  7, 13, 14],
       [ 0,  6,  2,  3,  4],
       [10,  1, 17, 18, 19],
       [15, 16, 12,  8,  9]])

Esta solicitação foi motivada por esta pergunta em stackoverflow: http://stackoverflow.com/questions/26310346/quickly-calculate-randomized-3d-numpy-array-from-2d-numpy-array/

01 - Enhancement numpy.random

Comentários muito úteis

Alguma novidade sobre isso? Fiquei surpreso que essa funcionalidade não exista. Por enquanto, estou usando np.apply_along_axis com np.random.permutation como uma solução alternativa.

Todos 35 comentários

Não vejo por que isso precisaria ser uma alternativa - por que não apenas adicionar um
argumento do eixo para embaralhar? Padronizando para Nenhum, como np.sum.

No sábado, 11 de outubro de 2014 às 21h36, Warren Weckesser [email protected]
escreveu:

Seria bom ter uma alternativa para numpy.random.shuffle que
aceita um argumento do eixo, e que embaralha independentemente o
fatias unidimensionais. Aqui está uma implementação que chamarei de disarrange.
Funciona, mas seria bom ter uma implementação C mais eficiente.

def disarrange (a, eixo = -1):
"" "
Embaralhe a no local ao longo do eixo fornecido.

Apply numpy.random.shuffle to the given axis of `a`.
Each one-dimensional slice is shuffled independently.
"""
b = a.swapaxes(axis, -1)
# Shuffle `b` in-place along the last axis.  `b` is a view of `a`,
# so `a` is shuffled in place, too.
shp = b.shape[:-1]
for ndx in np.ndindex(shp):
    np.random.shuffle(b[ndx])
return

Exemplo:

Em [156]: a = np.arange (20). Remodelar (4,5)

Em [157]: a
Fora [157]:
matriz ([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])

Em [158]: desorganizar (a, eixo = -1)

Em [159]: a
Fora [159]:
matriz ([[2, 0, 4, 3, 1],
[8, 6, 7, 9, 5],
[11, 14, 13, 10, 12],
[19, 18, 16, 17, 15]])

Em [160]: a = np.arange (20). Remodelar (4,5)

Em [161]: desorganizar (a, eixo = 0)

Em [162]: a
Fora [162]:
matriz ([[5, 11, 7, 13, 14],
[0, 6, 2, 3, 4],
[10, 1, 17, 18, 19],
[15, 16, 12, 8, 9]])

Esta solicitação foi motivada por esta pergunta sobre stackoverflow:
http://stackoverflow.com/questions/26310346/quickly-calculate-randomized-3d-numpy-array-from-2d-numpy-array/

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/numpy/numpy/issues/5173.

Nathaniel J. Smith
Pesquisador de pós-doutorado - Informática - Universidade de Edimburgo
http://vorpus.org

O comportamento atual de shuffle não é realmente como axis=None . Ele trata seu argumento como uma sequência unidimensional.

In [181]: a = np.arange(20).reshape(4,5)

In [182]: np.random.shuffle(a)

In [183]: a
Out[183]: 
array([[ 0,  1,  2,  3,  4],
       [15, 16, 17, 18, 19],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])

Você pode interpretar isso como sendo axis=0 , mas o recurso que falta é o embaralhamento independente das fatias 1-D.

Para uma matriz 2-D, você pode embaralhar a.T para emular axis=1 , mas isso não o deixará embaralhado de forma independente:

In [184]: a = np.arange(20).reshape(4,5)

In [185]: np.random.shuffle(a.T)

In [186]: a
Out[186]: 
array([[ 4,  1,  0,  3,  2],
       [ 9,  6,  5,  8,  7],
       [14, 11, 10, 13, 12],
       [19, 16, 15, 18, 17]])

Em disarrange , eu esperaria que axis=None agisse como np.random.shuffle(a.flat) .

Estaria tudo bem se o embaralhamento alternativo fosse implementado adicionando argumentos apropriados a shuffle que controlam como ele se comporta, mas eu não tenho uma proposta para essa API.

Talvez dois argumentos possam ser adicionados a shuffle : axis e independent (ou algo parecido). A nova assinatura seria:

def shuffle(a, independent=False, axis=0)

Quando independent é False, ele age como o shuffle atual. Quando verdadeiro, ele age como disarrange .

Oh, ugh, eu apenas presumi que era mais consistente com o análogo
funciona como sort :-(. Seria melhor se este tipo de
o embaralhamento de fatias foi escrito como idx = arange (...); embaralhar (idx);
multi_dim_array [idx, ...]; mas ninguém me perguntou :-)

Recebo +1 em uma versão do shuffle que tem convenções de chamada que correspondem
np.sort, embora, como regra, devamos verificar a lista. Eles podem ter
sugestões sobre questões cruciais, como o melhor nome também :-)

(Talvez "embaralhar"?)

No sábado, 11 de outubro de 2014 às 22h31, Warren Weckesser < [email protected]

escreveu:

O comportamento atual do shuffle não é realmente como axis = None. Trata
seu argumento como uma sequência unidimensional.

Em [181]: a = np.arange (20). Remodelar (4,5)

Em [182]: np.random.shuffle (a)

Em [183]: a
Fora [183]:
matriz ([[0, 1, 2, 3, 4],
[15, 16, 17, 18, 19],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])

Você pode interpretar isso como sendo eixo = 0, mas o recurso que falta é o
embaralhamento independente das fatias 1-D.

Para uma matriz 2-D, você pode embaralhar aT para emular o eixo = 1, mas isso não
você obterá embaralhamento independente:

Em [184]: a = np.arange (20). Remodelar (4,5)

Em [185]: np.random.shuffle (aT)

Em [186]: a
Fora [186]:
matriz ([[4, 1, 0, 3, 2],
[9, 6, 5, 8, 7],
[14, 11, 10, 13, 12],
[19, 16, 15, 18, 17]])

Em desordem, eu esperaria que axis = None agisse como
np.random.shuffle (a.flat).

Não haveria problema se o embaralhamento alternativo fosse implementado adicionando
argumentos apropriados para embaralhar que controlam como ele se comporta, mas eu não
tem uma proposta para essa API.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/numpy/numpy/issues/5173#issuecomment -58765220.

Nathaniel J. Smith
Pesquisador de pós-doutorado - Informática - Universidade de Edimburgo
http://vorpus.org

Ah, descrever o comportamento desejado como um análogo de sort é uma boa ideia.

Oh, ugh, eu apenas presumi que era mais consistente com funções análogas como sort

Eu também fiquei surpreso e, com base nos comentários sobre a questão stackoverflow, pelo menos dois outros usuários entorpecidos experientes ficaram surpresos. Vou iniciar uma discussão na lista de e-mails.

Eu acho que se o usuário comum está entendendo errado, então vale a pena
mencionando a outra opção - nós _podemos_ adicionar um argumento para escolher entre
os dois comportamentos, que começam com o padrão do comportamento atual,
e em algum ponto mudar o padrão depois de muito FutureWarning e gritar
para alertar as pessoas. Mas essa é uma transição feia de se fazer ...

No sábado, 11 de outubro de 2014 às 23h, Warren Weckesser < [email protected]

escreveu:

Oh, ugh, eu apenas presumi que era mais consistente com o análogo
funções como classificar

Eu também fiquei surpreso e com base nos comentários sobre o stackoverflow
questão, pelo menos dois outros usuários entorpecidos experientes ficaram surpresos. eu vou
iniciar uma discussão na lista de discussão.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/numpy/numpy/issues/5173#issuecomment -58766099.

Nathaniel J. Smith
Pesquisador de pós-doutorado - Informática - Universidade de Edimburgo
http://vorpus.org

Eles também podem ter sugestões sobre questões cruciais, como o melhor nome.

Precisamos de uma função chamada Sue.

Só queria marcar com +1 esse recurso, como eu também esperava que ele existisse, de forma análoga à classificação (eixo = N). Houve alguma decisão tomada na lista de mala direta?

O tópico da lista de discussão está aqui:
http://thread.gmane.org/gmane.comp.python.numeric.general/59014

Isso seria muito útil!

Eu também gostaria disso!

De acordo com https://stackoverflow.com/a/35647011/3401634 , para matrizes multidimensionais X

np.random.shuffle(X)

é o mesmo que

np.take(X, np.random.permutation(X.shape[0]), axis=0, out=X)

Então, por que não implementar

np.random.shuffle(X, axis=axis)

Como

np.take(X, np.random.permutation(X.shape[axis]), axis=axis, out=X)

com o padrão axis=0 ?

Alguma novidade sobre isso? Fiquei surpreso que essa funcionalidade não exista. Por enquanto, estou usando np.apply_along_axis com np.random.permutation como uma solução alternativa.

Isso pode ser fechado agora por causa de # 13829?

(Observe que enquanto trabalhava nos exemplos aqui, encontrei um bug no novo código aleatório. A seguir, estou usando a correção proposta em https://github.com/numpy/numpy/pull/14662, que foi fundido.)

@wkschwartz , a mudança em # 13829 é útil, mas não é o aprimoramento solicitado aqui. O eixo adicionado em # 13829 ainda trata a matriz como uma sequência 1-d a ser embaralhada. O novo argumento do eixo permite ao usuário especificar qual eixo é visto como o eixo 1-d, mas não faz um embaralhamento independente dentro do eixo.

Por exemplo,

In [1]: import numpy as np                                                      

In [2]: rng = np.random.default_rng()                                           

In [3]: x = np.arange(20).reshape(2, 10)                                        

In [4]: x                                                                       
Out[4]: 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])

In [5]: rng.shuffle(x, axis=1)                                                  

In [6]: x                                                                       
Out[6]: 
array([[ 5,  9,  6,  4,  7,  0,  3,  2,  1,  8],
       [15, 19, 16, 14, 17, 10, 13, 12, 11, 18]])

Você pode ver que as linhas não foram embaralhadas de forma independente . As colunas foram reorganizadas, mas os valores em cada coluna são os mesmos.

O comportamento solicitado nesta edição é embaralhar independentemente, como no código disarrange que dei acima:

In [10]: x = np.arange(20).reshape(2, 10)                                       

In [11]: x                                                                      
Out[11]: 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])

In [12]: disarrange(x, axis=1)                                                  

In [13]: x                                                                      
Out[13]: 
array([[ 4,  3,  7,  8,  0,  6,  5,  2,  9,  1],
       [12, 15, 19, 17, 18, 14, 10, 13, 11, 16]])

Eu gostaria de colocar isso de novo, talvez também para a reunião de quarta-feira. Acabamos de adicionar capacidades dimensionais superiores a choice e permutation e no 1.18 até mesmo o argumento do eixo (portanto, é totalmente novo).

Todos eles usam a lógica shuffle atual que é shuffle the subarrays along this axis , em vez de shuffle along (individual) axis que eu acho que é indiscutivelmente o que deveria acontecer. Ou seja, ele embaralha "ao longo" em vez de "ao longo" ou dentro do eixo fornecido.

Mas, em quase todas as ocasiões, axis significa ao longo do eixo em NumPy, com muito poucas exceções, como apply_over_axes que tem o "sobre" no nome. Portanto, serei tão ousado e reivindicarei que mesmo renomear o argumento para over_axis=0 seria melhor evitar confusão! Especialmente para números aleatórios, onde o embaralhamento incorreto pode ser muito difícil de notar.

Conforme observado na referência cruzada do github acima, tenho um PR de trabalho em andamento em https://github.com/numpy/numpy/pull/15121. Recebi um bom feedback depois de enviar o PR, mas não tive tempo para resolver todos os problemas que foram levantados.

@WarrenWeckesser que é legal, o que me preocupa mais urgentemente é que expandimos o significado de over na nova API e recentemente nisso.
E eu estou me perguntando se não devemos retirar isso parcialmente, por exemplo, pelo menos renomeando o argumento axis . Ou até mesmo se livrar do comportamento multidimensional completamente de novo no momento ...

Provavelmente estou exagerando agora, porque estou um pouco irritado por não ter percebido isso ou não ter pensado nisso antes ... Mas, honestamente, acho que a lógica atual é muito perigosa. É fácil perder que ele não fornece o esperado ao longo significado. E não é o significado que np.sort usa.

@seberg , obrigado por cutucar este problema. Acho que ainda precisamos chegar a um consenso sobre a API. Vou tentar dar um breve resumo das ideias anteriores aqui. Seguirei sua convenção de usar "over" e "along" para duas interpretações de axis . Não sei se podemos, neste ponto, desfazer totalmente a interpretação existente "ao longo" de axis para shuffle e permutation , mas acho que muitas pessoas ficaria feliz se descobríssemos que podemos. :)

No final da discussão da lista de e-mails há vários anos, acabei pensando que a solução era não mudar as APIs de shuffle e permutation e, em vez disso, introduzir dois novos métodos que randomizaram ao longo do eixo em vez de sobre ele. Um método funcionaria no local e o outro retornaria uma cópia. Minha preferência na época era pelos nomes permute e permuted , mas havia algumas objeções a esses nomes. No PR de dezembro passado, chamei-os de randomly_permute e randomly_permuted , mas esses nomes devem ser considerados substitutos. Antes de tentar decidir sobre esses nomes, temos que decidir se adicionar duas novas funções é a abordagem correta. A partir daqui, para resumir, vou me referir aos novos métodos propostos como permute e permuted .

Com as novas funções, teríamos os seguintes Generator métodos relacionados:

meaning    operate     return
of axis    in-place     copy
-------    --------  -----------
"over"     shuffle   permutation
"along"    permute   permuted

(Os métodos que operam "sobre" o eixo, shuffle e permutation , já existem.)

Em vez de dois novos métodos, foi sugerido que temos apenas um, com um parâmetro que controla o comportamento in-loco vs. cópia. Duas sugestões foram apresentadas para isso:

(a) Adicione um parâmetro out . Para trabalhar no local, passe a matriz de entrada como out . Se out não for fornecido, devolva uma cópia embaralhada.
(b) Adicione um sinalizador booleano como copy ou inplace , que especifica o comportamento desejado.

A principal alternativa para criar novos métodos é adicionar um novo parâmetro aos métodos existentes que muda a forma como axis é interpretado. Antes de listá-los, reiterarei um comentário que Robert Kern fez no tópico da lista de discussão sobre como o argumento extra provavelmente será usado na prática (aqui se referindo ao parâmetro independent mostrado abaixo):

Parece-me uma razão perfeitamente boa para ter dois métodos em vez de
1. Não consigo imaginar quando não estaria usando um verdadeiro ou falso literal
para isso, então realmente deve haver dois métodos diferentes.

( Digressão editorial : inevitavelmente em discussões como esta, surge a questão de aumentar o namespace (neste caso, o namespace Generator ) (às vezes referido como "poluição do namespace"). Vamos concordar que, sim, todos se as coisas forem iguais, um namespace menor é melhor. Mas, como a maioria das decisões de design de API, há compensações a serem consideradas. Se mantivermos o namespace menor, mas criarmos métodos com APIs complicadas ou excessivamente complicadas, não estaremos vencendo.)

Tendo dito tudo isso, aqui estão dois acréscimos à assinatura existente de shuffle que foram sugeridos.

(1) shuffle(x, axis=0, independent=False) : o sinalizador booleano independent determina como axis é interpretado: False -> "over", True -> "along". (Provavelmente, há nomes melhores do que independent .)
(2) shuffle(x, axis=0, iaxis=???) : Um segundo argumento, iaxis , fornece o eixo para o comportamento "ao longo". (Como isso interage com axis precisa de uma especificação clara. Presumivelmente, dar um valor para iaxis faz com que axis seja ignorado.)

Acho que cobri todas as várias ideias de API que surgiram. Se alguém souber de outras pessoas, avise-nos.

Estou feliz em aumentar a API aqui. Não tenho certeza se há muitos motivos para ser contra:

  • Provavelmente podemos concordar que é um útil
  • Não há uma boa maneira de conseguir isso com os recursos existentes
  • usar um kwarg para uma mudança de comportamento total não parece um padrão normal, acho que Rober Kern estava completamente certo nisso.

Suponho que o que está acontecendo aqui é que shuffle e permutation (e talvez choice ) podem ser comparados a uma operação de indexação (ou seja, take ), que usa o mesmo significado para axis . E a razão pela qual parece um pouco estranho para mim, é provavelmente a desvantagem desta definição que nunca pode generalizar para ND ao contrário de funções típicas com reconhecimento de array (até mesmo a própria indexação o faz se você usar arr[..., index] . É isso generalize para pilhas de matrizes e faça a mesma operação de antes para cada uma).
Observe que take_along_axis fornece o significado generalizável de ND "junto" para take para ND corretamente (mesmo que pareça complicado). apply_along_axis e apply_over_axis são de onde obtive o "over", embora não tenha certeza de que "over" seja a palavra certa ...

Acho que permutation (que não é facilmente alterável, mas deveria ser shuffled ) é o verdadeiro outlier aqui. Era shuffle - shuffled , permute - permuted então eu acho que as coisas começaram a parecer bem claras e razoáveis. Alguém está disposto a adicionar shuffled e iniciar uma depreciação em permutation ? permutation também não é muito consistente em seu comportamento com itertools.permutations , FWIW.

Eu realmente acho que permutation , permute , permuted é um triplo confuso de nomes com sons semelhantes com comportamentos diferentes. Seria bom (possivelmente a longo prazo) evitar isso.

Embora pareça simples estender a API existente, acho que o ponto do @rkern sobre não ter palavras-chave que mudem radicalmente o comportamento é o melhor caminho.

Suponho que para in-loco vs. não-in-loco, temos a grafia alternativa out= em NumPy. Mas, uma vez que o shuffle está implementado, isso não é uma solução e o shuffle é bom. Poderia ser permuted (ou seja, permuted(arr, out=arr) significa o mesmo que permute(arr) , exceto - ao contrário do embaralhamento - que será convertido em ndarray ).
Em qualquer caso, gosto do plano de descontinuar permutation em favor de shuffled para limpar o novo namespace!

Estou voltando a este problema (e ao PR relacionado em https://github.com/numpy/numpy/pull/15121).

Quando criei o problema original e tentei descrever o problema com a API shuffle atual, foi apontado que uma maneira de explicar o problema é que a maioria das pessoas espera o argumento axis de shuffle para agir da mesma forma que o argumento axis de sort . A analogia com sort é muito boa, então pode ser útil também observar como lidamos com a questão da operação no local versus cópia para classificação. A função numpy.sort() aceita um argumento do tipo array e retorna uma cópia classificada. Para classificação no local, usa-se o método ndarray sort() . Por ser um método em um ndarray existente, a operação no local é clara. Em gh-15121, o argumento da função no local que permuta aleatoriamente seu argumento deve ser um ndarray, e não um tipo de array arbitrário. Caso contrário, a função terá que fazer toda a descoberta de forma que np.array faz, e também rejeitar entradas que se revelem imutáveis ​​(por exemplo, não podemos fazer um embaralhamento no local de [(1, 2, 3, 4), (5, 6, 7, 8)] )

Seria ótimo se pudéssemos realmente replicar a API sort , com uma função que retorna uma cópia embaralhada e um método ndarray que embaralha no local, mas não acho que adicionar tal um método para a classe ndarray tem qualquer chance de ser aceito.

e um ndarray _method_ que embaralha no local, mas não acho que adicionar tal método à classe ndarray tenha qualquer chance de ser aceito.

Sem um gerador singleton, acho que isso seria impossível de alcançar.

@bashtage escreveu

Acho que permutation (que não é facilmente alterável, mas deveria ser shuffled ) é o verdadeiro outlier aqui. [Se] fosse shuffle-shuffled , permute-permuted então acho que as coisas começaram a parecer bem claras e razoáveis. Alguém está disposto a adicionar shuffled e iniciar uma depreciação em permutation ?

É para isso que a discussão da lista de e-mails (mais ou menos) convergiu em 2014. Aqui está um link para a sugestão de Nathaniels: https://mail.python.org/pipermail/numpy-discussion/2014-October/071364.html

Seu scramble[d] é o que chamei de randomly_permute[d] em https://github.com/numpy/numpy/pull/15121.

Se adicionarmos shuffled como um substituto para permutation , e chamarmos os novos métodos que operam ao longo de um eixo permute[d] , a tabela de funções relacionadas é

meaning    operate
of axis    in-place   return copy
-------    ---------  -----------
"over"     shuffle    shuffled
"along"    permute    permuted

que tem uma boa consistência. Nesta versão da API, nenhum dos métodos tem um parâmetro out .

Em https://github.com/numpy/numpy/pull/15121 , recentemente adicionei outro método, com o nome desajeitado e obviamente temporário permuted_with_out que demonstra como o argumento out pode ser usava. Se usarmos um parâmetro out e ficarmos com os nomes dos métodos existentes shuffle e permutation , a tabela ficará

meaning    operate
of axis    in-place                           return copy
-------    ---------------------------------  --------------------
"over"     shuffle(x, axis)                   permutation(x, axis)
"along"    permuted_with_out(x, axis, out=x)  permuted_with_out(x, axis)

Mas se vamos introduzir um parâmetro out , devemos ser consistentes e usá-lo em permutation também. E ainda podemos considerar a substituição de permutation por shuffled . E como o novo método shuffled tem um parâmetro out , que permite a operação in-loco, shuffle se torna redundante e pode ser descontinuado junto com permutation . Então, mudando para os nomes "legais" de shuffled e permuted , a mesa é

    meaning    operate
    of axis    in-place                  return copy
    -------    ------------------------  -----------------
    "over"     shuffled(x, axis, out=x)  shuffled(x, axis)
    "along"    permuted(x, axis, out=x)  permuted(x, axis)

Observe que o parâmetro out não serve apenas para operar no local. Ele permite que um array de saída seja reutilizado, evitando potencialmente a criação de um array temporário. Esta é uma vantagem desta API sobre a API shuffle/shuffled/permute/permuted , mas não tenho certeza de quão significativa essa vantagem realmente é. A desvantagem desta API é a depreciação de dois métodos, shuffle e permutation . Essas podem ser depreciações "leves" por um tempo (ou seja, não enfatizam seu uso nos documentos, mas não adicionam um aviso de descontinuação por um tempo) para diminuir o impacto imediato.

Este é o meu resumo dos dois principais candidatos à mudança. Temos a versão shuffle/shuffled/permute/permuted , ou a versão com shuffled/permuted com um parâmetro out . Se, em 2014, alguém tivesse entrado em ação para implementar as mudanças que foram discutidas, provavelmente já teríamos a versão shuffle/shuffled/permute/permuted . Mas a versão que usa out tem algumas vantagens (pequenas? Insignificantes?): Dois nomes em vez de quatro, e out potencialmente permite que um usuário tenha menos variáveis ​​temporárias. Eu ficaria feliz com qualquer um.

O que as pessoas pensam?

Dos três cenários que você listou, em ordem, eu os classificaria com 1, 3 e bem atrás de 2. As 2 permutações que estão fazendo coisas radicalmente diferentes parecem ser uma grande fonte de confusão. Minha preferência pessoal é evitar o uso obrigatório de out para acessar um recurso; Sempre penso nisso como uma escolha de desempenho que pode fazer sentido em alguns cenários. Eu realmente não gostaria de ensinar os alunos a usar apenas para acessar um recurso. Eu também presumiria que no caso 3 x = shuffled(x, axis, out=x) também return x vez de return None , de modo que, enquanto estiver no lugar, alguém pode acabar com x aparecendo 3 vezes.

Minha preferência pessoal é evitar o uso obrigatório de out para acessar um recurso; Sempre penso nisso como uma escolha de desempenho que pode fazer sentido em alguns cenários.

Mas embaralhar _é_ uma escolha de desempenho, não é?

Mas embaralhar _é_ uma escolha de desempenho, não é?

No local também pode ser uma escolha de estilo de codificação, quando disponível. Talvez confuso e sujeito a erros.

Minha opinião pessoal é que quando f (x, out = x) sempre parece um pouco mágico, já que às vezes é usado como uma forma nada óbvia de conseguir algo rápido. f (x, inplace = True), apesar de não parecer com qualquer outra coisa, parece muito mais claro (parece um pouco com um antigo padrão de pandas que foi quase todo removido).

Verdade, mas é uma escolha de estilo de codificação que em NumPy parece tipicamente escrita usando out=... (a menos que você esteja usando um operador local ou um método). Ou talvez seja uma escolha de estilo de codificação que o NumPy não tenta ativamente tornar fácil na maioria dos casos atualmente ...

Eu admito que é um pouco mágico e um inplace= kwarg pode ser menos mágico, mas também sem precedência real? E não tenho certeza se o principal motivo pelo qual parece menos mágico é que o shuffle no local está no centro do algoritmo aqui. Os detalhes do algoritmo não devem importar muito para a maioria dos alunos e, no final, usar out= também protege aproximadamente uma única cópia + a largura de banda da memória associada, e é comparável aos ufuncs. (Justo, também para ufuncs out=input é talvez um tanto mágico, mas sua magia comum e um padrão conhecido - para usuários avançados.)

Embora seja um pouco tedioso de escrever e um pouco menos rápido de ler, np.shuffled(x, out=x) parece muito claro quanto ao comportamento. A parte não óbvia parece apenas o impacto no desempenho, que para mim parece ser um problema reservado para os usuários avançados se preocupar.

Uma pergunta hipotética para aqueles que defendem o uso de out : se não tivéssemos as funções existentes numpy.sort e ndarray.sort , e estivéssemos adicionando uma função de classificação agora, o API preferencial numpy.sorted(a, axis=-1, kind=None, order=None, out=None) (sem necessidade de implementar o método ndarray.sort para classificação no local)?

ndarray.sort é modelado após list.sort , então provavelmente é uma escolha de API sensata de qualquer maneira. Dito isso, eu teria sido a favor de np.sort não existir e, em vez disso, np.sorted(..., out=...) .

Sim, acho que np.sort deve ser nomeado np.sorted (assim como sorted() do python, afinal). Uma vez que apenas o método tem o comportamento in-loco, não vejo muita preocupação.

Não tenho certeza sobre o "sem necessidade de implementar o método ndarray.sort ". Não vejo nada de errado com o método (ou seu comportamento no local). A questão sobre o método é apenas se acharmos que é importante o suficiente para fornecer uma abreviatura de método conveniente.
Suponho que também não há nada de errado em ter uma versão de função no local. A versão não local parece melhor para novos usuários e o padrão out= comum o suficiente para mim para que os usuários avançados sejam bem servidos.

Não tenho certeza sobre o "sem necessidade de implementar o método ndarray.sort". Não vejo nada de errado com o método (ou seu comportamento no local).

Isso foi parte do meu experimento mental de API. Não quis dizer que há algo errado com o que temos agora. Eu estava apenas dizendo que, se começarmos do zero - e acrescentarei às minhas premissas hipotéticas que não estamos preocupados em combinar a API Python para listas - então a API preferida para classificação seria numpy.sorted(..., out=...) , e não precisaríamos de mais nada.

Outra questão, não tão hipotética: se usar out é a opção preferida aqui, então, para consistência da API em todo o NumPy, devemos planejar eventualmente adicionar out a numpy.sort , numpy.partition , numpy.argsort , e, bem, tudo o mais que atualmente não o tem?

Sim, na minha opinião adicionar um out= kwarg com a mesma semântica dos ufuncs é uma boa escolha para praticamente todas as funções da API NumPy. Qualquer falta de um argumento out é geralmente um aprimoramento esperando para ser feito (embora, eu acho que na prática pode ser um pequeno aprimoramento e, em casos raros, possivelmente não vale a pena adicionar muita complexidade de código).

Esta página foi útil?
0 / 5 - 0 avaliações