write read matrices empty crear con python arrays multidimensional-array mapping numpy

matrices - read matrix python



Mapeo de una matriz NumPy en su lugar (5)

Esta es una reseña de contribuciones dispersas en respuestas y comentarios, que escribí después de aceptar la respuesta a la pregunta. Los votos ascendentes son siempre bienvenidos, pero si votó positivamente esta respuesta, no se pierda la posibilidad de votar también los de remitente y (si (es) escribe uno) eryksun , quien sugirió los métodos a continuación.

P: ¿Es posible mapear una matriz numpy en su lugar?
A: Sí, pero no con un solo método de matriz . Tienes que escribir tu propio código.

Debajo de una secuencia de comandos que compara las diversas implementaciones discutidas en el hilo:

import timeit from numpy import array, arange, vectorize, rint # SETUP get_array = lambda side : arange(side**2).reshape(side, side) * 30 dim = lambda x : int(round(x * 0.67328)) # TIMER def best(fname, reps, side): global a a = get_array(side) t = timeit.Timer(''%s(a)'' % fname, setup=''from __main__ import %s, a'' % fname) return min(t.repeat(reps, 3)) #low num as in place --> converge to 1 # FUNCTIONS def mac(array_): for row in range(len(array_)): for col in range(len(array_[0])): array_[row][col] = dim(array_[row][col]) def mac_two(array_): li = range(len(array_[0])) for row in range(len(array_)): for col in li: array_[row][col] = int(round(array_[row][col] * 0.67328)) def mac_three(array_): for i, row in enumerate(array_): array_[i][:] = [int(round(v * 0.67328)) for v in row] def senderle(array_): array_ = array_.reshape(-1) for i, v in enumerate(array_): array_[i] = dim(v) def eryksun(array_): array_[:] = vectorize(dim)(array_) def ufunc_ed(array_): multiplied = array_ * 0.67328 array_[:] = rint(multiplied) # MAIN r = [] for fname in (''mac'', ''mac_two'', ''mac_three'', ''senderle'', ''eryksun'', ''ufunc_ed''): print(''/nTesting `%s`...'' % fname) r.append(best(fname, reps=50, side=50)) # The following is for visually checking the functions returns same results tmp = get_array(3) eval(''%s(tmp)'' % fname) print tmp tmp = min(r)/100 print(''/n===== ...AND THE WINNER IS... ========================='') print('' mac (as in question) : %.4fms [%.0f%%]'') % (r[0]*1000,r[0]/tmp) print('' mac (optimised) : %.4fms [%.0f%%]'') % (r[1]*1000,r[1]/tmp) print('' mac (slice-assignment) : %.4fms [%.0f%%]'') % (r[2]*1000,r[2]/tmp) print('' senderle : %.4fms [%.0f%%]'') % (r[3]*1000,r[3]/tmp) print('' eryksun : %.4fms [%.0f%%]'') % (r[4]*1000,r[4]/tmp) print('' slice-assignment w/ ufunc : %.4fms [%.0f%%]'') % (r[5]*1000,r[5]/tmp) print(''=======================================================/n'')

El resultado del script anterior, al menos en mi sistema, es:

mac (as in question) : 88.7411ms [74591%] mac (optimised) : 86.4639ms [72677%] mac (slice-assignment) : 79.8671ms [67132%] senderle : 85.4590ms [71832%] eryksun : 13.8662ms [11655%] slice-assignment w/ ufunc : 0.1190ms [100%]

Como puede observar, usar ufunc de ufunc aumenta la velocidad de más de 2 y casi 3 órdenes de magnitud en comparación con la segunda mejor y peor alternativa, respectivamente.

Si usar ufunc no es una opción, aquí hay una comparación de las otras alternativas solamente:

mac (as in question) : 91.5761ms [672%] mac (optimised) : 88.9449ms [653%] mac (slice-assignment) : 80.1032ms [588%] senderle : 86.3919ms [634%] eryksun : 13.6259ms [100%]

HTH!

¿Es posible mapear una matriz NumPy en su lugar? Si es así, ¿cómo?

Dado a_values - array 2D - este es el código que me hace el truco en este momento:

for row in range(len(a_values)): for col in range(len(a_values[0])): a_values[row][col] = dim(a_values[row][col])

Pero es tan feo que sospecho que en algún lugar dentro de NumPy debe haber una función que haga lo mismo con algo parecido a:

a_values.map_in_place(dim)

pero si algo como el anterior existe, no he podido encontrarlo.


¿Por qué no usar la implementación de numpy y out_ trick?

from numpy import array, arange, vectorize, rint, multiply, round as np_round def fmilo(array_): np_round(multiply(array_ ,0.67328, array_), out=array_)

tiene:

===== ...AND THE WINNER IS... ========================= mac (as in question) : 80.8470ms [130422%] mac (optimised) : 80.2400ms [129443%] mac (slice-assignment) : 75.5181ms [121825%] senderle : 78.9380ms [127342%] eryksun : 11.0800ms [17874%] slice-assignment w/ ufunc : 0.0899ms [145%] fmilo : 0.0620ms [100%] =======================================================


Esta es solo una versión actualizada de la escritura de mac, actualizada para Python 3.x, y con numba y numpy.frompyfunc agregados.

numpy.frompyfunc toma una función python abitrary y devuelve una función, que cuando se lanza en un numpy.array, aplica la función elementwise.
Sin embargo, cambia el tipo de datos de la matriz a objeto, por lo que no está en su lugar, y los cálculos futuros en esta matriz serán más lentos.
Para evitar este inconveniente, se numpy.ndarray.astype la prueba numpy.ndarray.astype , devolviendo el tipo de datos a int.

Como nota al margen:
Numba no está incluido en las bibliotecas básicas de Python y debe descargarse externamente si desea probarlo. En esta prueba, en realidad no hace nada, y si hubiera sido llamado con @jit (nopython = True) , habría dado un mensaje de error que indica que no puede optimizar nada allí. Sin embargo, dado que numba a menudo acelera el código escrito en un estilo funcional, se incluye para la integridad.

import timeit from numpy import array, arange, vectorize, rint, frompyfunc from numba import autojit # SETUP get_array = lambda side : arange(side**2).reshape(side, side) * 30 dim = lambda x : int(round(x * 0.67328)) # TIMER def best(fname, reps, side): global a a = get_array(side) t = timeit.Timer(''%s(a)'' % fname, setup=''from __main__ import %s, a'' % fname) return min(t.repeat(reps, 3)) #low num as in place --> converge to 1 # FUNCTIONS def mac(array_): for row in range(len(array_)): for col in range(len(array_[0])): array_[row][col] = dim(array_[row][col]) def mac_two(array_): li = range(len(array_[0])) for row in range(len(array_)): for col in li: array_[row][col] = int(round(array_[row][col] * 0.67328)) def mac_three(array_): for i, row in enumerate(array_): array_[i][:] = [int(round(v * 0.67328)) for v in row] def senderle(array_): array_ = array_.reshape(-1) for i, v in enumerate(array_): array_[i] = dim(v) def eryksun(array_): array_[:] = vectorize(dim)(array_) @autojit def numba(array_): for row in range(len(array_)): for col in range(len(array_[0])): array_[row][col] = dim(array_[row][col]) def ufunc_ed(array_): multiplied = array_ * 0.67328 array_[:] = rint(multiplied) def ufunc_frompyfunc(array_): udim = frompyfunc(dim,1,1) array_ = udim(array_) array_.astype("int") # MAIN r = [] totest = (''mac'', ''mac_two'', ''mac_three'', ''senderle'', ''eryksun'', ''numba'',''ufunc_ed'',''ufunc_frompyfunc'') for fname in totest: print(''/nTesting `%s`...'' % fname) r.append(best(fname, reps=50, side=50)) # The following is for visually checking the functions returns same results tmp = get_array(3) eval(''%s(tmp)'' % fname) print (tmp) tmp = min(r)/100 results = list(zip(totest,r)) results.sort(key=lambda x: x[1]) print(''/n===== ...AND THE WINNER IS... ========================='') for name,time in results: Out = ''{:<34}: {:8.4f}ms [{:5.0f}%]''.format(name,time*1000,time/tmp) print(Out) print(''=======================================================/n'')



Y finalmente, los resultados:

===== ...AND THE WINNER IS... ========================= ufunc_ed : 0.3205ms [ 100%] ufunc_frompyfunc : 3.8280ms [ 1194%] eryksun : 3.8989ms [ 1217%] mac_three : 21.4538ms [ 6694%] senderle : 22.6421ms [ 7065%] mac_two : 24.6230ms [ 7683%] mac : 26.1463ms [ 8158%] numba : 27.5041ms [ 8582%] =======================================================


Si ufuncs no son posibles, debería considerar usar cython. es fácil de integrar y ofrece grandes aceleraciones en el uso específico de matrices numpy.


Solo vale la pena intentar hacer esto en el lugar si estás bajo restricciones de espacio significativas. Si ese es el caso, es posible acelerar su código un poco iterando sobre una vista aplanada de la matriz. Dado que la nueva reshape devuelve una nueva vista cuando es posible , los datos en sí mismos no se copian (a menos que el original tenga una estructura inusual).

No sé de una mejor manera de lograr la aplicación de buena fe en el lugar de una función arbitraria de Python.

>>> def flat_for(a, f): ... a = a.reshape(-1) ... for i, v in enumerate(a): ... a[i] = f(v) ... >>> a = numpy.arange(25).reshape(5, 5) >>> flat_for(a, lambda x: x + 5) >>> a array([[ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20, 21, 22, 23, 24], [25, 26, 27, 28, 29]])

Algunos tiempos:

>>> a = numpy.arange(2500).reshape(50, 50) >>> f = lambda x: x + 5 >>> %timeit flat_for(a, f) 1000 loops, best of 3: 1.86 ms per loop

Es aproximadamente el doble de rápido que la versión de bucle anidado:

>>> a = numpy.arange(2500).reshape(50, 50) >>> def nested_for(a, f): ... for i in range(len(a)): ... for j in range(len(a[0])): ... a[i][j] = f(a[i][j]) ... >>> %timeit nested_for(a, f) 100 loops, best of 3: 3.79 ms per loop

Por supuesto, vectorize es aún más rápido, así que si puedes hacer una copia, usa eso:

>>> a = numpy.arange(2500).reshape(50, 50) >>> g = numpy.vectorize(lambda x: x + 5) >>> %timeit g(a) 1000 loops, best of 3: 584 us per loop

Y si puede reescribir dim utilizando ufuncs incorporados, entonces, por favor, no vectorize :

>>> a = numpy.arange(2500).reshape(50, 50) >>> %timeit a + 5 100000 loops, best of 3: 4.66 us per loop

numpy hace que las operaciones como += numpy en su lugar, tal como cabría esperar, para que pueda obtener la velocidad de un ufunc con la aplicación in situ sin costo. ¡A veces es incluso más rápido! Vea here para un ejemplo.

Por cierto, mi respuesta original a esta pregunta, que se puede ver en su historial de edición, es ridícula e implica vectorizar sobre índices en a . No solo tuvo que hacer algunas cosas funky para eludir el mecanismo de detección de tipo de vectorize , sino que resultó ser tan lento como la versión de bucle anidado. ¡Tanto por inteligencia!