考虑其列保存取自1、2、3的随机值的数组a:

a = np.array([[2, 3, 1, 3],
              [3, 2, 1, 3],
              [1, 1, 1, 2],
              [1, 3, 2, 3],
              [3, 3, 1, 3],
              [2, 1, 3, 2]])

现在,考虑数组b,其前2列保存了9个可能的值对,取自1,2,3(元素对的顺序很重要). 第3列的b将一个非负整数与每个配对相关联.

b = np.array([[1, 1, 6],
              [1, 2, 0],
              [1, 3, 9],
              [2, 1, 6],
              [2, 2, 0],
              [2, 3, 4],
              [3, 1, 1],
              [3, 2, 0],
              [3, 3, 8]])

我需要帮助生成数组c的代码,其中a中的垂直相邻元素被b的第三列中的匹配值替换. 例如,'a'的第一列从2到3向下移动到1到1到3到2. 因此,c的第一列将保存值4,1,6,9,0. 同样的概念适用于a的每一列. 我们看到,对的顺序很重要(从3移动到1产生值1,而从1移动到3产生值9.

这个小例子的输出是:

c = np.array([[4, 0, 6, 8],
              [1, 6, 6, 0],
              [6, 9, 0, 4],
              [9, 8, 6, 8],
              [0, 1, 9, 0]])

因为这个代码将被执行大量次,我希望有一个快速的矢量化解决方案.

推荐答案

由于b包含了所有的对,你可以有效地将其重新塑造为正方形,并按其行数/列数索引,然后用sliding_window_view形成索引对,并索引正方形中间:

from numpy.lib.stride_tricks import sliding_window_view as swv

s = np.full((b[:, 0].max()+1, b[:, 1].max()+1), -1)
s[b[:, 0], b[:, 1]] = b[:, 2]

v = swv(a, 2, axis=0)
out = s[v[..., 0], v[..., 1]]

具有基于0的索引的变体(产生稍微更紧凑的中间部分):

s = np.full((b[:, 0].max(), b[:, 1].max()), -1)
s[b[:, 0]-1, b[:, 1]-1] = b[:, 2]

v = swv(a, 2, axis=0)-1
out = s[v[..., 0], v[..., 1]]

输出:

array([[4, 0, 6, 8],
       [1, 6, 6, 0],
       [6, 9, 0, 4],
       [9, 8, 6, 8],
       [0, 1, 9, 0]])

中级s:

array([[-1, -1, -1, -1],
       [-1,  6,  0,  9],
       [-1,  6,  0,  4],
       [-1,  1,  0,  8]])

# variant
array([[6, 0, 9],
       [6, 0, 4],
       [1, 0, 8]])

If you had arbitrary values making it difficult to generate a dense square intermediate, you could use 's merge:

from numpy.lib.stride_tricks import sliding_window_view as swv
import pandas as pd

out = (pd.DataFrame(swv(a, 2, axis=0).reshape(-1, 2))
         .merge(pd.DataFrame(b), how='left')
         [2].to_numpy()
         .reshape(-1, a.shape[1])
       )

输出:

array([[4, 0, 6, 8],
       [1, 6, 6, 0],
       [6, 9, 0, 4],
       [9, 8, 6, 8],
       [0, 1, 9, 0]])

timings

对于密集输入(即索引为0—n(或1—n)的形式而没有缺失索引),具有1->N个索引的正方形NxN a(N = a0):>>

# numpy
16.5 ms ± 941 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# pandas
173 ms ± 17 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

使用稀疏输入(索引是从更大的集合中 Select 的N个值;这里是从50_000个可能性中 Select 的N0个值;~2%密度;~0.04%密度以正方形形式表示):

# numpy
5.04 s ± 2.5 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

# pandas
192 ms ± 13.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Python相关问答推荐

如何根据日期和时间将状态更新为已过期或活动?

如何在Windows上用Python提取名称中带有逗号的文件?

输出中带有南的亚麻神经网络

按顺序合并2个词典列表

为什么sys.exit()不能与subproccess.run()或subprocess.call()一起使用

如何获得每个组的时间戳差异?

Django admin Csrf令牌未设置

在Python中调用变量(特别是Tkinter)

基于行条件计算(pandas)

matplotlib图中的复杂箭头形状

在matplotlib中使用不同大小的标记顶部添加批注

Pandas—堆栈多索引头,但不包括第一列

我对这个简单的异步者的例子有什么错误的理解吗?

freq = inject在pandas中做了什么?''它与freq = D有什么不同?''

Python类型提示:对于一个可以迭代的变量,我应该使用什么?

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

我可以不带视频系统的pygame,只用于游戏手柄输入吗?''

Python日志(log)库如何有效地获取lineno和funcName?

一维不匹配两个数组上的广义ufunc

是否需要依赖反转来确保呼叫方和被呼叫方之间的分离?