跨多个轴的Numpy聚合

6yt4nkrj  于 2023-06-23  发布在  其他
关注(0)|答案(3)|浏览(107)

假设我有一个3d numpy数组,其形状为(27,27,27)。我想通过同时对每个轴上的每3个元素进行平均来将其压缩为(9,9,9)(例如使3x3x3像素变为1x1x1)。目标是同时在所有三个轴上有效地压缩单个整数(假设任何阵列对于每个轴的形状都将具有该整数的倍数)。
我最初的尝试是使用np.apply_over_axes,尽管我担心它不会得到所有3个轴的立方平均值,而是依次平均每个轴。

def mean_over(arr, axis):

    np.average(arr.reshape(-1, 3), axis=axis)

the_array_small = np.apply_over_axes(mean_over, the_array, \[0,1,2\])

但是,这将返回一个错误:

Traceback (most recent call last):

  File "\<stdin\>", line 1, in \<module\>

  File "\<\__array_function_\_ internals\>", line 180, in apply_over_axes

  File "/opt/homebrew/Caskroom/mambaforge/base/envs/seaborn/lib/python3.10/site-packages/numpy/lib/shape_base.py", line 496, in apply_over_axes

    if res.ndim == val.ndim:

AttributeError: 'NoneType' object has no attribute 'ndim'

我不相信我的apply_over_axes解决方案能够达到我的目标。理想情况下,返回每个(3,3,3)分量的平均值。

jqjz2hbq

jqjz2hbq1#

只是第一个答案(但同样,取决于你对我的评论的回答,依靠一些卷积可能会更好)

arr=np.randon.rand(27,27,27)
the_array_small = arr.reshape(9,3,9,3,9,3).mean(axis=(1,3,5))
mbzjlibv

mbzjlibv2#

另一种解决方案,但要利用as_strided

a = np.arange(27**3).reshape(27, 27, 27)
tile_size = (3, 3, 3)
tile_shape = tuple(np.array(a.shape) // np.array(tile_size))
tile_strides = tuple(np.array(a.strides) * np.array(tile_size)) + tuple(a.strides)
tile_view = np.lib.stride_tricks.as_strided(
    a,
    shape=tile_shape + tile_size,
    strides=tile_strides,
    writeable=False,
)
result = np.mean(tile_view, axis=(-3, -2, -1))
pcrecxhr

pcrecxhr3#

使用this answer中的cubify函数,您可以将数组拆分为立方体。有了这个结果,你可以使用apply_over_axes来获得平均值,并根据你想要的结果进行整形。这里我使用一个9x9x9的立方体的例子,因为这样更容易看到结果。

import numpy as np

def cubify(arr, newshape):
    """https://stackoverflow.com/a/42298440/12131013"""
    oldshape = np.array(arr.shape)
    repeats = (oldshape / newshape).astype(int)
    tmpshape = np.column_stack([repeats, newshape]).ravel()
    order = np.arange(len(tmpshape))
    order = np.concatenate([order[::2], order[1::2]])
    # newshape must divide oldshape evenly or else ValueError will be raised
    return arr.reshape(tmpshape).transpose(order).reshape(-1, *newshape)

a = np.arange(9**3).reshape(9,9,9)
c = cubify(a, (3,3,3))
res = np.apply_over_axes(np.mean, c, [1,2,3]).reshape(3,3,3)

结果:

array([[[ 91.,  94.,  97.],
        [118., 121., 124.],
        [145., 148., 151.]],

       [[334., 337., 340.],
        [361., 364., 367.],
        [388., 391., 394.]],

       [[577., 580., 583.],
        [604., 607., 610.],
        [631., 634., 637.]]])

相关问题