首页 > 解决方案 > 为笨拙的数组实现 numpy.linalg.norm

问题描述

目前,不存在 numpy.linalg.norm 与 akward-arrays 的实现。在笨拙的 1 中,我可以behavior用来覆盖(或添加?)实现,如教程中所示。在我的用例中,我已经成功地实现了和使用np.absolute教程示例的版本。然而,失败。np.subtractTVector2TVector3numpy.linalg.norm

如何定义笨拙数组的行为?例如,在下面的示例中,我使用一个简单的 int64 数组进行了尝试:

import awkward1 as ak
import numpy as np

def norm(data, *args, **kwargs):
    return np.absolute(data)

ak.behavior[np.linalg.norm, "int64"] = norm

sample = ak.Array(np.arange(10))

print(ak.type(sample))  # 10 * int64
print(np.absolute(sample))  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

print(np.linalg.norm(np.arange(10)))  # 16.881943016134134
print(np.linalg.norm(sample)) # raises TypeError

标签: awkward-array

解决方案


如果您还没有看到https://awkward-array.readthedocs.io/en/latest/ak.behavior.html,那就从这里开始吧。

如果np.linalg.norm是一个ufunc,以下应该工作:

ak.behavior[np.linalg.norm, "vector2"] = lambda a: np.sqrt(a.x**2 +a.y**2)

其中数据位于具有字段xy名为 的记录中"vector2"。你可以用

ak.zip({"x": x_array, "y": y_array}, with_name="vector2")

(警告:我还没有测试过——我是在手机上写的。我稍后会测试并编辑这个答案,或者你可以编辑它。)

如果它不是 ufunc,那么就没有可公开访问(即没有下划线)的方式来定义它,也许应该有。

另外,请注意https://github.com/scikit-hep/vector项目,它定义了这样的操作。


编辑:查看np.linalg.norm文档,你是对的,它不是 ufunc。(isinstance(np.linalg.norm, np.ufunc)False。)

此外,此函数对其输入做出了一些强有力的假设。二维数组被解释为矩阵,而不是向量列表。在 Awkward Array 中,此类区别将由元数据标记。我不认为我们想要实现这样的函数,因为它可能会对本来应该是不同长度向量列表的锯齿状数组造成严重破坏。

我认为您想要的是添加矢量行为,如下所示:

>>> class Vector2(ak.Record):
...     @property
...     def norm(self):
...         return np.sqrt(self.x**2 + self.y**2)
... 
>>> class ArrayOfVector2(ak.Array):
...     @property
...     def norm(self):
...         return np.sqrt(self.x**2 + self.y**2)
... 
>>> ak.behavior["vector2"] = Vector2
>>> ak.behavior["*", "vector2"] = ArrayOfVector2

这只是说如果你有一个名为 "vector2"的记录,那么它应该被呈现为 Python 类Vector2,如果你有一个"vector2"记录数组(任何深度),它们应该集体呈现为一个ArrayOfVector2类。

>>> x_array = ak.Array([[1.1, 2.2, 3.3], [], [4.4, 5.5]])
>>> y_array = ak.Array([[1.0, 2.0, 3.0], [], [4.0, 5.0]])
>>> vectors = ak.zip({"x": x_array, "y": y_array}, with_name="vector2")
>>> vectors[0, 0]
<Vector2 {x: 1.1, y: 1} type='vector2["x": float64, "y": float64]'>
>>> vectors
<ArrayOfVector2 [[{x: 1.1, y: 1}, ... y: 5}]] type='3 * var * vector2["x...'>

这使您可以使用已定义的方法和属性:

>>> vectors[0, 0].norm
1.4866068747318506
>>> vectors.norm
<Array [[1.49, 2.97, 4.46], ... [5.95, 7.43]] type='3 * var * float64'>

而且,这正是https://github.com/scikit-hep/vector项目正在做的事情。密切关注它!


推荐阅读