Esto es similar a esto, así que, por favor, léalo primero para entender lo que estoy tratando de hacer.
Ahora, quiero hacer el reemplazo cuando tenga instancias de clase. Algo como:
import numpy as np class B(): def __init__(self, a,b): self.a = a self.b = b arr = np.array([ [1,2,3,4,5],[6,7,8,9,10] ]) b1 = np.array([B(100,'a'), B(11,'b'), B(300,'c'), B(33,'d')]) b2 = np.array([B(45,'a'), B(65,'b'), B(77,'c'), B(88,'d')]) # My d array will be like that and I will have to # run 3 loops as below . I can't change that d = np.array([[b1],[b2]],dtype=object) # Replace the elements for i in d: for y in i: for idx,el in enumerate(y): #y[idx].a = arr.reshape(-1,5) # 5 is the size of every sublength of arr #print(y[idx].a) pass # Show the updated values for i in d: for y in i: for idx,x in enumerate(y): print(y[idx].a)
No puedo usar b = arr.reshape(-1, a.size)
porque esto debe ejecutarse fuera de los bucles. Pero, como dije, la matriz b
será el valor y[idx].value
, así que no puedo simplemente colóquelo en el tercer ciclo porque obtendré resultados incorrectos, y tampoco puedo ubicarlo fuera del tercer ciclo porque no tendré acceso a la parte de value
de la instancia de clase.
Quiero que mi resultado sea:
b1 = np.array([B(1,'a'), B(2,'b'), B(3,'c'), B(4,'d'), B(5,'d')]) b2 = np.array([B(6,'a'), B(7,'b'), B(8,'c'), B(9,'d'), B(10,'d')])
Por lo tanto, quiero llenar solo a
parte, por ejemplo, de las instancias de la clase B. Y tenga en cuenta que, como antes (en la pregunta anterior), la B
se expande para contener los 5 valores de arr
.
En pocas palabras, verifique la longitud de cada lista secundaria de arr
(que ahora es 5) y actualice los valores de d
consecuencia. Por lo tanto, si b1
y b2
tienen 4 valores, deben convertirse en 5 valores (los primeros 5 valores de arr
y los siguientes 5 valores de arr
).
Así que agrego
print(d.shape) print(d)
y obten
2249:~/mypy$ python3 stack42283851.py (2, 1, 4) [[[<__main__.B object at 0xb71d760c> <__main__.B object at 0xb71d7aac> <__main__.B object at 0xb71d7acc> <__main__.B object at 0xb71e5cec>]] [[<__main__.B object at 0xb391718c> <__main__.B object at 0xb39171ac> <__main__.B object at 0xb39171cc> <__main__.B object at 0xb39171ec>]]]
añadiendo un __repr__
a B
obtengo
1231:~/mypy$ python3 stack42283851.py (2, 1, 4) [[[B(100, a) B(11, b) B(300, c) B(33, d)]] [[B(45, a) B(65, b) B(77, c) B(88, d)]]]
Añadiendo
import itertools for a,b in itertools.zip_longest(arr[0,:],b1): print(a,b)
produce
1 B(100, a) 2 B(11, b) 3 B(300, c) 4 B(33, d) 5 None
Cambiando eso a
newlist = [] for a,b in itertools.zip_longest(arr[0,:],b1): if b is not None: new_b = B(a, bb) last_b = b else: new_b = B(a, last_b.b) newlist.append(new_b) print(np.array(newlist))
produce
[B(1, a) B(2, b) B(3, c) B(4, d) B(5, d)]
Asigne eso a b1
, y repita para a[1,:]
y b2
.
Para ser un poco más limpio, podría escribir ese código new_b
como una función, y reescribir el bucle como una lista de comprensión.
Sí, podría modificar b
en su lugar, por ejemplo
ba = a
pero como necesito crear un nuevo objeto B
para reemplazar el None
, ¿por qué molestarse? No puedo agregar el nuevo objeto B
a la matriz b1
original. Por lo tanto, es más sencillo crear una nueva matriz a través de una lista.
Puedo hacer un cambio in situ de d
y b1
con:
def replace(a,b): ba = a f = np.frompyfunc(replace, 2, 1) f(arr[:,None,:4], d) # produces array of None; ignore print(d) print(b1) [[[B(1, a) B(2, b) B(3, c) B(4, d)]] # chgd d [[B(6, a) B(7, b) B(8, c) B(9, d)]]] [B(1, a) B(2, b) B(3, c) B(4, d)] # chgd b1
Solo estoy usando frompyfunc
como una forma de transmisión perezosa de mans mans para hacer arr
contra todos los elementos. Tenga en cuenta que tengo que cambiar arr
para que coincida con d
forma. Además esto no añade ningún nuevo B()
. Obviamente no puedes hacer eso en el lugar.
Mi B
es
class B(): def __init__(self, a,b): self.a = a self.b = b def __repr__(self): return 'B(%s, %s)'%(self.a, self.b)
Jugando con frompyfunc
poco más:
getB_b = np.frompyfunc(lambda x: xb, 1,1) # fetch b attributes print(getB_b(d)) #[[['a' 'b' 'c' 'd']] # # [['a' 'b' 'c' 'd']]] mkB = np.frompyfunc(B, 2,1) # build array of B() with broadcasting print(mkB(arr, ['a','b','c','d','e'])) # [[B(1, a) B(2, b) B(3, c) B(4, d) B(5, e)] # [B(6, a) B(7, b) B(8, c) B(9, d) B(10, e)]] print(mkB(arr[:,:4], getB_b(d[:,0,:]))) # [[B(1, a) B(2, b) B(3, c) B(4, d)] # [B(6, a) B(7, b) B(8, c) B(9, d)]]
editar para comentarios
arr1 = np.array([ [1,2],[6,7] ]) newlist = [] for a,b in itertools.zip_longest(arr1[0,:],b1): if b is not None: new_b = B(a, bb) last_b = b else: new_b = B(a, last_b.b) newlist.append(new_b) print(np.array(newlist))
produce
[B(1, a) B(2, b) B(None, c) B(None, d)]
Cuando arr
es más corto, a
será None
(en lugar de b
); así que tenemos que probar para eso
def foo(arr,bn): newlist = [] for a,b in itertools.zip_longest(arr,bn): print(a,b) if a is None: pass else: if b is not None: new_b = B(a, bb) last_b = b else: new_b = B(a, last_b.b) newlist.append(new_b) return newlist print(np.array(foo(arr1[0,:],b1))) # arr1 shorter print(np.array(foo(arr[0,:], b2))) # arr longer
pruebas:
1 B(1, a) 2 B(2, b) None B(3, c) None B(4, d) [B(1, a) B(2, b)] 1 B(6, a) 2 B(7, b) 3 B(8, c) 4 B(9, d) 5 None [B(1, a) B(2, b) B(3, c) B(4, d) B(5, d)]
Nada especial o mágico; Sólo es una cuestión asegurarme de que obtengo las pruebas if
y sangría correctas.
Haz el bloque de reemplazo como este. También tenga en cuenta que esto supone que su arr será estrictamente en múltiplos de 5 y que habrá tantos bloques como b1, b2, etc., ya que hay bloques en arr como se indica en el ejemplo.
for i,b_arr in enumerate(d): temp_arr = [] for j in range(5): if j