关于numpy沿轴和列表理解的应用的困惑 [英] Confusion about numpy's apply along axis and list comprehensions

查看:98
本文介绍了关于numpy沿轴和列表理解的应用的困惑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,所以如果我只是问些愚蠢的事情,我会提前道歉,但是我真的以为我理解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使用列表推导然后将其强制转换回数组感到很傻,但是我也不知道有其他方法可以做到这一点.我只是想念一些明显的东西吗?

解决方案

问题似乎是apply_along_axis使用isscalar来确定返回的对象是否为标量,但是isscalar为用户返回False定义的类. apply_along_axis文档说:

outarr的形状与arr的形状相同,不同之处在于沿轴尺寸,其中outarr的长度等于func1d返回值的大小.

由于类的__len__返回其包装的数组的长度,因此numpy将结果数组扩展"为原始形状.如果不定义__len__,则会收到错误消息,因为numpy认为用户定义的类型不是标量,因此它仍将尝试在其上调用len.

据我所知,没有办法使该类与用户定义的类一起使用.您可以从__len__返回1,但是仍然会得到Nx1 2D结果,而不是长度为N的1D数组.我看不出任何方法可以使Numpy将用户定义的实例视为标量. /p>

关于apply_along_axis行为,有一个numpy错误,但令人惊讶的是,我可以找不到有关isscalar对于非numpy对象返回False的根本问题的任何讨论.可能是numpy决定决定平移,而不猜测用户定义的类型是矢量还是标量.尽管如此,还是值得在numpy列表上询问这一点,因为对我来说,像isscalar(object())这样的东西返回False似乎很奇怪.

但是,如果您说过无论如何都不关心性能,那并不重要.只需对列表理解使用第一种方法,它已经可以满足您的要求.

Alright, so I apologize ahead of time if I'm just asking something silly, but I really thought I understood how apply_along_axis worked. I just ran into something that might be an edge case that I just didn't consider, but it's baffling me. In short, this is the code that is confusing me:

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

I always feel silly using a list comprehension with numpy and then casting back to an array, but I'm just nor sure of another way to do this. Am I just missing something obvious?

解决方案

The problem seems to be that apply_along_axis uses isscalar to determine whether the returned object is a scalar, but isscalar returns False for user-defined classes. The documentation for apply_along_axis says:

The shape of outarr is identical to the shape of arr, except along the axis dimension, where the length of outarr is equal to the size of the return value of func1d.

Since your class's __len__ returns the length of the array it wraps, numpy "expands" the resulting array into the original shape. If you don't define a __len__, you'll get an error, because numpy doesn't think user-defined types are scalars, so it will still try to call len on it.

As far as I can see, there is no way to make this work with a user-defined class. You can return 1 from __len__, but then you'll still get an Nx1 2D result, not a 1D array of length N. I don't see any way to make Numpy see a user-defined instance as a scalar.

There is a numpy bug about the apply_along_axis behavior, but surprisingly I can't find any discussion of the underlying issue that isscalar returns False for non-numpy objects. It may be that numpy just decided to punt and not guess whether user-defined types are vector or scalar. Still, it might be worth asking about this on the numpy list, as it seems odd to me that things like isscalar(object()) return False.

However, if as you say you don't care about performance anyway, it doesn't really matter. Just use your first way with the list comprehension, which already does what you want.

这篇关于关于numpy沿轴和列表理解的应用的困惑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆