Python 关于numpy的困惑';s沿轴应用,并列出理解
好吧,如果我只是问一些愚蠢的问题,我提前道歉,但我真的认为我理解了Python 关于numpy的困惑';s沿轴应用,并列出理解,python,object,numpy,vectorization,Python,Object,Numpy,Vectorization,好吧,如果我只是问一些愚蠢的问题,我提前道歉,但我真的认为我理解了apply\u沿_轴的工作原理。我刚刚遇到了一个可能是我没想到的边缘案例,但这让我感到困惑。简而言之,这就是让我困惑的代码: class Leaf(object): def __init__(self, location): self.location = location def __len__(self): return self.location.shape[0] def
apply\u沿_轴
的工作原理。我刚刚遇到了一个可能是我没想到的边缘案例,但这让我感到困惑。简而言之,这就是让我困惑的代码:
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中使用列表理解然后再回溯到数组很愚蠢,但我只是不确定是否有其他方法可以做到这一点。我是不是遗漏了一些明显的东西?沿轴应用的
是纯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_沿_轴
,除了错误之外,速度较慢。apply_沿_轴
是纯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\u-arou-arou-arou-araxis
除了错误之外,速度较慢。问题似乎在于apply\u-arou-araxis
使用isscalar
来确定返回的对象是否是标量,但是isscalar
对于用户定义的类返回False
。for沿_轴应用
表示:
outarr的形状与arr的形状相同,除了沿轴尺寸外,其中outarr的长度等于func1d返回值的大小
由于类的\uuu len\uu
返回它所包装的数组的长度,numpy将结果数组“扩展”为原始形状。如果不定义\uuuu len\uuuu
,您将得到一个错误,因为numpy不认为用户定义的类型是标量,所以它仍然会尝试对其调用len
就我所见,没有办法使用用户定义的类来实现这一点。您可以从\uuu len\uuuu
返回1,但仍然会得到一个Nx1 2D结果,而不是长度为N的1D数组。我看不到任何方法可以让Numpy将用户定义的实例视为标量
有关于apply\u沿_轴
行为的讨论,但令人惊讶的是,我找不到任何关于isscalar
对非numpy对象返回False的根本问题的讨论。可能是numpy只是决定下注,而不是猜测用户定义的类型是向量还是标量。尽管如此,在numpy列表中询问这个问题还是值得的,因为像isscalar(object())
这样的东西返回False对我来说似乎很奇怪
然而,如果正如你所说的,你根本不在乎性能,那也没关系。只需使用列表理解的第一种方法,它已经实现了您想要的功能。问题似乎是apply\u沿轴
使用isscalar
来确定返回的对象是否是标量,但是isscalar
对于用户定义的类返回False
。for沿_轴应用
表示:
outarr的形状与arr的形状相同,除了沿轴尺寸外,其中outarr的长度等于func1d返回值的大小
由于类的\uuu len\uu
返回它所包装的数组的长度,numpy将结果数组“扩展”为原始形状。如果不定义\uuuu len\uuuu
,您将得到一个错误,因为numpy不认为用户定义的类型是标量,所以它仍然会尝试对其调用len
就我所见,没有办法使用用户定义的类来实现这一点。您可以从\uuu len\uuuu
返回1,但仍然会得到一个Nx1 2D结果,而不是长度为N的1D数组。我看不到任何方法可以让Numpy将用户定义的实例视为标量
有关于apply\u沿_轴
行为的讨论,但令人惊讶的是,我找不到任何关于isscalar
对非numpy对象返回False的根本问题的讨论。可能是numpy只是决定下注,而不是猜测用户定义的类型是向量还是标量。尽管如此,在numpy列表中询问这个问题还是值得的,因为像isscalar(object())
这样的东西返回False对我来说似乎很奇怪
然而,如果正如你所说的,你根本不在乎性能,那也没关系。只需使用列表理解的第一种方法,它已经实现了您想要的功能。apply\u沿\u轴
从不修改其输入。它返回一个新数组。如果用词不当,我的意思是check与shapeWhatchild\u array
?一个Leaf
实例数组将具有dtypeobject
。这些数组的内存效率并不比常规Python列表高,并且执行任何计算的速度都不会比使用常规Python列表的等效代码快(而且考虑到创建数组的成本,它通常会更慢)。它提供的只是ndarray索引语法。你确定要使用NumPy数组吗?@BrenBarn只是一个随机数数组。一个np.random.rand(x,y)
apply\u沿轴
从不修改其输入。它返回一个新的数组。如果拼写错误,我的意思是检查是相同的