3

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

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

......似乎确实如此。

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

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

......突然它起作用了。即使数组是相同的(至少看起来如此)!

我确保所有测试数组都具有相同的类型、形状和 dtype:

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),但是我仍然想知道其他解决方案有什么问题。

4

1 回答 1

2

这看起来像是输入数组不连续时如何empty_like处理的错误。dtype=str更新:我为此问题创建了一个numpy 错误报告。该修复已合并到主开发分支中,并将在下一个版本中(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)

strides属性不x应该是(0, 0)

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

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)
于 2021-08-10T13:29:22.000 回答