【问题标题】:apply function to unique values of NumPy array将函数应用于 NumPy 数组的唯一值
【发布时间】:2021-01-14 23:07:33
【问题描述】:

我有一个函数 f,我想将它应用于任意形状和有序的 NumPy 数组 x 的所有元素。因为函数求值成本高,x 可能包含重复值,所以我首先将x 简化为唯一值,一个一维数组xu

xu, ind = np.unique(x, return_inverse=True)

然后我为函数值创建一个数组

yu = np.full(len(xu), np.nan)

并通过应用 f elementwise 来填充此数组。

我现在想创建一个与x 形状相同的数组y,以便相应的条目包含函数的结果。我的尝试:

y = np.full(x.shape, np.nan)
y[ind] = yu

如果x 还不是一维的,这将失败。 (您可能会猜到我习惯了 Matlab,其中多维数组的线性索引起作用。)我需要的是 y 上的一维视图,我可以将 [ind] = 应用到,分配给正确的元素。

问题一:多维数组上是否有这样的一维视图?

或者,我可以将y 创建为一维,分配值,然后重塑。

y = np.full(x.size, np.nan)
y[ind] = yu
y = np.reshape(y, x.shape)

这似乎可行,但我不确定是否必须考虑x 的存储顺序。

问题2:np.unique返回的ind是否总是遵循np.reshape默认的'C'顺序,还是取决于x的内部结构?

【问题讨论】:

  • 您的标题与实际问题无关。您可以删除有关应用该功能的整个部分,您的问题仍然是一样的。
  • 我修正了答案中的错别字。

标签: python numpy numpy-ndarray


【解决方案1】:

np.unique 的索引在 raveled 数组上运行。这记录在第一个参数下:

除非指定了 axis,否则如果它还不是一维的,它将被展平。

无论内存布局如何,拉开/展平总是按 C 顺序发生。扁平化只是保证副本的松散。这意味着当您的数组不是 C 顺序时,它会创建一个副本:

>>> x = np.zeros((3, 3), order='F')
>>> x.ravel().base is x
False
>>> y = np.zeros((3, 3))
>>> y.ravel().base is y
True

x.ravel() 等价于x.reshape(-1)。这意味着,如果您可以使用 flat_y.reshape(original_x_shape) 之类的东西来解开结果:

xu, ind = np.unique(x, return_inverse=True)
yu = np.zeros_like(xu)
for i in range(len(xu)):
    yu[i] = fn(xu[i])
y_flat = yu[ind]
y = y_flat.reshape(x.shape)

由于您正在重塑一个连续的缓冲区,yy_flat 共享相同的内存:

>>> y.base is y_flat
True

花哨的索引,如表达式y_flat = yu[ind] 将始终进行复制,因为在一般情况下您无法判断数据是否连续。

线性索引在 MATLAB 中始终有效的部分原因是它保证了连续数组,始终以列优先顺序存储。 Numpy 在每个维度上保持一个长度,因此它支持非连续数组。这允许 numpy 执行诸如转置数组之类的操作,或从中获取简单的切片,而无需复制底层数据。

附带说明,如果您想避免在 y 上显式调用 reshape,可以改为在 ind 上调用它:

xu, ind = np.unique(x, return_inverse=True)
yu = np.zeros_like(xu)
for i in range(len(xu)):
    yu[i] = fn(xu[i])
y = yu[ind.reshape(x.shape)]

【讨论】:

    猜你喜欢
    • 2019-07-25
    • 1970-01-01
    • 2014-04-20
    • 2016-12-30
    • 1970-01-01
    • 2015-02-10
    • 2020-02-24
    • 1970-01-01
    • 2016-08-10
    相关资源
    最近更新 更多