gpt4 book ai didi

python - 如何从左侧使用 Numpy 数组实现对象的乘法?

转载 作者:行者123 更新时间:2023-12-04 09:50:15 24 4
gpt4 key购买 nike

如果想要将左侧的任意对象与 np.ndarray 相乘,一个人遇到了问题。

问题是,numpy.ndarray.__mul__叫右手边的__rmul__如果右侧是迄今为止未知的类型,则按元素进行。

要查看问题,您可以复制粘贴以下代码并从命令行或 SDK 运行它。您可以通过调试器逐步完成。评论可以帮助您并引导您完成...

import numpy as np


class Zora(object):

def __init__(self, array):
self._array = array
self._values_field_name = array.dtype.names[-1]

@property
def a(self):
return self._array

def __repr__(self):
return repr(self._array)

def __mul__(self, other):
result = self.copy()
result *= other
return result

def __imul__(self, other):
self._array[self._values_field_name] *= other
return self

def __rmul__(self, other):
return self * other

def copy(self):
return self.__class__(self.a.copy())

@classmethod
def create(cls, fields, codes, data):
array = np.array([(*c, d) for c, d in zip(codes, data)], dtype=fields)
return cls(array)


if __name__ == '__main__':

# Let's create a Zora dataset with scenarios
scenarios = 7

fields = np.dtype([('LegalEntity', np.unicode_, 32), ('Division', np.unicode_, 32),
('Scenarios', np.float64, (scenarios, ))])

legal_entities = ['A', 'A', 'B', 'B', 'C']
divisions = ['a', 'b', 'a', 'b', 'b']

codes = list(zip(legal_entities, divisions))

data = np.random.uniform(0., 1., (len(codes), scenarios))

zora = Zora.create(fields, codes, data)

# The dataset looks like the following
print(zora)

# We can multiply it from the left with scalars ...
z = zora * 2
print(zora * 2)

# ... and with column vectors, for example ...
# ... for this we generate a columns vector with some weights ...
numrows = zora.a.shape[0]

weights = np.expand_dims(np.array(list(range(numrows))), 1)
# ... the weights ...
print(weights)

# ... left side multiplication works fine too with this
print(zora * weights)

# Let's show inplace multiplication ...
# Which we apply on a copy, so that we can still compare ...
z = zora.copy()
z *= 2

# Is pretty fine too, ...
print(zora)
print(z)

# Now it becomes a bit special ...
# ... when multiplying from the left.
# It works fine with a scalar..
z = 2 * zora
print(z)

# But becomes special with np.ndarrays ...
print('-------------------------------------')
print('-------------------------------------')
print('The following result ...')
z = weights * zora
print(z)

# which is not the same, but should, as ...
print('-------------------------------------')
print('... should be the same as this one ...')

z = zora * weights
print(z)

# We got a list of arrays, where for each i-th array
# the corresponding i-th weight has been used for
# multiplication
#
# This has to do with numpy's implementation of calling
# __rmul__ from the right hand side within the __mul__
# from the np.ndarray ...
#
# The same is true for all other __r{...}__ methods

最佳答案

使用 Numpy Hook __array_ufunc__
Numpy 允许您通过正确定义 __array_ufunc__ 来规避此问题。对象上的方法。

以下方法添加到Zora上面的类,做的工作。很容易将其推广到所有二进制 ufunc包括非交换操作。但我只展示这个,不是为了让事情变得复杂。

def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
lhs, rhs = inputs
return rhs * lhs

因此,以下将显示预期的结果......
import numpy as np


class Zora(object):

def __init__(self, array):
self._array = array
self._values_field_name = array.dtype.names[-1]

@property
def a(self):
return self._array

def __repr__(self):
return repr(self._array)

def __mul__(self, other):
result = self.copy()
result *= other
return result

def __imul__(self, other):
self._array[self._values_field_name] *= other
return self

def __rmul__(self, other):
return self * other

def copy(self):
return self.__class__(self.a.copy())

def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
lhs, rhs = inputs
return rhs * lhs

@classmethod
def create(cls, fields, codes, data):
array = np.array([(*c, d) for c, d in zip(codes, data)], dtype=fields)
return cls(array)


if __name__ == '__main__':

# Let's create a Zora dataset with scenarios
scenarios = 7

fields = np.dtype([('LegalEntity', np.unicode_, 32), ('Division', np.unicode_, 32),
('Scenarios', np.float64, (scenarios, ))])

legal_entities = ['A', 'A', 'B', 'B', 'C']
divisions = ['a', 'b', 'a', 'b', 'b']

codes = list(zip(legal_entities, divisions))

data = np.random.uniform(0., 1., (len(codes), scenarios))

zora = Zora.create(fields, codes, data)

# The dataset looks like the following
print(zora)

# We can multiply it from the left with scalars ...
z = zora * 2
print(zora * 2)

# ... and with column vectors, for example ...
# ... for this we generate a columns vector with some weights ...
numrows = zora.a.shape[0]

weights = np.expand_dims(np.array(list(range(numrows))), 1)
# ... the weights ...
print(weights)

# ... left side multiplication works fine too with this
print(zora * weights)

# Let's show inplace multiplication ...
# Which we apply on a copy, so that we can still compare ...
z = zora.copy()
z *= 2

# Is pretty fine too, ...
print(zora)
print(z)

# Now it becomes a bit special ...
# ... when multiplying from the left.
# It works fine with a scalar..
z = 2 * zora
print(z)

# But becomes special with np.ndarrays ...
print('-------------------------------------')
print('-------------------------------------')
print('The following result ...')
z = weights * zora
print(z)

# which is now the same ...
print('-------------------------------------')
print('... should be the same as this one ...')

z = zora * weights
print(z)

关于python - 如何从左侧使用 Numpy 数组实现对象的乘法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62023723/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com