我有两个二维数组,我必须减go ,但不在相同的维度上,并且这些数组有不同的大小.如果我理解正确的话,有一种叫做广播的东西可以做我需要做的事情,我认为这篇文章(Link)展示了做这件事所需的一切,但我很难将它应用到我的问题上,而且,可能还有一种比我到目前为止所想的更直接的方法.

问题所在

这个问题的一般逻辑是这样的(如下所示,如果您在黑暗模式下,请原谅黑色字体):我有两个数组,目前都在相同的维度上,它们的行(m行和n行)大小不同.在它们当前的形状中,它们只在列中匹配,我想按列将一个数组的每个值减go 另一个数组的每个值.

enter image description here

我不知道哪些函数和操作可以并且应该在没有循环的情况下有效地完成这项工作.我目前有一个循环来完成这项工作,但我在这里处理的数据太大了,需要+12分钟才能完成.

我的 idea

我想我可以首先(1)将第一个数组转置到不同的维度上,然后(2)按照另一个数组的行数重复这一过程,以便在连接时得到一个m*n*500的array.

enter image description here

然后,我对第二个数组执行相同的操作,只是针对不同的维度,并按之前另一个数组的行数重复该操作.然后,当连接时,它们应该具有相同的大小.

enter image description here

然后,最后,我将能够简单地将两个数组相减,而不会有任何维度冲突.

enter image description here

代码示例

在代码方面,这里真的没有什么可展示的.目前,我正在循环访问其中一个数组的行,然后在减法中使用它之前对其进行转置.

self.C = [] # list to hold the resulting arrays
for i in range(self.A.shape[0]): # loop over rows
   A = pd.DataFrame(self.A.iloc[i, :]).T
   C = pd.DataFrame(self.B.to_numpy() - A.to_numpy(), index=self.index)
   self.C.append((self.A.index[i], C))

结果甚至不是3D数组,而是包含索引和2D数组的元组列表.

The Ask

如上所述,我不知道如何在NumPy中做到这一点,而且我很难将类似问题的答案应用到我的问题中.如果你能在这件事上帮忙,我将不胜感激.

推荐答案

TLDR:参见hpaulj's comment.


你说得对,广播才是解决之道!事实上,您对重复数组的可视化表示正是numpy guide on broadcasting可视化该技术的方式.

在您的例子中,假设您从两个数组AB开始(我已经从您美丽的视觉效果中解释了它们):

A.shape == (500, M, 1)
B.shape == (500, N, 1)

并且您的输出C应该具有以下形状:

C.shape == (M, N, 500)

也就是说,我们应该从A(其中M个)中每个长度500个子数组中减go B(其中有N个)中每个长度500个子array.

为了完成您的用例,我们希望数组A"重复"或"堆叠"或"广播"N次,数组B被"重复"或"堆叠"或"广播"M次.广播规则规定,在两个数组之间的某些计算中,数组的形状是右对齐的,并且任何大小为1的轴被广播为与另一个数组中的轴的长度相同.在上面的链接指南中有更多信息.

从这个意义上说:

shape (M, 1, 500) with
shape (1, N, 500)
================= would broadcast to
shape (M, N, 500)

这完全符合要求!

因此,我们只需要对输入数组的轴进行"改组"、"置换"、"重新排序"或"转置"(所有我听说过的对数组轴进行重新排序的术语),就可以将输入数组的轴传播到所需的形状.您可以在NumPy中使用np.ndarray.transpose来做到这一点.举个例子:

>>> M, N = 300, 100
>>> A = np.random.rand(500, M, 1)
>>> B = np.random.rand(500, N, 1)

>>> A.shape
(500, 300, 1)
>>> A.transpose(1, 2, 0).shape
(300, 1, 500)
>>> B.shape
(500, 100, 1)
>>> B.transpose(2, 1, 0).shape
(1, 100, 500)

将它们放在一段代码中:

import numpy as np

M, N = 300, 100
A = np.random.rand(500, M, 1)
B = np.random.rand(500, N, 1)

C = A.transpose(1, 2, 0) - B.transpose(2, 1, 0)
# C.shape == (M, N, 500)

需要注意的一点是,存储没有任何大小为1的轴的数组,并且仅在广播需要时才引入它们的情况要常见得多.例如,您可以从以下位置开始:

A.shape == (M, 500)
B.shape == (N, 500)

在我看来,这是存储数据最自然的方式.现在,为了方便广播,你必须自己介绍尺寸为1的轴.这样做的方式是,在数组AB之间,大小500的轴对齐,而大小MN的轴与新的大小1的轴对齐.

Numpy提供了多种方法来实现这一点,比如Via np.expand_dims甚至np.reshape,但最流行的方法(尤其是在我看来用于促进广播的时候)是用np.newaxis或等价的None来索引.indexing guide中对此行为进行了描述.

然后,您的代码可能如下所示:

import numpy as np

M, N = 300, 100
A = np.random.rand(M, 500)
B = np.random.rand(N, 500)

C = A[:, None, :] - B[None, :, :]
# A[:, None, :].shape == (M, 1, 500)
# B[None, :, :].shape == (1, N, 500)
# C.shape == (M, N, 500)

在我看来,这似乎是C的最自然的轴排序,但当然,您可以在之后使用C = C.transpose(...)重新排序C的轴.

Python相关问答推荐

优化在numpy数组中非零值周围创建缓冲区的函数的性能

Pandas 第二小值有条件

即使在可见的情况下也不相互作用

如何在箱形图中添加绘制线的传奇?

Django mysql图标不适用于小 case

删除最后一个pip安装的包

Python—从np.array中 Select 复杂的列子集

SQLAlchemy Like ALL ORM analog

如何在表中添加重复的列?

如何使用Numpy. stracards重新编写滚动和?

try 检索blob名称列表时出现错误填充错误""

为什么if2/if3会提供两种不同的输出?

如何防止Pandas将索引标为周期?

基于多个数组的多个条件将值添加到numpy数组

Polars map_使用多处理对UDF进行批处理

如何在Python请求中组合多个适配器?

如何反转一个框架中列的值?

如何重新组织我的Pandas DataFrame,使列名成为列值?

如何写一个polars birame到DuckDB

如何从一个维基页面中抓取和存储多个表格?