首页 > 解决方案 > 使用 Numpy PYthon 在值之间签入

问题描述

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

价值观:

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')

香草蟒:

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]])))))

麻木版本:

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]

标签: pythonarraysfunctionnumpymultidimensional-array

解决方案


上一个问题的答案:

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]

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

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])

推荐阅读