【问题标题】:Checking in between values with Numpy PYthon使用 Numpy PYthon 在值之间签入
【发布时间】:2026-02-02 09:30:01
【问题描述】:

我正在尝试将下面的代码转换为 Numpy 版本。 vanilla python 代码检查Formating 的先前值和当前值,并检查Numbers 值是否在它们之间。这段代码的 Numpy 版本有问题,我该如何修复它?代码来自问题:issue link

价值观:

Numbers = np.array([3, 4, 5, 7, 8, 10,20])
Formating = np.array([0, 2 , 5, 12, 15, 22])
x = np.sort(Numbers);
l = np.searchsorted(x, Formating, side='left')

原版 Python:

for i in range(len(l)-1):
    if l[i] >= l[i+1]:
        print('Numbers between %d,%d = _0_' % (Formating[i], Formating[i+1]))
    else:
        print('Numbers between %d,%d = %s' % (Formating[i], Formating[i+1], ','.join(map(str, list(x[l[i]:l[i+1]])))))

Numpy 版本:

L_index = np.arange(0, len(l)-1, 1)
result= np.where(l[L_index] >= l[L_index+1], 0 , l )

预期输出:

[0]
[3 4]
[5 7 8 10]
[0]
[20]

【问题讨论】:

  • 如果您希望列表(或数组)的长度不同,这很好地表明“纯”numpy 选项是不可能的。数组是“矩形的”,而不是“参差不齐的”。有一些技巧可以创建填充数组或掩码数组。
  • (Numbers[:,None]>=Formats[:-1]) & (Numbers[:,None]<=Formats[1:]) 可能是有用的第一步。它应该是一个 2d 布尔数组,其中数字在所需格式范围内为 True。

标签: python arrays function numpy multidimensional-array


【解决方案1】:

上一个问题的答案:

In [173]: Numbers = np.array([3, 4, 5, 7, 8, 10,20])
     ...: Formating = np.array([0, 2 , 5, 12, 15, 22])
     ...: x = np.sort(Numbers);
     ...: l = np.searchsorted(x, Formating, side='left')
     ...: 
In [174]: l
Out[174]: array([0, 0, 2, 6, 6, 7])
In [175]: for i in range(len(l)-1):
     ...:     if l[i] >= l[i+1]:
     ...:         print('Numbers between %d,%d = _0_' % (Formating[i], Formating[i+1]))
     ...:     else:
     ...:         print('Numbers between %d,%d = %s' % (Formating[i], Formating[i+1], ','.jo
     ...: in(map(str, list(x[l[i]:l[i+1]])))))
     ...: 
Numbers between 0,2 = _0_
Numbers between 2,5 = 3,4
Numbers between 5,12 = 5,7,8,10
Numbers between 12,15 = _0_
Numbers between 15,22 = 20

与列表一起工作的东西 - 实际上列表比数组更快:

In [182]: for i in range(len(Formating)-1):
     ...:     print([x for x in Numbers if (Formating[i]<=x<Formating[i+1])])
     ...: 
[]
[3, 4]
[5, 7, 8, 10]
[]
[20]

Formating 上迭代的版本,但不是Numbers。与使用searchsorted 的版本相当相似。我不确定哪个会更快:

In [177]: for i in range(len(Formating)-1):
     ...:     idx = (Formating[i]<=Numbers)&(Numbers<Formating[i+1])
     ...:     print(Numbers[idx])
     ...: 
[]
[3 4]
[ 5  7  8 10]
[]
[20]

我们可以一次获得Formating 的所有值的idx 掩码:

In [183]: mask=(Formating[:-1,None]<=Numbers)&(Numbers<Formating[1:,None])
In [184]: mask
Out[184]: 
array([[False, False, False, False, False, False, False],
       [ True,  True, False, False, False, False, False],
       [False, False,  True,  True,  True,  True, False],
       [False, False, False, False, False, False, False],
       [False, False, False, False, False, False,  True]])
In [185]: N=Numbers[:,None].repeat(5,1).T   # 5 = len(Formating)-1
In [186]: N
Out[186]: 
array([[ 3,  4,  5,  7,  8, 10, 20],
       [ 3,  4,  5,  7,  8, 10, 20],
       [ 3,  4,  5,  7,  8, 10, 20],
       [ 3,  4,  5,  7,  8, 10, 20],
       [ 3,  4,  5,  7,  8, 10, 20]])
In [187]: np.ma.masked_array(N,~mask)
Out[187]: 
masked_array(
  data=[[--, --, --, --, --, --, --],
        [3, 4, --, --, --, --, --],
        [--, --, 5, 7, 8, 10, --],
        [--, --, --, --, --, --, --],
        [--, --, --, --, --, --, 20]],
  mask=[[ True,  True,  True,  True,  True,  True,  True],
        [False, False,  True,  True,  True,  True,  True],
        [ True,  True, False, False, False, False,  True],
        [ True,  True,  True,  True,  True,  True,  True],
        [ True,  True,  True,  True,  True,  True, False]],
  fill_value=999999)

您的列表在那里很明显。但是列表显示还是需要迭代的:

In [188]: for row in mask:
     ...:     print(Numbers[row])
[]
[3 4]
[ 5  7  8 10]
[]
[20]

我会让你用这个或更真实的数据来测试这些替代方案。我怀疑纯列表版本对于小问题最快,但我不确定其他版本将如何扩展。

编辑

以下问题询问总和。 np.ma.sum,或掩码数组自己的sum 方法,对未掩码值求和,有效地用 0 填充掩码值。

In [253]: np.ma.masked_array(N,~mask).sum(axis=1)
Out[253]: 
masked_array(data=[--, 7, 30, --, 20],
             mask=[ True, False, False,  True, False],
       fill_value=999999)

In [256]: np.ma.masked_array(N,~mask).filled(0)
Out[256]: 
array([[ 0,  0,  0,  0,  0,  0,  0],
       [ 3,  4,  0,  0,  0,  0,  0],
       [ 0,  0,  5,  7,  8, 10,  0],
       [ 0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0, 20]])

其实我们并不需要使用掩码数组机制来到达这里(虽然它在视觉上可以很好):

In [258]: N*mask
Out[258]: 
array([[ 0,  0,  0,  0,  0,  0,  0],
       [ 3,  4,  0,  0,  0,  0,  0],
       [ 0,  0,  5,  7,  8, 10,  0],
       [ 0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0, 20]])
In [259]: (N*mask).sum(axis=1)
Out[259]: array([ 0,  7, 30,  0, 20])

【讨论】:

  • 有没有办法让我可以将 -- 替换为掩码数组中的零。我尝试实现np.where(result != "--", result, 0),不管它工作的是谁。这是你答案的最后一个例子。
  • 当迭代行(打印行)时,只需对 [] 进行测试并替换你想要的。但是任何这样的调整都会让你远离一个“纯”的 numpy 解决方案。匹配列表的长度和匹配的数量是最合乎逻辑的选择。