Numpy: Apoyando la coerción de matriz de patos

Creado en 25 jun. 2019  ·  55Comentarios  ·  Fuente: numpy/numpy

Abriendo este número después de una discusión con @shoyer , @pentschev y @mrocklin en cuestión (https://github.com/dask/dask/issues/4883). AIUI esto se discutió en NEP 22 (por lo que principalmente estoy repitiendo las ideas de otras personas aquí para renovar la discusión y corregir mi propio malentendido;).

Sería útil que varias bibliotecas de matrices descendentes tuvieran una función para garantizar que tenemos alguna matriz de pato (como ndarray ). Esto sería algo similar a np.asanyarray , pero sin el requisito de subclases. Permitiría a las bibliotecas devolver su propio tipo de matriz (pato) . Si el objeto no admitía una conversión adecuada, podríamos recurrir a las subclases ndarray , ndarray s y la coerción de otras cosas (listas anidadas) a ndarray s.

cc @njsmith (coautor de NEP 22)

01 - Enhancement numpy.core

Comentario más útil

Quizás quack_array :)

Todos 55 comentarios

La implementación propuesta sería similar a la siguiente:

import numpy as np

# hypothetical np.duckarray() function
def duckarray(array_like):
  if hasattr(array_like, '__duckarray__'):
    # return an object that can be substituted for np.ndarray
    return array_like.__duckarray__()
  return np.asarray(array_like)

Uso de ejemplo:

class SparseArray:
  def __duckarray__(self):
    return self
  def __array__(self):
    raise TypeError

np.duckarray(SparseArray())  # returns a SparseArray object
np.array(SparseArray())  # raises TypeError

Aquí he usado np.duckarray y __duckarray__ como marcadores de posición, pero probablemente podamos hacerlo mejor con estos nombres. Consulte la terminología de NEP 22:

"Duck array" funciona bien como marcador de posición por ahora, pero es bastante jerga y puede confundir a los nuevos usuarios, por lo que es posible que deseemos elegir algo más para las funciones reales de la API. Desafortunadamente, "tipo matriz" ya se toma para el concepto de "cualquier cosa que pueda ser forzada a una matriz" (incluyendo, por ejemplo, lista de objetos), y "anyarray" ya se toma como concepto de "algo que comparte la implementación de ndarray, pero tiene una semántica diferente ”, que es lo opuesto a un arreglo de pato (por ejemplo, np.matrix es un“ anyarray ”, pero no es un“ arreglo de pato ”). Este es un cobertizo para bicicletas clásico, por lo que por ahora solo estamos usando "matriz de patos". Sin embargo, algunas opciones posibles incluyen: arrayish, pseudoarray, nominalarray, ersatzarray, arraymimic,…

Algunas otras ideas de nombres: np.array_compatible() , np.array_api() ....

np.array_compatible podría funcionar, aunque no estoy seguro de que me guste más que duckarray . np.array_api No me gusta, me da una idea equivocada en mi humilde opinión.

Dado que después de mucho tiempo no hemos encontrado un nombre mejor, tal vez deberíamos bendecir el nombre de "patos"

Me gusta la palabra compatible, tal vez también podamos pensar en variaciones a lo largo de esa línea as_compatible_array (de alguna manera implica que todos los objetos compatibles son matrices). El as es quizás molesto (en parte porque todas las funciones as no tienen espacios). "pato" parece agradable en las bibliotecas, pero creo que es un poco extraño para personas al azar que lo vean. Así que creo que no me gusta "pato" si y solo si queremos que los usuarios posteriores lo utilicen mucho (es decir, incluso cuando empiezo a escribir una pequeña herramienta para mí o un pequeño laboratorio).

Quizás quack_array :)

Para ampliar un poco el tema, hay otro caso que no se cubre con np.duckarray , que es la creación de nuevas matrices con un tipo basado en un tipo existente, similar a funciones como np.empty_like hacer. Actualmente podemos hacer cosas como esta:

>>> import numpy as np, cupy as cp
>>> a  = cp.array([1, 2])
>>> b = np.ones_like(a)
>>> type(b)
<class 'cupy.core.core.ndarray'>

Por otro lado, si tenemos un array_like que nos gustaría crear una matriz CuPy a través de la API de NumPy, eso no es posible. Creo que sería útil tener algo como:

import numpy as np, cupy as cp
a  = cp.array([1, 2])
b = [1, 2]
c = np.asarray(b, like=a)

¿Alguna idea / sugerencia sobre esto?

¿Quizás np.copy_like? Querríamos definir cuidadosamente qué propiedades
(por ejemplo, incluyendo dtype o no) se copian de la otra matriz.

El lunes 1 de julio de 2019 a las 5:40 a. M. Peter Andreas Entschev <
[email protected]> escribió:

Para ampliar un poco el tema, hay otro caso que no está cubierto.
con np.duckarray, que es la creación de nuevas matrices con un tipo basado
en un tipo existente, similar a lo que hacen funciones como np.empty_like.
Actualmente podemos hacer cosas como esta:

importar numpy como np, cupy como cp >>> a = cp.array ([1, 2]) >>> b = np.ones_like (a) >>> tipo (b)

Por otro lado, si tenemos un array_like que nos gustaría crear
una matriz CuPy desde la API de NumPy, eso no es posible. creo que sería
útil tener algo como:

importar numpy como np, cupy como cp
a = cp.array ([1, 2])
b = [1, 2]
c = np.asarray (b, like = a)

¿Alguna idea / sugerencia sobre esto?

-
Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/numpy/numpy/issues/13831?email_source=notifications&email_token=AAJJFVRCWDHRAXHHRDHXXM3P5H3LRA5CNFSM4H3HQWAKYY3PNVWWK3TUL52HS4DFVDVREXWJWK2TUL52HS4DFVDVREXWJWKNM2 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AAJJFVRSYHUYHMPWQTW2NLLP5H3LRANCNFSM4H3HQWAA
.

np.copy_like suena bien. Estoy de acuerdo, lo más probable es que debamos tener formas de controlar cosas como dtype .

Perdón por la pregunta del principiante, pero ¿algo como np.copy_like sería una enmienda a NEP-22, debería discutirse en la lista de correo o cuál sería el enfoque más apropiado para eso?

Realmente no tenemos reglas estrictas sobre esto, pero me inclinaría por poner np.copy_like y np.duckarray (o como lo llamemos) juntos en un nuevo NEP sobre coerción / creación de matrices de pato, una que es prescriptivo como NEP 18 en lugar de "informativo" como NEP 22. No necesita ser largo, la mayor parte de la motivación ya está clara al hacer referencia a NEP 18/22.

Una nota sobre np.copy_like() : definitivamente debería realizar el envío con __array_function__ (o algo así), por lo que operaciones como np.copy_like(sparse_array, like=dask_array) podrían definirse en cualquier tipo de matriz.

Genial, gracias por la información y estoy de acuerdo con su propuesta de envío. Trabajaré en un NEP para la implementación de np.duckarray y np.copy_like y enviaré un borrador de PR esta semana para eso.

¡Increíble, gracias Peter!

El lunes 1 de julio de 2019 a las 9:29 a. M. Peter Andreas Entschev <
[email protected]> escribió:

Genial, gracias por la información y estoy de acuerdo con su propuesta de envío. yo
trabajará en un NEP para la implementación de np.duckarray y
np.copy_like y envíe un borrador de PR esta semana para eso.

-
Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/numpy/numpy/issues/13831?email_source=notifications&email_token=AAJJFVW2YUBNUCJZK6JWDBTP5IWHNA5CNFSM4H3HQWAKYY3PNVWWK3TUL52HS4DFVDBXWJWWK3TUL52HS4DFVDVREXWJWKNM73 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AAJJFVR2KTPAZ4JPWDYYMFLP5IWHNANCNFSM4H3HQWAA
.

¡Es un placer y muchas gracias por las ideas y el apoyo con este trabajo!

Las funciones array_like y copy_like serían un poco extrañas de tener en el espacio de nombres principal, creo, ya que no podemos tener una implementación predeterminada (al menos no una que haría lo correcto para cupy / dask / sparse / etc), ¿verdad? Solo son útiles cuando se anulan. ¿O me falta una forma de crear objetos de matriz arbitrarios no numéricos aquí?

Es cierto, estos solo serían realmente útiles si desea admitir la escritura de pato. Pero ciertamente np.duckarray y np.copy_like funcionarían incluso si los argumentos son solo matrices NumPy; solo serían equivalentes a np.array / np.copy .

Todas las implementaciones de matrices tienen un método copy , ¿verdad? Usar eso en lugar de copy_like debería funcionar, entonces, ¿por qué agregar una nueva función?

array_like Puedo ver la necesidad, pero es posible que queramos discutir dónde ponerlo.

np.duckarray tiene sentido para mí.

Me inclinaría por poner np.copy_like y np.duckarray (o como lo llamemos) juntos en un nuevo NEP sobre coerción / creación de matrices de pato, uno que sea prescriptivo como NEP 18 en lugar de "informativo" como NEP 22.

+1

array_like puedo ver la necesidad de, pero es posible que deseemos discutir dónde ponerlo.

Ese es realmente el caso que me gustaría haber abordado con algo como np.copy_like . No lo he probado, pero probablemente np.copy ya se envía correctamente si la matriz no es NumPy.

Para que quede claro, ¿se refiere también a una función np.array_like ? Intencionalmente evité ese nombre porque pensé que podría ser confuso para todas las referencias existentes a array_like -arrays. Sin embargo, ahora me doy cuenta de que np.copy_like puede implicar una copia necesaria, y creo que sería bueno tener un comportamiento similar a np.asarray , donde la copia solo ocurre si aún no es un NumPy formación. En el caso que se analiza aquí, lo mejor sería hacer la copia solo si a no es del mismo tipo que b en una llamada como np.copy_like(a, like=b) .

No lo he probado, pero probablemente np.copy ya se envía correctamente si la matriz no es NumPy.

Debería estar decorado para admitir __array_function__ .

Para que quede claro, ¿se refiere también a una función np.array_like ? Intencionalmente evité ese nombre porque pensé que podría ser confuso para todas las referencias existentes a array_like-arrays.

Si. Y sí, estoy de acuerdo en que puede ser confuso.

Sin embargo, ahora me doy cuenta de que np.copy_like puede implicar una copia necesaria,

Sí, ese nombre implica una copia de datos.

puede implicar una copia necesaria, y creo que sería bueno tener un comportamiento similar a np.asarray ,

Pensé que eso era np.duckarray .

Creo que el ejemplo anterior de Peter podría ayudar a aclarar esto. Copiado a continuación y subtitulado en np.copy_like por simplicidad.

import numpy as np, cupy as cp
a  = cp.array([1, 2])
b = [1, 2]
c = np.copy_like(b, like=a)

Pensé que era np.duckarray.

En realidad, np.duckarray básicamente no hará nada y solo devolverá la matriz en sí (si se anula), de lo contrario, devolverá np.asarray (lo que lleva a una matriz NumPy). No podemos obtener una matriz CuPy de una lista de Python con ella, por ejemplo. Todavía necesitamos una función que pueda enviarse a CuPy (o cualquier otro arreglo like= ) por un array_like .

Gracias @jakirkham por el ejemplo actualizado.

c = np.copy_like(b, like=a)

Entonces, ¿se enviará a CuPy a través de a.__array_function__ y fallará si ese atributo no existe (por ejemplo, a=<scipy.sparse matrix> no funcionaría)? Parece que necesitamos un nuevo espacio de nombres o un nuevo paquete de utilidades de interoperabilidad para ese tipo de cosas. O eso o dejarlo en manos de un mecanismo de envío futuro más completo en el que uno podría hacer simplemente:

with cupy_backend:
   np.array(b)

La introducción de nuevas funciones en el espacio de nombres principal que no tiene sentido para que NumPy sea compatible con el trabajo alrededor de una limitación de __array_function__ parece un poco insalubre ...

Entonces, ¿se enviará a CuPy a través de a.__array_function__ y fallará si ese atributo no existe (por ejemplo, a=<scipy.sparse matrix> no funcionaría)?

No diría que tiene que fallar necesariamente. Podríamos usar NumPy de forma predeterminada y generar una advertencia (o no generarla en absoluto), por ejemplo.

Parece que necesitamos un nuevo espacio de nombres o un nuevo paquete de utilidades de interoperabilidad para ese tipo de cosas. O eso o dejarlo en manos de un mecanismo de despacho futuro más completo.

Ciertamente, sería bueno tener un mecanismo de envío con todas las funciones, pero me imagino que esto no se hizo antes debido a su complejidad y problemas de compatibilidad con versiones anteriores. No estaba presente cuando ocurrieron las discusiones, así que solo estaba adivinando.

La introducción de nuevas funciones en el espacio de nombres principal que no tiene sentido para que NumPy sea compatible con trabajar alrededor de una limitación de __array_function__ parece un poco insalubre ...

Ciertamente veo su punto, pero también creo que si alejamos demasiadas cosas del espacio de nombres principal, podría asustar a los usuarios. Quizás me equivoque y esto es solo una impresión. De cualquier manera, no estoy proponiendo implementar funciones que no funcionarán con NumPy, pero tal vez no sean absolutamente necesarias cuando se usa NumPy por sí mismo.

La introducción de nuevas funciones en el espacio de nombres principal que no tiene sentido para que NumPy sea compatible con trabajar alrededor de una limitación de __array_function__ parece un poco insalubre ...

En realidad, en este sentido, también np.duckarray no pertenecería al espacio de nombres principal.

En realidad, en este sentido, también np.duckarray no pertenecería al espacio de nombres principal.

Creo que uno es más defendible (análogo a asarray y básicamente marcaría "¿cumple con nuestra definición de un tipo de pato tipo ndarray"), pero sí. Si también queremos exponer array_function_dispatch , y tenemos cosas np.lib.mixins.NDArrayOperatorsMixin y planeamos escribir más mixins, un nuevo submódulo sensato para todo lo relacionado con la interoperabilidad podría tener sentido.

Ciertamente, sería bueno tener un mecanismo de envío con todas las funciones, pero me imagino que esto no se hizo antes debido a su complejidad y problemas de compatibilidad con versiones anteriores. No estaba presente cuando ocurrieron las discusiones, así que solo estaba adivinando.

Creo que hay varias razones. __array_function__ es similar a las cosas que ya teníamos, por lo que es más fácil razonar. Tiene gastos generales bajos. Podría diseñarse e implementarse en una escala de tiempo de ~ 6 meses, y @shoyer presentó un caso sólido de que lo necesitábamos. Y no teníamos otra alternativa concreta.

Un nuevo submódulo sensible para todo lo relacionado con la interoperabilidad podría tener sentido.

No tengo objeciones reales, creo que es mejor tener funcionalidad en algún lugar que en ninguna. :)

Creo que hay varias razones. __array_function__ es similar a las cosas que ya teníamos, por lo que es más fácil razonar. Tiene gastos generales bajos. Podría diseñarse e implementarse en una escala de tiempo de ~ 6 meses, y @shoyer presentó un caso sólido de que lo necesitábamos. Y no teníamos otra alternativa concreta.

Pero si queremos aprovechar __array_function__ manera más amplia, ¿tenemos ahora otras alternativas para implementar cosas como np.duckarray y np.copy_like (o como sea que decidamos llamarlo)? Estoy abierto a todas las alternativas, pero en este momento no veo ninguna, por supuesto, en lugar de seguir el camino de envío de funciones completas, que probablemente llevará mucho tiempo y limitará el alcance de __array_function__ tremendamente (y básicamente lo vuelve impracticable para la mayoría de los casos más complejos que he visto).

Pero si queremos aprovechar __array_function__ manera más amplia, ¿tenemos ahora otras alternativas para implementar cosas como np.duckarray y np.copy_like (o como sea que decidamos llamarlo)?

Creo que de hecho necesitas un conjunto de funciones de utilidad como esa, para pasar de cubrir una fracción de los casos de uso a> 80% de los casos de uso. No creo que haya una forma de evitar eso. Simplemente no me gusta abarrotar el espacio de nombres principal, así que propongo encontrar un lugar mejor para ellos.

Estoy abierto a todas las alternativas, pero en este momento no veo ninguna, por supuesto, en lugar de seguir el camino de envío de funciones completas, que probablemente llevará mucho tiempo y limitará el alcance de __array_function__ tremendamente (y básicamente lo vuelve impracticable para la mayoría de los casos más complejos que he visto).

Quiero decir, solo estamos tapando algunos agujeros obvios aquí, ¿verdad? Nunca vamos a cubrir todos los "casos más complejos". Digamos que quiere anular np.errstate o np.dtype , eso no va a suceder con el enfoque basado en protocolos.

En cuanto a las alternativas, uarray aún no está allí y aún no estoy convencido de que la sobrecarga se reduzca lo suficiente como para usarse de forma predeterminada en NumPy, pero se está acercando y estamos a punto de probarlo para crear el scipy.fft sistema backend (WIP PR: https://github.com/scipy/scipy/pull/10383). Si eso se demuestra allí, debe considerarse como una solución completa de envío múltiple. Y ya tiene una API numpy con backends Dask / Sparse / CuPy / PyTorch / XND, algunos de los cuales son lo suficientemente completos como para ser utilizables: https://github.com/Quansight-Labs/uarray/tree/master/unumpy

El enfoque de envío con uarray es ciertamente interesante. Aunque todavía me preocupa cómo manejamos las metamatrices (como Dask, xarray, etc.). Consulte este comentario para obtener más detalles. No está claro que esto se haya solucionado (aunque corríjame si me he perdido algo). Me interesaría trabajar con otros en SciPy para tratar de averiguar cómo resolvemos este problema.

Consulte este comentario para obtener más detalles. No está claro que esto se haya solucionado (aunque corríjame si me he perdido algo).

Creo que los cambios de la semana pasada resuelven eso, pero no estoy seguro, dejémoslo para otro hilo.

Me interesaría trabajar con otros en SciPy para tratar de averiguar cómo resolvemos este problema.

Estaré allí, sería genial conocerte en persona.

Tal vez np.coerce_like() o np.cast_like() serían mejores nombres que copy_like , por lo que está claro que las copias no son necesariamente necesarias. La funcionalidad deseada es bastante similar al método .cast() , excepto que queremos convertir tipos de matriz y dtypes, y debe ser una función en lugar de un protocolo para que pueda implementarse con cualquier argumento.

El enfoque de envío con uarray es ciertamente interesante. Aunque todavía me preocupa cómo manejamos las metamatrices (como Dask, xarray, etc.).

uarray tiene soporte para múltiples backends, por lo que algo como esto debería funcionar

with ua.set_backend(inner_array_backend), ua.set_backend(outer_array_backend):
  s = unumpy.sum(meta_array)

Esto podría hacerse haciendo que la metamatriz llame a ua.skip_backend dentro de su implementación, o si el backend de la metamatriz devuelve NotImplemented en caso de falta de coincidencia de tipos.

cc: @hameerabbasi

Ampliaré esto: como regla general, para dask.array , cualquier cosa con da se escribiría sin skip_backend. Cualquier cosa con NumPy necesitaría un skip_backend.

O por da siempre puede omitir el envío y llamar a su propia implementación directamente y tener skip_backend(dask.array) todas partes.

En cuanto a las funciones de envío que no tienen una matriz adjunta, como ones , cast , simplemente establecería un backend y listo. Lo mismo para np.errstate y np.dtype . Hay un ejemplo que cubre np.ufunc en unumpy .

En cuanto al problema original, uarray proporciona el protocolo __ua_convert__ , que hace exactamente esto. Una alternativa sería que los backends anularan asarray directamente.

Gracias por el aviso sobre uarray , @rgommers , @ peterbell10 , @hameerabbasi.

Pero, como veo, debes configurar el backend adecuado antes de iniciar el cálculo, ¿es correcto? Una de las ventajas de __array_function__ es que las bibliotecas pueden ser completamente independientes de otras bibliotecas, como por ejemplo, Dask no necesita saber de la existencia de CuPy.

@pentschev Este era el caso hasta hace poco, cuando agregamos la capacidad de “registrar” un backend, pero recomendamos que solo NumPy (o una implementación de referencia) haga esto. Entonces los usuarios que usen Dask necesitarían solo un set_backend.

Entendido , supongo que esto es lo que https://github.com/numpy/numpy/issues/13831#issuecomment -507432311, apuntando a los backends en https://github.com/Quansight-Labs/uarray / árbol / maestro / unumpy.

Perdón por tantas preguntas, pero ¿qué pasa si alguna aplicación hipotética se basa en varios backends, por ejemplo, tanto NumPy como Sparse, donde, dependiendo de la entrada del usuario, tal vez todo sea solo NumPy, solo Sparse o una combinación de ambos? @ peterbell10 mencionó que se https://github.com/numpy/numpy/issues/13831#issuecomment -507458331, pero ¿se puede realizar la selección del backend de forma automática o sería necesario manejar los tres casos por separado?

Entonces, para este caso, lo ideal sería registrar NumPy, usar un administrador de contexto para Sparse y devolver NotImplemented desde sparse cuando sea apropiado, lo que haría algo alternativo a NumPy.

En SciPy @rgommers , @danielballan y yo hablamos sobre este tema. Concluimos que sería valioso continuar agregando duckarray (usando ese nombre). Dicho esto, parecía que estaría programado para 1,18. Aunque, por favor, corrígeme si entendí mal las cosas. Dado esto, ¿estaría bien comenzar un PR?

Concluimos que sería valioso continuar agregando duckarray (usando ese nombre). Dicho esto, parecía que estaría programado para 1,18. Aunque, por favor, corrígeme si entendí mal las cosas. Dado esto, ¿estaría bien comenzar un PR?

Todo esto me suena muy bien, pero sería bueno comenzar con un NEP breve explicando la propuesta exacta. Ver https://github.com/numpy/numpy/issues/13831#issuecomment -507334210

Seguro que tiene sentido. 🙂

En cuanto al punto de copia que se mencionó anteriormente, tengo curiosidad por saber si esto no se resuelve a través de los mecanismos existentes. En particular, ¿qué pasa con estas líneas?

a2 = np.empty_like(a1)
a2[...] = a1[...]

Es cierto que sería bueno reducir esto a una sola línea. Solo tengo curiosidad por saber si esto ya funciona para ese caso de uso o si nos faltan cosas.

Concluimos que sería valioso continuar agregando duckarray (usando ese nombre).

Todo esto me suena muy bien, pero sería bueno comenzar con un NEP breve explicando la propuesta exacta. Ver # 13831 (comentario)

Ya comencé a escribir eso, pero aún no he podido completarlo (lo siento por mi mala planificación https://github.com/numpy/numpy/issues/13831#issuecomment-507336302).

En cuanto al punto de copia que se mencionó anteriormente, tengo curiosidad por saber si esto no se resuelve a través de los mecanismos existentes. En particular, ¿qué pasa con estas líneas?

a2 = np.empty_like(a1)
a2[...] = a1[...]

Es cierto que sería bueno reducir esto a una sola línea. Solo tengo curiosidad por saber si esto ya funciona para ese caso de uso o si nos faltan cosas.

Puede hacer eso, pero puede requerir una lógica de copia especial (como en CuPy https://github.com/cupy/cupy/pull/2079).

Dicho esto, una función de copia puede ser lo mejor para evitar que este tipo de código adicional sea necesario.

Por otro lado, esto sería una especie de reemplazo de asarray . Así que me preguntaba si en lugar de una función nueva copy_like , en su lugar querríamos volver a examinar la idea sugerida por NEP-18 :

Estos necesitarán sus propios protocolos:
...
array y asarray, porque están destinados explícitamente a la coerción del objeto numpy.ndarray real.

Si existe la posibilidad de que nos gustaría volver a visitar eso, tal vez sería mejor comenzar un nuevo hilo. ¿Ideas, sugerencias, objeciones?

Solo para ser claro en mi comentario anterior, yo mismo no sé si un nuevo protocolo es una gran idea (probablemente muchos detalles engorrosos que no preveo estén involucrados), realmente me pregunto si esa es una idea que deberíamos revisar y discutir. .

El consenso de la reunión de desarrolladores y el sprint en SciPy'19 fue: saquemos 1.17.0 y obtengamos algo de experiencia en el mundo real antes de dar los siguientes pasos.

Realmente me pregunto si esa es una idea que deberíamos revisar y discutir.

probablemente sí, pero en unos meses.

probablemente sí, pero en unos meses.

Ok, gracias por la respuesta!

En cuanto al punto de copia que se mencionó anteriormente, tengo curiosidad por saber si esto no se resuelve a través de los mecanismos existentes. En particular, ¿qué pasa con estas líneas?

a2 = np.empty_like(a1)
a2[...] = a1[...]

Es cierto que sería bueno reducir esto a una sola línea. Solo tengo curiosidad por saber si esto ya funciona para ese caso de uso o si nos faltan cosas.

Mi principal problema con esto es que no funcionaría para matrices de pato que son inmutables, lo cual no es muy raro. Además, para NumPy, el costo adicional de asignar una matriz y luego llenarla puede ser casi cero, pero no estoy seguro de que eso sea cierto para todas las matrices de pato.

En cuanto al punto de copia que se mencionó anteriormente, tengo curiosidad por saber si esto no se resuelve a través de los mecanismos existentes. En particular, ¿qué pasa con estas líneas?

a2 = np.empty_like(a1)
a2[...] = a1[...]

Es cierto que sería bueno reducir esto a una sola línea. Solo tengo curiosidad por saber si esto ya funciona para ese caso de uso o si nos faltan cosas.

Puede hacer eso, pero puede requerir una lógica de copia especial (como en CuPy cupy / cupy # 2079 ).

Dicho esto, una función de copia puede ser lo mejor para evitar que este tipo de código adicional sea necesario.

Por otro lado, esto sería una especie de reemplazo de asarray . Así que me preguntaba si en lugar de una función nueva copy_like , en su lugar querríamos volver a examinar la idea sugerida por NEP-18 :

Estos necesitarán sus propios protocolos:
...
array y asarray, porque están destinados explícitamente a la coerción del objeto numpy.ndarray real.

Si existe la posibilidad de que nos gustaría volver a visitar eso, tal vez sería mejor comenzar un nuevo hilo. ¿Ideas, sugerencias, objeciones?

No creo que sea una buena idea cambiar el comportamiento de np.array o np.asarray con un nuevo protocolo. Su significado establecido es lanzar a matrices NumPy, que es básicamente la razón por la que necesitamos np.duckarray

Dicho esto, podríamos considerar agregar un argumento like a duckarray . Eso requeriría cambiar el protocolo de la propuesta simplificada anterior, tal vez usar __array_function__ lugar de un protocolo dedicado como __duckarray__ ? Realmente no lo he pensado bien.

En cuanto al punto de copia que se mencionó anteriormente, tengo curiosidad por saber si esto no se resuelve a través de los mecanismos existentes. En particular, ¿qué pasa con estas líneas?

a2 = np.empty_like(a1)
a2[...] = a1[...]

Es cierto que sería bueno reducir esto a una sola línea. Solo tengo curiosidad por saber si esto ya funciona para ese caso de uso o si nos faltan cosas.

Mi principal problema con esto es que no funcionaría para matrices de pato que son inmutables, lo cual no es muy raro. Además, para NumPy, el costo adicional de asignar una matriz y luego llenarla puede ser casi cero, pero no estoy seguro de que eso sea cierto para todas las matrices de pato.

Eso es justo. De hecho, ya podemos simplificar las cosas. Por ejemplo, esto funciona con CuPy y Sparse hoy.

a2 = np.copy(a1)

Eso es justo. De hecho, ya podemos simplificar las cosas. Por ejemplo, esto funciona con CuPy y Sparse hoy.

a2 = np.copy(a1)

Sí, pero también queremos "copiar esta matriz de patos en el tipo de esta otra matriz de patos"

No creo que sea una buena idea cambiar el comportamiento de np.array o np.asarray con un nuevo protocolo. Su significado establecido es lanzar a matrices NumPy, que es básicamente la razón por la que necesitamos np.duckarray

Tampoco estoy seguro de esto, y estaba reacio incluso a plantear esta pregunta, es por eso que no lo había hecho hasta hoy.

Dicho esto, podríamos considerar agregar un argumento similar a duckarray. Eso requeriría cambiar el protocolo de la propuesta simplificada anterior, ¿tal vez usar __array_function__ en lugar de un protocolo dedicado como __duckarray__? Realmente no lo he pensado bien.

No sé si habría alguna complicación con eso, aunque probablemente necesitemos algo de cuidado, pero me gusta esta idea. Eso parecería redundante en varios niveles, pero tal vez para seguir el patrón existente, en lugar de agregar un parámetro like , podríamos tener duckarray y duckarray_like ?

Sí, pero también queremos "copiar esta matriz de patos en el tipo de esta otra matriz de patos"

¿Qué tal basar esto en np.copyto ?

¿Qué tal basar esto en np.copyto ?

No dudes en corregirme si me equivoco, pero supongo que te refieres a algo como:

np.copyto(cupy_array, numpy_array)

Eso podría funcionar, asumiendo que NumPy está dispuesto a cambiar el comportamiento actual, por ejemplo, asarray siempre implica que el destino es una matriz NumPy, ¿ copyto hace la misma suposición?

np.copyto ya admite el envío con __array_function__ , pero es aproximadamente equivalente a:

def copyto(dst, src):
    dst[...] = src

Queremos el equivalente de:

def copylike(src, like):
    dst = np.empty_like(like)
    dst[...] = src
    return dst

np.copyto ya admite el envío con __array_function__ , pero es aproximadamente equivalente a:

def copyto(dst, src):
    dst[...] = src

Queremos el equivalente de:

def copylike(src, like):
    dst = np.empty_like(like)
    dst[...] = src
    return dst

Correcto, esto es lo que queremos. copyto se envía y funciona si el origen y el destino tienen el mismo tipo, necesitamos algo que permita el envío a la biblioteca de la matriz de destino.

Bueno, copyto aún podría tener sentido dependiendo de cómo lo pensemos. Tomemos, por ejemplo, el siguiente caso de uso.

np.copyto(cp.ndarray, np.random.random((3,)))

Esto podría traducirse en algo como asignar y copiar los datos como hemos discutido. Si enviamos alrededor de dst ( cp.ndarray en este caso), las bibliotecas con matrices inmutables también podrían implementar esto de una manera adecuada. También nos evita agregar una nueva API (que NumPy simplemente proporciona, pero no usa), lo que parecía ser una preocupación.

Solo para resaltar otro pensamiento que se me ocurrió recientemente, vale la pena pensar en lo que estas API significarán en sentido descendente entre otras bibliotecas (por ejemplo, cómo interactúan Dask y Xarray).

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