Numpy布尔索引分配有时会失败并分配整个数组

2024-06-02 12:13:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我想简单地为数组的每个元素分配一个标签,基于它低于或高于某个阈值,并使用布尔索引解决这个问题:

def easy_labeling(arr, thresh=5):
  negative_mask = arr < thresh
  positive_mask = arr >= thresh
  labels = np.empty_like(arr, dtype=str)
  labels[negative_mask] = 'N'
  labels[positive_mask] = 'P'
  return labels

到目前为止还不错。我创建了一些虚拟数组来检查它是否工作:

test_arr1 = np.arange(24).reshape((12,2))
test_arr1
>>> test_arr1
array([[ 0,  1],
       [ 2,  3],
       [ 4,  5],
       [ 6,  7],
       [ 8,  9],
       [10, 11],
       [12, 13],
       [14, 15],
       [16, 17],
       [18, 19],
       [20, 21],
       [22, 23]])
easy_labeling(test_arr1)
>>> array([['N', 'N'],
           ['N', 'N'],
           ['N', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P']], dtype='<U1')
test_arr2 = np.random.randint(12, size=(12,2))
test_arr2
>>> array([[ 1, 11],
           [ 5,  6],
           [11,  7],
           [ 9,  4],
           [11,  3],
           [ 0,  9],
           [ 0,  4],
           [11,  8],
           [ 3,  6],
           [ 0,  1],
           [ 5,  8],
           [10,  4]])
easy_labeling(test_arr2)
>>> array([['N', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'N'],
           ['P', 'N'],
           ['N', 'P'],
           ['N', 'N'],
           ['P', 'P'],
           ['N', 'P'],
           ['N', 'N'],
           ['P', 'P'],
           ['P', 'N']], dtype='<U1')

。。。看起来确实如此

但是,在我的特定应用程序中,出现了一些其他数组-形状、类型和数据类型相同,但结果不同:

test_arr3 = np.array([[ 2,  0,  4,  4], [ 0,  2,  9, 11], [ 4,  4,  6, 10], [11,  5, 10, 15], 
[ 5,  8,  0,  8], [ 3,  6,  5, 11], [ 6,  7,  2,  9], [ 1,  1,  1,  2], [ 9, 11,  3, 14], [ 8, 
10,  7, 17], [10,  3, 11, 14], [ 7,  9,  8, 17]])
test_arr3 = test_arr3[:, 1:3]
test_arr3
>>> array([[ 0,  4],
           [ 2,  9],
           [ 4,  6],
           [ 5, 10],
           [ 8,  0],
           [ 6,  5],
           [ 7,  2],
           [ 1,  1],
           [11,  3],
           [10,  7],
           [ 3, 11],
           [ 9,  8]])
easy_labeling(test_arr3):
>>> array([['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P'],
           ['P', 'P']], dtype='<U1')

——>;突然间,所有元素都被标记为正数,即使数组中包含的数字明显低于5。就我所见,索引仍然有效,因此如果我请求arr[mask],我会得到正确的元素,但是分配给它会产生错误的结果

更奇怪的是:在写下这个问题时,我想简化上面的表达式,而不必做“test_arr3=test_arr3[:,1:3]”部分,所以我直接输入了我想要的数组:

test_arr4 = np.array([[0,  4], [2,  9], [4,  6], [5, 10], [8,  0], [6,  5], [7,  2], [1,  1], 
[11,  3], [10,  7], [3, 11], [9,  8]])
test_arr4
>>> array([[ 0,  4],
           [ 2,  9],
           [ 4,  6],
           [ 5, 10],
           [ 8,  0],
           [ 6,  5],
           [ 7,  2],
           [ 1,  1],
           [11,  3],
           [10,  7],
           [ 3, 11],
           [ 9,  8]])
easy_labeling(test_arr4)
>>> array([['N', 'N'],
           ['N', 'P'],
           ['N', 'P'],
           ['P', 'P'],
           ['P', 'N'],
           ['P', 'P'],
           ['P', 'N'],
           ['N', 'N'],
           ['P', 'N'],
           ['P', 'P'],
           ['N', 'P'],
           ['P', 'P']], dtype='<U1')

。。。突然间,它起了作用。即使阵列是一样的(至少看起来是一样的)

我确保所有测试阵列具有相同的类型、形状和数据类型:

for x in [test_arr1, test_arr2, test_arr3, test_arr4]:
...   print(type(x), x.shape, x.dtype)
>>> <class 'numpy.ndarray'> (12, 2) int32
    <class 'numpy.ndarray'> (12, 2) int32
    <class 'numpy.ndarray'> (12, 2) int32
    <class 'numpy.ndarray'> (12, 2) int32

我假设数组有一些我不知道的隐藏属性,整个事情对我来说没有什么意义-有人知道吗


一种解决方法似乎是使用np.chararray(arr.shape,unicode=True)而不是np.empty_-like(arr,dtype=str),但是我仍然想知道另一种解决方案有什么问题


Tags: testlabelseasynpmask数组arrayarr
1条回答
网友
1楼 · 发布于 2024-06-02 12:13:51

这看起来像是输入数组不连续时empty_like如何处理dtype=str的错误。(更新:我为此问题创建了一个numpy bug report。该fix已合并到主开发分支中,并将在下一版本(NumPy 1.22.0)中发布。)

下面是一个令人惊讶的行为的简单例子:

In [66]: a = np.arange(9).reshape(3, 3)

In [67]: b = a[:, ::2]

In [68]: b
Out[68]: 
array([[0, 2],
       [3, 5],
       [6, 8]])

In [69]: x = np.empty_like(b, dtype=str)

In [70]: x
Out[70]: 
array([['', ''],
       ['', ''],
       ['', '']], dtype='<U1')

In [71]: x.strides
Out[71]: (0, 0)

x^{}属性不应为(0, 0)

另一种解决方法(除了您建议的方法之外)是在调用empty_like时使用显式NumPy数据类型而不是str

In [72]: x = np.empty_like(b, dtype='U1')

In [73]: x
Out[73]: 
array([['', ''],
       ['', ''],
       ['', '']], dtype='<U1')

In [74]: x.strides
Out[74]: (8, 4)

相关问题 更多 >