Numpy: ENH: Alternativa a `random.shuffle`, con un argumento` axis`.

Creado en 11 oct. 2014  ·  35Comentarios  ·  Fuente: numpy/numpy

Sería bueno tener una alternativa a numpy.random.shuffle que acepte un argumento axis y que mezcle de forma independiente los cortes unidimensionales. Aquí hay una implementación que llamaré disarrange . Funciona, pero sería bueno tener una implementación de C más 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

Ejemplo:

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 solicitud fue motivada por esta pregunta en stackoverflow: http://stackoverflow.com/questions/26310346/quickly-calculate-randomized-3d-numpy-array-from-2d-numpy-array/

01 - Enhancement numpy.random

Comentario más útil

¿Alguna noticia sobre esto? Me sorprendió que esta funcionalidad no existiera. Por ahora estoy usando np.apply_along_axis con np.random.permutation como solución.

Todos 35 comentarios

No veo por qué esto debería ser una alternativa, ¿por qué no simplemente agregar un
argumento del eje para mezclar? De forma predeterminada a Ninguno, como np.sum.

El sábado, 11 de octubre de 2014 a las 9:36 p. M., Warren Weckesser [email protected]
escribió:

Sería bueno tener una alternativa a numpy.random.shuffle que
acepta un argumento de eje, y que baraja independientemente el
cortes unidimensionales. Aquí hay una implementación que llamaré desorden.
Funciona, pero sería bueno tener una implementación de C más eficiente.

def disarrange (a, eje = -1):
"" "
Mezcla a en el lugar a lo largo del eje dado.

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

Ejemplo:

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

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

En [158]: desordenar (a, eje = -1)

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

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

En [161]: desordenar (a, eje = 0)

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

Esta solicitud fue motivada por esta pregunta en stackoverflow:
http://stackoverflow.com/questions/26310346/quickly-calculate-randomized-3d-numpy-array-from-2d-numpy-array/

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/numpy/numpy/issues/5173.

Nathaniel J. Smith
Investigador postdoctoral - Informática - Universidad de Edimburgo
http://vorpus.org

El comportamiento actual de shuffle no es realmente como axis=None . Trata su argumento como una secuencia 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]])

Puede interpretarlo como axis=0 , pero la característica que falta es la mezcla independiente de los cortes 1-D.

Para una matriz 2-D, puede mezclar a.T para emular axis=1 , pero esto no le dará una mezcla independiente:

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]])

En disarrange , esperaría que axis=None actuara como np.random.shuffle(a.flat) .

Estaría bien si la mezcla alternativa se implementara agregando argumentos apropiados a shuffle que controlan cómo se comporta, pero no tengo una propuesta para esa API.

Quizás se podrían agregar dos argumentos a shuffle : axis y independent (o algo por el estilo). La nueva firma sería:

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

Cuando independent es Falso, actúa como el actual shuffle . Cuando es verdadero, actúa como disarrange .

Oh, uf, solo asumí que era más consistente con análogos
funciona como sort :-(. Sería mejor si este tipo de
barajar-de-rebanadas se escribieron como idx = arange (...); barajar (idx);
multi_dim_array [idx, ...]; pero nadie me preguntó :-)

Soy +1 en una versión de Shuffle que tiene convenciones de llamadas que coinciden
np.sort, aunque como regla deberíamos comprobar con la lista. Ellos pueden tener
sugerencias sobre temas cruciales como el mejor nombre también :-)

(¿Quizás "revolver"?)

El sábado 11 de octubre de 2014 a las 10:31 p.m., Warren Weckesser < [email protected]

escribió:

El comportamiento actual de la reproducción aleatoria no es realmente como axis = None. Trata
su argumento como una secuencia unidimensional.

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

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

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

Puede interpretarlo como eje = 0, pero la característica que falta es la
barajado independiente de los cortes 1-D.

Para una matriz 2-D, puede mezclar aT para emular el eje = 1, pero esto no
conseguir que barajes de forma independiente:

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

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

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

En desorden, esperaría que axis = None actuara como
np.random.shuffle (un.flat).

Estaría bien si la mezcla alternativa se implementara agregando
argumentos apropiados para barajar que controlan cómo se comporta, pero no
tener una propuesta para esa API.

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/numpy/numpy/issues/5173#issuecomment -58765220.

Nathaniel J. Smith
Investigador postdoctoral - Informática - Universidad de Edimburgo
http://vorpus.org

Ah, describir el comportamiento deseado como un análogo de sort es una buena idea.

Oh, uf, asumí que era más consistente con funciones análogas como sort

También me sorprendió y, según los comentarios sobre la pregunta de stackoverflow, al menos otros dos usuarios experimentados se sorprendieron. Comenzaré una discusión sobre la lista de correo.

Supongo que si el usuario promedio se está equivocando actualmente, entonces vale la pena
mencionando la otra opción: _podríamos_ agregar un argumento para elegir entre
los dos comportamientos, que comienzan por defecto al comportamiento actual,
y en algún momento cambia el valor predeterminado después de mucho FutureWarning y gritos
para advertir a la gente. Pero esa es una transición fea de hacer ...

El sábado 11 de octubre de 2014 a las 11:00 p.m., Warren Weckesser < [email protected]

escribió:

Oh, uf, solo asumí que era más consistente con análogos
funciones como ordenar

También me sorprendió, y basándome en los comentarios en el stackoverflow
pregunta, al menos otros dos usuarios experimentados de Numpy se sorprendieron. voy a
iniciar una discusión en la lista de correo.

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/numpy/numpy/issues/5173#issuecomment -58766099.

Nathaniel J. Smith
Investigador postdoctoral - Informática - Universidad de Edimburgo
http://vorpus.org

Es posible que también tengan sugerencias sobre temas cruciales, como el mejor nombre.

Necesitamos una función llamada Sue.

Solo quería hacer +1 en esta característica, ya que yo también esperaba que existiera, de manera análoga a ordenar (eje = N). ¿Se tomó alguna decisión en la lista de correo?

El hilo de la lista de correo está aquí:
http://thread.gmane.org/gmane.comp.python.numeric.general/59014

¡Esto sería realmente útil!

¡Yo también lo agradecería!

Según https://stackoverflow.com/a/35647011/3401634 , para matrices multidimensionales X

np.random.shuffle(X)

es lo mismo que

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

Entonces, ¿por qué no implementar

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

como

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

con el valor predeterminado axis=0 ?

¿Alguna noticia sobre esto? Me sorprendió que esta funcionalidad no existiera. Por ahora estoy usando np.apply_along_axis con np.random.permutation como solución.

¿Se puede cerrar ahora debido a # 13829?

(Tenga en cuenta que mientras trabajaba en los ejemplos aquí, encontré un error en el nuevo código aleatorio. A continuación, estoy usando la solución propuesta en https://github.com/numpy/numpy/pull/14662, que ha sido fusionados.)

@wkschwartz , el cambio en # 13829 es útil, pero no es la mejora solicitada aquí. El eje agregado en # 13829 aún trata la matriz como una secuencia 1-d para ser barajada. El nuevo argumento del eje permite al usuario especificar qué eje se ve como el eje 1-d, pero no realiza una reproducción aleatoria independiente dentro del eje.

Por ejemplo,

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]])

Puede ver que las filas no se han barajado de forma independiente . Las columnas se han reorganizado, pero los valores dentro de cada columna son los mismos.

El comportamiento solicitado en este número es mezclar de forma independiente, como en el código disarrange que di arriba:

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]])

Me gustaría flotar esto nuevamente, tal vez también para la reunión de los miércoles. Acabamos de agregar capacidades dimensionales más altas a choice y permutation y en 1.18 incluso el argumento del eje (por lo tanto, es completamente nuevo).

Todos estos usan la lógica de reproducción aleatoria actual, que es shuffle the subarrays along this axis , en lugar de shuffle along (individual) axis que creo que podría decirse que es lo que debería suceder. Es decir, se baraja "sobre" en lugar de "a lo largo de" o dentro del eje dado.

Pero, en casi todas las ocasiones, axis significa a lo largo del eje en NumPy, con suerte con muy pocas excepciones, como apply_over_axes que tiene el "over" en el nombre. Así que seré tan audaz y afirmaré que incluso cambiar el nombre del argumento a over_axis=0 sería mejor para evitar confusiones. Especialmente para números aleatorios donde la mezcla incorrecta puede ser muy difícil de notar.

Como se señaló en la referencia cruzada de github anterior, tengo un PR en progreso en https://github.com/numpy/numpy/pull/15121. Recibí algunos buenos comentarios después de enviar el RP, pero no he tenido tiempo para abordar todos los problemas que se mencionaron.

@WarrenWeckesser que esté fresco, lo que personalmente estoy más preocupado por urgencia es que hemos ampliado el más sentido a la nueva API y recientemente en eso.
Y me pregunto si no deberíamos retirar eso parcialmente, por ejemplo, al menos cambiando el nombre del argumento axis . O incluso deshacerse del comportamiento multidimensional por completo de nuevo por el momento ...

Probablemente estoy exagerando en este momento, porque estoy un poco molesto porque me perdí esto o no lo pensé hasta el final antes ... Pero honestamente creo que la lógica actual es muy peligrosa. Es fácil pasar por alto que no proporciona la espera a lo largo de un sentido. Y no es el significado que usa np.sort .

@seberg , gracias por axis . No sé si podemos, en este punto, deshacer totalmente la interpretación "continua" existente de axis por shuffle y permutation , pero creo que mucha gente Sería feliz si resulta que podemos. :)

Al final de la discusión de la lista de correo hace varios años, terminé pensando que la solución era no cambiar las API de shuffle y permutation , y en su lugar introducir dos nuevos métodos que se aleatorizaron a lo largo del eje. en lugar de sobre él. Un método funcionaría en el lugar y el otro devolvería una copia. Mi preferencia en ese momento eran los nombres permute y permuted , pero hubo algunas objeciones a esos nombres. En el PR de diciembre pasado, los llamé randomly_permute y randomly_permuted , pero esos nombres deberían considerarse marcadores de posición. Antes de intentar decidir sobre esos nombres, tenemos que decidir si agregar dos funciones nuevas es el enfoque correcto. De aquí en adelante, por brevedad, me referiré a los nuevos métodos propuestos como permute y permuted .

Con las nuevas funciones, tendríamos los siguientes métodos Generator :

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

(Los métodos que operan "sobre" el eje, shuffle y permutation , ya existen).

En lugar de dos métodos nuevos, se ha sugerido que tengamos solo uno, con un parámetro que controla el comportamiento en el lugar frente a la copia. Se han presentado dos sugerencias para esto:

(a) Agregue un parámetro out . Para trabajar en el lugar, pase la matriz de entrada como out . Si no se proporciona out , devuelva una copia aleatoria.
(b) Agregue una bandera booleana como copy o inplace , que especifique el comportamiento deseado.

La principal alternativa a la creación de nuevos métodos es agregar un nuevo parámetro a los métodos existentes que cambia la forma en que se interpreta axis . Antes de enumerarlos, reiteraré un comentario que hizo Robert Kern en el hilo de la lista de correo sobre cómo es probable que se use el argumento adicional en la práctica (aquí haciendo referencia al parámetro independent que se muestra a continuación):

Me parece una razón perfectamente válida para tener dos métodos en lugar de
una. No puedo imaginar cuándo no estaría usando un verdadero o falso literal
para esto, por lo que realmente deberían ser dos métodos diferentes.

( Digresión editorial : inevitablemente en una discusión como esta, surge el problema de hacer crecer el espacio de nombres (en este caso, el espacio de nombres Generator ) (a veces denominado "contaminación del espacio de nombres"). Acordemos que, sí, todos en igualdad de condiciones, un espacio de nombres más pequeño es mejor. Pero, como la mayoría de las decisiones de diseño de API, hay que considerar las compensaciones. Si mantenemos el espacio de nombres más pequeño pero creamos métodos con API incómodas o demasiado complicadas, no estamos ganando).

Habiendo dicho todo eso, aquí hay dos adiciones a la firma existente de shuffle que se han sugerido.

(1) shuffle(x, axis=0, independent=False) : La bandera booleana independent determina cómo se interpreta axis : Falso -> "sobre", Verdadero -> "junto". (Probablemente haya nombres mejores que independent .)
(2) shuffle(x, axis=0, iaxis=???) : Un segundo argumento, iaxis , da el eje para el comportamiento "a lo largo". (La forma en que esto interactúa con axis necesita una especificación clara. Presumiblemente, dar un valor para iaxis hace que axis se ignore).

Creo que he cubierto todas las ideas de API que han surgido. Si alguien conoce a otros, háganoslo saber.

Estoy contento de haber aumentado la API aquí. No estoy seguro de que haya muchas razones para estar en contra:

  • Probablemente podamos estar de acuerdo en que es útil
  • No hay una buena manera de lograrlo con las características existentes.
  • usar kwarg para un cambio de comportamiento total no parece un patrón normal, creo que Rober Kern estaba completamente ahí.

Supongo que lo que está sucediendo aquí es que shuffle y permutation (y tal vez choice ) se pueden comparar con operaciones de indexación (es decir, take ), que usa el mismo significado para axis . Y la razón por la que me parece un poco extraño, es probablemente la desventaja de esta definición que nunca se puede generalizar a ND a diferencia de las funciones típicas de arreglo (incluso la indexación sí lo hace si usa arr[..., index] . generalizar a pilas de matrices y hacer la misma operación que antes para cada una de ellas).
Tenga en cuenta que take_along_axis proporciona el significado "largo" generalizable de ND para take a ND correctamente (incluso si parece complicado). apply_along_axis y apply_over_axis son de donde obtuve el "cambio", aunque no estoy seguro de que "cambio" sea la palabra correcta ...

Encuentro que permutation (que no se puede cambiar fácilmente pero debería ser shuffled ) es el valor atípico real aquí. Fue shuffle - shuffled , permute - permuted entonces creo que las cosas empiezan a verse bastante claras y razonables. ¿Alguien está dispuesto a agregar shuffled y comenzar una depreciación en permutation ? permutation tampoco es muy consistente en su comportamiento con itertools.permutations , FWIW.

Creo que permutation , permute , permuted es un triple confuso de nombres que suenan similares con comportamientos diferentes. Sería bueno (posiblemente a largo plazo) evitar esto.

Si bien parece simple extender la API existente, creo que el punto de @rkern sobre no tener palabras clave que cambien radicalmente el comportamiento es el mejor camino.

Supongo que para en el lugar frente a no en el lugar, tenemos la ortografía alternativa out= en NumPy. Pero dado que la reproducción aleatoria está en el lugar, no es una solución y la reproducción aleatoria es agradable. Podría ser por permuted (es decir, permuted(arr, out=arr) significa lo mismo que permute(arr) , excepto que, a diferencia de la reproducción aleatoria, se convertirá en ndarray ).
En cualquier caso, me gusta el plan de desaprobar permutation a favor de shuffled para limpiar el nuevo espacio de nombres.

Estoy volviendo a este problema (y al PR relacionado en https://github.com/numpy/numpy/pull/15121).

Cuando creé el problema original e intenté describir el problema con la API actual shuffle , se señaló que una forma de explicar el problema es que la mayoría de la gente esperará el argumento axis de shuffle para actuar de la misma manera que el argumento axis de sort . La analogía con sort es bastante buena, por lo que podría ser útil analizar también cómo manejamos el problema de la operación in situ frente a la copia para ordenar. La función numpy.sort() acepta un argumento similar a una matriz y devuelve una copia ordenada. Para la clasificación en el lugar, se usa el método ndarray sort() . Debido a que es un método en un ndarray existente, la operación en el lugar es clara. En gh-15121, el argumento de la función local que permuta aleatoriamente su argumento debe ser un ndarray y no un arreglo arbitrario. De lo contrario, la función tendrá que hacer todo el descubrimiento de formas que hace np.array , y también rechazar las entradas que resulten ser inmutables (por ejemplo, no podemos hacer una reproducción aleatoria en el lugar de [(1, 2, 3, 4), (5, 6, 7, 8)] ).

Sería genial si realmente pudiéramos replicar la API sort , con una función que devuelve una copia aleatoria y un método ndarray que se baraja en el lugar, pero no creo que agregue tal un método para la clase ndarray tiene alguna posibilidad de ser aceptado.

y un ndarray _method_ que se baraja en el lugar, pero no creo que agregar un método de este tipo a la clase ndarray tenga ninguna posibilidad de ser aceptado.

Sin un generador singleton, creo que esto sería imposible de lograr.

@bashtage escribió

Encuentro que permutation (que no se puede cambiar fácilmente pero debería ser shuffled ) es el valor atípico real aquí. [Si] fue shuffle-shuffled , permute-permuted entonces creo que las cosas empiezan a verse bastante claras y razonables. ¿Alguien está dispuesto a agregar shuffled y comenzar una depreciación en permutation ?

Esto es a lo que convergió la discusión de la lista de correo (más o menos) en 2014. Aquí hay un enlace a la sugerencia de Nathaniels: https://mail.python.org/pipermail/numpy-discussion/2014-October/071364.html

Su scramble[d] es lo que llamé randomly_permute[d] en https://github.com/numpy/numpy/pull/15121.

Si agregamos shuffled como reemplazo de permutation , y llamamos a los nuevos métodos que operan a lo largo de un eje permute[d] , la tabla de funciones relacionadas es

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

que tiene una buena consistencia. En esta versión de la API, ninguno de los métodos tiene un parámetro out .

En https://github.com/numpy/numpy/pull/15121 , recientemente agregué otro método, con el nombre desgarbado y obviamente temporal permuted_with_out que demuestra cómo podría ser el argumento out usado. Si vamos con un parámetro out y nos quedamos con los nombres de los métodos existentes shuffle y permutation , la tabla se ve así

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)

Pero si vamos a introducir un parámetro out , deberíamos ser coherentes y usarlo también en permutation . Y aún podemos considerar reemplazar permutation con shuffled . Y dado que el nuevo método shuffled tiene un parámetro out , que permite la operación in situ, shuffle vuelve redundante y puede quedar obsoleto junto con permutation . Luego, cambiando a los nombres "agradables" de shuffled y permuted , la tabla es

    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)

Tenga en cuenta que el parámetro out no es solo para operar in situ. Permite reutilizar una matriz de salida, evitando potencialmente la creación de una matriz temporal. Esta es una ventaja de esta API sobre la API shuffle/shuffled/permute/permuted , pero no estoy seguro de cuán significativa es realmente esa ventaja. La desventaja de esta API es la desaprobación de dos métodos, shuffle y permutation . Estos pueden ser desaprobaciones "suaves" por un tiempo (es decir, restar importancia a su uso en los documentos, pero en realidad no agregue una advertencia de desaprobación por un tiempo) para disminuir el impacto inmediato.

Ese es mi resumen de los dos principales candidatos al cambio. Tenemos la versión shuffle/shuffled/permute/permuted , o la versión con shuffled/permuted con un parámetro out . Si, en 2014, alguien hubiera intervenido para implementar los cambios que se discutieron, probablemente ya tendríamos la versión shuffle/shuffled/permute/permuted . Pero la versión que usa out tiene un par de ventajas (¿pequeñas? ¿Insignificantes?): Dos nombres en lugar de cuatro, y out potencialmente permite que un usuario tenga menos variables temporales. Sería feliz con cualquiera de los dos.

¿Qué piensa la gente?

De los tres escenarios que enumeró, en orden, los clasificaría 1, 3 y bastante detrás del 2. Las 2 permutaciones que están haciendo cosas radicalmente diferentes parecen ser una gran fuente de confusión. Mi preferencia personal es evitar el uso obligatorio de out para acceder a una función; Siempre pienso en ello como una opción de rendimiento que puede tener sentido en algunos escenarios. Realmente no me gustaría enseñar a los estudiantes a usar solo para acceder a una función. También asumiría que en el caso de 3 x = shuffled(x, axis, out=x) también return x lugar de return None , de modo que mientras esté en su lugar, uno podría terminar con x apareciendo 3 veces.

Mi preferencia personal es evitar el uso obligatorio de out para acceder a una función; Siempre pienso en ello como una opción de rendimiento que puede tener sentido en algunos escenarios.

Pero barajar en el lugar _es_ una elección de rendimiento, ¿no es así?

Pero barajar en el lugar _es_ una elección de rendimiento, ¿no es así?

En el lugar también puede ser una opción de estilo de codificación, cuando esté disponible. Quizás uno confuso y quizás propenso a errores.

Mi opinión personal es que cuando f (x, out = x) siempre se siente un poco mágico, ya que a veces se usa como una forma muy poco obvia de lograr algo rápido. f (x, inplace = True), a pesar de no parecerse a ninguna otra cosa, parece mucho más claro (se parece un poco a un patrón de pandas antiguo que en su mayoría se ha eliminado).

Es cierto, pero es una elección de estilo de codificación que en NumPy normalmente parece deletreada usando out=... (a menos que esté usando un operador in situ o un método). O tal vez es una elección de estilo de codificación que NumPy no intenta activamente facilitar en la mayoría de los casos actualmente ...

Admito que es un poco mágico y un inplace= kwarg puede ser menos mágico, ¿pero también sin precedencia real? Y no estoy seguro de si la razón principal por la que parece menos mágico es que la reproducción aleatoria en el lugar es el núcleo del algoritmo aquí. Los detalles algorítmicos no deberían importar mucho a la mayoría de los estudiantes y, al final, usar out= también protege aproximadamente una sola copia + el ancho de banda de memoria asociado, y es comparable a ufuncs. (Es justo, también para ufuncs out=input es quizás algo mágico, pero su magia común y un patrón conocido, para usuarios avanzados).

Si bien es posible que sea un poco tedioso de escribir y algo menos rápido de leer, np.shuffled(x, out=x) parece muy claro en cuanto a cuál es el comportamiento. La parte no obvia parece solo el impacto en el rendimiento, que a mí me parece un tema reservado para que los usuarios avanzados se preocupen.

Una pregunta hipotética para aquellos que abogan por el uso de out : si no tuviéramos las funciones existentes numpy.sort y ndarray.sort , y estuviéramos agregando una función de clasificación ahora, ¿el la API preferida sea numpy.sorted(a, axis=-1, kind=None, order=None, out=None) (sin necesidad de implementar el método ndarray.sort para la clasificación en el lugar)?

ndarray.sort se modela a partir de list.sort , por lo que probablemente sea una opción de API sensata independientemente. Dicho esto, habría estado a favor de que np.sort no exista, y np.sorted(..., out=...) lugar.

Sí, creo que np.sort debería llamarse np.sorted (al igual que sorted() Python después de todo). Sin embargo, dado que solo el método tiene el comportamiento en el lugar, no veo mucha preocupación.

No estoy seguro del "sin necesidad de implementar el método ndarray.sort ". No veo nada malo con el método (o su comportamiento en el lugar). La pregunta sobre el método es simplemente si creemos que es lo suficientemente importante como para proporcionar una breve descripción del método conveniente.
Supongo que tampoco hay nada de malo en tener una versión de función en el lugar. La versión que no está en el lugar parece más agradable para los nuevos usuarios y el patrón out= suficientemente común para mí como para que los usuarios avanzados estén lo suficientemente bien atendidos.

No estoy seguro sobre el "sin necesidad de implementar el método ndarray.sort". No veo nada malo con el método (o su comportamiento en el lugar).

Eso fue parte de mi experimento mental de API. No quise insinuar que haya algo malo en lo que tenemos ahora. Solo estaba diciendo que, si comenzamos desde cero, y agregaré a mis premisas hipotéticas que no nos preocupa hacer coincidir la API de Python para las listas, entonces la API preferida para ordenar sería numpy.sorted(..., out=...) , y no necesitaríamos nada más.

Otra pregunta, no tan hipotética: si usar out es la opción preferida aquí, entonces, para la coherencia de la API en todo NumPy, ¿deberíamos planear eventualmente agregar out a numpy.sort , numpy.partition , numpy.argsort , y, bueno, ¿ todo lo demás que no lo tiene actualmente?

Sí, en mi opinión, agregar un out= kwarg con la misma semántica que para ufuncs es una buena opción para prácticamente todas las funciones de la API de NumPy. Cualquier falta de un argumento out es generalmente una mejora a la espera de ser realizada (aunque, en la práctica, supongo que puede ser una pequeña mejora y, en casos raros, posiblemente no valga la pena agregar demasiada complejidad al código).

¿Fue útil esta página
0 / 5 - 0 calificaciones