这类似于this,所以请先阅读它,以了解我要做什么.
现在,我想在有类实例时进行替换.
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)
我不能使用b = arr.reshape(-1,a.size),因为它必须在循环之外运行.但是,正如我所说的,b数组将是y [idx] .value,所以我不能只能将其放置在第3循环中,因为我将获得错误的结果,也不能将其放置在第3循环之外,因为我将无法访问类实例的值部分.
我希望我的结果是:
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')])
因此,我只想填写B类实例的一部分.
并请注意,与之前(在上一个问题中)一样,B进行了扩展以容纳arr中的所有5个值.
简而言之,请检查arr的每个子列表的长度(现在为5),
并相应地更新d值.因此,如果b1和b2具有4个值,则它们必须成为5个值(来自arr的前5个值和来自arr的下5个值).
解决方法:
所以我加
print(d.shape)
print(d)
并得到
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>]]]
我向B添加__repr__
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)]]]
添加
import itertools
for a,b in itertools.zip_longest(arr[0,:],b1):
print(a,b)
产生
1 B(100, a)
2 B(11, b)
3 B(300, c)
4 B(33, d)
5 None
更改为:
newlist = []
for a,b in itertools.zip_longest(arr[0,:],b1):
if b is not None:
new_b = B(a, b.b)
last_b = b
else:
new_b = B(a, last_b.b)
newlist.append(new_b)
print(np.array(newlist))
产生
[B(1, a) B(2, b) B(3, c) B(4, d) B(5, d)]
将其分配给b1,然后重复a [1 ,:]和b2.
为了更加简洁,我可以将new_b代码编写为一个函数,然后将循环重写为列表理解.
是的,我可以在适当位置修改b,例如
b.a = a
但是由于我需要创建一个新的B对象来替换None,所以麻烦.我不能将新的B对象添加到原始b1数组中.因此,通过列表创建新数组更为简单.
我可以用以下方法就地改变d和b1:
def replace(a,b):
b.a = 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
我只是使用frompyfunc作为一种懒惰的方式,对d广播arr并遍历所有元素.请注意,我必须更改arr以匹配d形状.同样,这不会添加任何新的B().显然,您不能就地执行此操作.
我的B是
class B():
def __init__(self, a,b):
self.a = a
self.b = b
def __repr__(self):
return 'B(%s, %s)'%(self.a, self.b)
和frompyfunc一起玩:
getB_b = np.frompyfunc(lambda x: x.b, 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)]]
编辑评论
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, b.b)
last_b = b
else:
new_b = B(a, last_b.b)
newlist.append(new_b)
print(np.array(newlist))
产生
[B(1, a) B(2, b) B(None, c) B(None, d)]
当arr较短时,a将为None(而不是b);所以我们需要测试一下
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, b.b)
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
测试:
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)]
没有什么特别的或不可思议的;确保我正确地通过if测试和缩进即可.
标签:python,numpy
来源: https://codeday.me/bug/20191011/1891670.html