resueltos recorrer objetos multiplicacion matriz matrices elementos ejercicios ejemplos ejemplo arreglos array agregar arrays python-3.x numpy error-handling reshape

arrays - recorrer - multiplicacion de matrices en fortran 90



¿Hay alguna manera de remodelar una matriz que no mantiene el tamaño original(o una solución práctica)? (2)

Como un ejemplo simplificado, supongamos que tengo un conjunto de datos compuesto por 40 valores ordenados. Los valores de este ejemplo son todos enteros, aunque este no es necesariamente el caso para el conjunto de datos real.

import numpy as np data = np.linspace(1,40,40)

Estoy tratando de encontrar el valor máximo dentro del conjunto de datos para ciertos tamaños de ventana. La fórmula para calcular los tamaños de ventana produce un patrón que se ejecuta mejor con matrices (en mi opinión). Por simplicidad, digamos que los índices que denotan los tamaños de ventana son una lista [1,2,3,4,5] ; esto corresponde a tamaños de ventana de [2,4,8,16,32] (el patrón es 2**index ).

## this code looks long because I''ve provided docstrings ## just in case the explanation was unclear def shapeshifter(num_col, my_array=data): """ This function reshapes an array to have ''num_col'' columns, where ''num_col'' corresponds to index. """ return my_array.reshape(-1, num_col) def looper(num_col, my_array=data): """ This function calls ''shapeshifter'' and returns a list of the MAXimum values of each row in ''my_array'' for ''num_col'' columns. The length of each row (or the number of columns per row if you prefer) denotes the size of each window. EX: num_col = 2 ==> window_size = 2 ==> check max( data[1], data[2] ), max( data[3], data[4] ), max( data[5], data[6] ), . . . max( data[39], data[40] ) for k rows, where k = len(my_array)//num_col """ my_array = shapeshifter(num_col=num_col, my_array=data) rows = [my_array[index] for index in range(len(my_array))] res = [] for index in range(len(rows)): res.append( max(rows[index]) ) return res

Hasta ahora, el código está bien. Lo revisé con lo siguiente:

check1 = looper(2) check2 = looper(4) print(check1) >> [2.0, 4.0, ..., 38.0, 40.0] print(len(check1)) >> 20 print(check2) >> [4.0, 8.0, ..., 36.0, 40.0] print(len(check2)) >> 10

Hasta aquí todo bien. Ahora aquí está mi problema.

def metalooper(col_ls, my_array=data): """ This function calls ''looper'' - which calls ''shapeshifter'' - for every ''col'' in ''col_ls''. EX: j_list = [1,2,3,4,5] ==> col_ls = [2,4,8,16,32] ==> looper(2), looper(4), looper(8), ..., looper(32) ==> shapeshifter(2), shapeshifter(4), shapeshifter(8), ..., shapeshifter(32) such that looper(2^j) ==> shapeshifter(2^j) for j in j_list """ res = [] for col in col_ls: res.append(looper(num_col=col)) return res j_list = [2,4,8,16,32] check3 = metalooper(j_list)

Ejecutar el código de arriba proporciona este error:

ValueError: total size of new array must be unchanged

Con 40 data points , la matriz se puede remodelar en 2 columns de 20 rows , o 4 columns de 10 rows u 8 columns de 5 rows , PERO en 16 columns , la matriz no se puede remodelar sin recortar datos desde 40/16 ≠ integer . Creo que este es el problema con mi código, pero no sé cómo solucionarlo.

Espero que haya una forma de cortar los últimos valores en cada fila que no encajan en cada ventana. Si esto no es posible, espero poder agregar ceros para llenar las entradas que mantienen el tamaño de la matriz original, para poder eliminar los ceros después. O tal vez incluso algún bloque complicado if - try - break . ¿Cuáles son algunas formas de solucionar este problema?


Aquí hay una forma generalizada de cambiar la forma con el truncamiento:

def reshape_and_truncate(arr, shape): desired_size_factor = np.prod([n for n in shape if n != -1]) if -1 in shape: # implicit array size desired_size = arr.size // desired_size_factor * desired_size_factor else: desired_size = desired_size_factor return arr.flat[:desired_size].reshape(shape)

Que tu shapeshifter podría usar en lugar de reshape


Creo que esto te dará lo que quieres en un solo paso:

def windowFunc(a, window, f = np.max): return np.array([f(i) for i in np.split(a, range(window, a.size, window))])

con f defecto, que le dará una matriz de máximos para sus ventanas.

Generalmente, al usar np.split y range , esto te permitirá np.split en una lista (posiblemente desigual) de matrices:

def shapeshifter(num_col, my_array=data): return np.split(my_array, range(num_col, my_array.size, num_col))

Necesita una lista de matrices porque una matriz 2D no puede ser irregular (cada fila necesita el mismo número de columnas)

Si realmente quieres rellenar con ceros, puedes usar np.lib.pad :

def shapeshifter(num_col, my_array=data): return np.lib.pad(my_array, (0, num_col - my.array.size % num_col), ''constant'', constant_values = 0).reshape(-1, num_col)

Advertencia:

También es técnicamente posible utilizar, por ejemplo, a.resize(32,2) que creará un ndArray rellenado con ceros (como lo solicitó). Pero hay algunas grandes advertencias:

  1. Debería calcular el segundo eje porque los trucos -1 no funcionan con el cambio de resize .
  2. Si la matriz original a es referenciada por cualquier otra cosa, a.resize fallará con el siguiente error:

    ValueError: cannot resize an array that references or is referenced by another array in this way. Use the resize function

  3. La función de cambio de resize (es decir, np.resize(a) ) no es equivalente a a.resize , ya que en lugar de relleno con ceros, volverá al principio.

Dado que parece querer hacer referencia a a por varias ventanas, a.resize no es muy útil. Pero es un agujero de conejo en el que es fácil caer.

EDITAR:

Looping a través de una lista es lento. Si su entrada es larga y las ventanas son pequeñas, el windowFunc anterior se empantanará en los bucles for . Esto debería ser más eficiente:

def windowFunc2(a, window, f = np.max): tail = - (a.size % window) if tail == 0: return f(a.reshape(-1, window), axis = -1) else: body = a[:tail].reshape(-1, window) return np.r_[f(body, axis = -1), f(a[tail:])]