关于numpy的混淆应用于轴和列表理解

时间:2014-12-24 20:29:30

标签: python object numpy vectorization

好吧,如果我只是问一些愚蠢的话,我提前道歉,但我真的以为我理解apply_along_axis是如何运作的。我刚刚碰到了一些我可能不会考虑的边缘情况,但令我感到困惑的是。简而言之,这是令我困惑的代码:

class Leaf(object):

    def __init__(self, location):
        self.location = location

    def __len__(self):
        return self.location.shape[0]

def bulk_leaves(child_array, axis=0):
    test = np.array([Leaf(location) for location in child_array])  # This is what I want
    check = np.apply_along_axis(Leaf, 0, child_array)  # This returns an array of individual leafs with the same shape as child_array
    return test, check

if __name__ == "__main__":
    test, check = bulk_leaves(np.random.ran(100, 50))
    test == check  # False

我总是觉得使用numpy的列表理解然后再回到数组会很傻,但我还不确定另一种方法。我只是遗漏了一些明显的东西吗?

2 个答案:

答案 0 :(得分:4)

apply_along_axis是纯Python,您可以自己查看和解码。在这种情况下,它基本上是这样做的:

check = np.empty(child_array.shape,dtype=object)
for i in range(child_array.shape[1]):
    check[:,i] = Leaf(child_array[:,i])

换句话说,它预先分配容器数组,然后用迭代填充值。这肯定比附加到数组更好,但很少比将值附加到列表更好(这就是理解所做的事情)。

您可以使用上面的模板并调整它以生成您真正想要的数组。

for i in range(check.shape[0]):
    check[i]=Leaf(child_array[i,:])

在快速测试中,此迭代次数与理解次数相同。除了错误之外,apply_along_axis速度较慢。

答案 1 :(得分:2)

问题似乎是apply_along_axis使用isscalar来确定返回的对象是否是标量,但isscalar为用户定义的类返回Falseapply_along_axis的{​​{3}}说:

  

outarr的形状与arr的形状相同,除了沿着轴的尺寸,其中outarr的长度等于func1d的返回值的大小。

由于你的班级__len__返回它所包含的数组的长度,numpy"扩展"将生成的数组转换为原始形状。如果您没有定义__len__,则会收到错误,因为numpy并不认为用户定义的类型是标量,因此它仍然会尝试调用{{1}在它上面。

据我所知,没有办法让用户定义的类工作。你可以从len返回1,但是你仍然会得到一个Nx1 2D结果,而不是长度为N的一维数组。我没有看到任何方法让Numpy看到用户定义的实例作为标量。

关于__len__行为有documentation,但令人惊讶的是,我无法找到apply_along_axis对非numpy对象返回False的基本问题的讨论。可能是numpy刚刚决定试图而不是猜测用户定义的类型是矢量还是标量。不过,在numpy列表中可能值得问这个问题,因为像isscalar这样的东西返回False似乎很奇怪。

但是,如果你说你不关心表现,那真的不重要。只需使用列表理解的第一种方式,已经做了你想要的。