意外的numpy.unique行为(Unexpected numpy.unique behavior)

编程入门 行业动态 更新时间:2024-10-22 09:52:29
意外的numpy.unique行为(Unexpected numpy.unique behavior)

我正在使用numpy.unique来获取已经使用numpy.ravel展平的蒙版数组的值,索引和计数,并且我得到了意想不到的结果。

如果我手动测试它,如下所示:

>>> import numpy as np >>> a = np.array([[1,2,3],[1,0,0],[2,1,5]]) >>> a array([[1, 2, 3], [1, 0, 0], [2, 1, 5]]) >>> src = np.ma.masked_equal(a, 0) >>> src masked_array(data = [[1 2 3] [1 -- --] [2 1 5]], mask = [[False False False] [False True True] [False False False]], fill_value = 0) >>> src = src.ravel() >>> src masked_array(data = [1 2 3 1 -- -- 2 1 5], mask = [False False False False True True False False False], fill_value = 0) >>> s_values, s_idx, s_counts = np.unique(src, return_inverse=True, return_counts=True) >>> s_values masked_array(data = [1 2 3 5 --], mask = [False False False False True], fill_value = 0) >>> s_counts array([3, 2, 1, 1, 2])

但是,当我从图像文件将相同的逻辑应用于uint8数组时,我得到以下内容:

>>> src_ds = '/Users/histo/S2_10_T_DN_2016_7_27_0_4328_repro.tif' >>> src_ds = gdal.Open(src_ds) >>> src = src_ds.GetRasterBand(1).ReadAsArray() >>> src = np.ma.masked_equal(src, 0) >>> src = src.ravel() >>> s_values, s_idx, s_counts = np.unique(src, return_index=True, return_inverse=True) >>> s_values masked_array(data = [3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255], mask = [False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True ...

由于某种原因,63和掩码一遍又一遍地重复作为唯一值,当然,这会抛出计数和索引,并使得结果不能用于任何后续分析。

我试过用ndimage打开数据,结果是一样的,我试过用其他图像。 再次,我得到重复值掩码值...作为唯一值。

很奇怪。 有人见过这个吗?

I am using numpy.unique to get values, indices and counts on a masked array that has been flattened with numpy.ravel and am getting unexpected results.

If I test it manually as in the following it works:

>>> import numpy as np >>> a = np.array([[1,2,3],[1,0,0],[2,1,5]]) >>> a array([[1, 2, 3], [1, 0, 0], [2, 1, 5]]) >>> src = np.ma.masked_equal(a, 0) >>> src masked_array(data = [[1 2 3] [1 -- --] [2 1 5]], mask = [[False False False] [False True True] [False False False]], fill_value = 0) >>> src = src.ravel() >>> src masked_array(data = [1 2 3 1 -- -- 2 1 5], mask = [False False False False True True False False False], fill_value = 0) >>> s_values, s_idx, s_counts = np.unique(src, return_inverse=True, return_counts=True) >>> s_values masked_array(data = [1 2 3 5 --], mask = [False False False False True], fill_value = 0) >>> s_counts array([3, 2, 1, 1, 2])

However, when I apply this same logic to a uint8 array from an image file I am getting the following:

>>> src_ds = '/Users/histo/S2_10_T_DN_2016_7_27_0_4328_repro.tif' >>> src_ds = gdal.Open(src_ds) >>> src = src_ds.GetRasterBand(1).ReadAsArray() >>> src = np.ma.masked_equal(src, 0) >>> src = src.ravel() >>> s_values, s_idx, s_counts = np.unique(src, return_index=True, return_inverse=True) >>> s_values masked_array(data = [3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 -- 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255], mask = [False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True False True ...

For some reason 63 and mask are repeating over and over as unique values which, of course, throws out the counts and indices and makes the results unusable for any subsequent analysis.

I have tried opening the data with ndimage and the results are the same and I have tried with other images. Again, I get repeating value mask value... as unique values.

Very strange. Has anybody seen this?

最满意答案

TL; DR

通过更改蒙版数组的默认填充值来解决此问题:

import numpy as np x = np.array([64, 0, 1, 2, 3, 63, 63, 0, 0, 0, 1, 2, 0, 63, 0], dtype='uint8') y = np.ma.masked_equal(x, 0) v, i, c = np.unique(y, return_index=True, return_counts=True) print(v) # [1 2 3 -- 63 -- 63 -- 64] np.ma.core.default_filler['u'] = 0 # fill value for unsigned integers np.ma.core.default_filler['i'] = 0 # fill value for unsigned integers v, i, c = np.unique(y, return_index=True, return_counts=True) print(v) # [-- 1 2 3 63 64]

细节

此问题是可重现的,并不适用于图像(注意它只发生在return_index=True ):

import numpy as np x = np.array([64, 0, 1, 2, 3, 62, 62, 0, 0, 0, 1, 2, 0, 62, 0], dtype='uint8') y = np.ma.masked_equal(x, 0) v, i, c = np.unique(y, return_index=True, return_counts=True) print(v) # [1 2 3 62 -- 64] x = np.array([64, 0, 1, 2, 3, 63, 63, 0, 0, 0, 1, 2, 0, 63, 0], dtype='uint8') y = np.ma.masked_equal(x, 0) v, i, c = np.unique(y, return_index=True, return_counts=True) print(v) # [1 2 3 -- 63 -- 63 -- 64] x = np.array([64, 0, 1, 2, 3, 63, 63, 0, 0, 0, 1, 2, 0, 63, 0], dtype='uint8') y = np.ma.masked_equal(x, 0) v = np.unique(y) print(v) # [1 2 3 63 64 --]

显然这与数字63有关。63有什么特别之处? 二进制它是所有的(在8位表示的情况下有两个前导零)。

>>> bin(63) '0b111111'

但是,我不知道为什么这个特定的数字(例如127个作品)在与面具结合时会在np.unique引起奇怪的行为。

这与排序数组有关。 没有return_indices np.unique在内部使用np.sort ,否则它使用np.argsort :

x = np.array([64, 0, 1, 2, 3, 63, 63, 0, 0, 0, 1, 2, 0, 63, 0], dtype='uint8') y = np.ma.masked_equal(x, 0) print(np.sort(y)) # [1 1 2 2 3 63 63 63 64 -- -- -- -- -- --] print(y[np.argsort(y)]) # [1 1 2 2 3 -- 63 63 -- -- -- -- 63 -- 64]

默认情况下, np.ma.argsort使用函数np.ma.default_fill_value在排序期间替换屏蔽值。 int的默认填充值(也用于uint8 )是999999.这是二进制的0b111101000010 00111111 - 最低的8位等于63! 因此,对于排序算法,屏蔽值和63是等效的并且它们是混杂在一起的。

可以更改默认填充值,从而解决问题:

np.ma.core.default_filler['u'] = 0 # fill value for unsigned integers np.ma.core.default_filler['i'] = 0 # fill value for unsigned integers

作为一种解决方法,您可以将数据转换为另一种数据类型,例如浮点的16位整数:

x = np.array([64, 0, 1, 2, 3, 63, 63, 0, 0, 0, 1, 2, 0, 63, 0], dtype='uint8') y = np.ma.masked_equal(x.astype('int16'), 9) v, i, c = np.unique(y, return_index=True, return_counts=True) print(v) # [1 2 3 63 64 --]

特定用例的另一种替代方案是根本不使用掩蔽数组。 由于只有0被掩码替换,因此很容易在结果中忽略0。

TL;DR

Solve the issue by changing the default fill value for masked arrays:

import numpy as np x = np.array([64, 0, 1, 2, 3, 63, 63, 0, 0, 0, 1, 2, 0, 63, 0], dtype='uint8') y = np.ma.masked_equal(x, 0) v, i, c = np.unique(y, return_index=True, return_counts=True) print(v) # [1 2 3 -- 63 -- 63 -- 64] np.ma.core.default_filler['u'] = 0 # fill value for unsigned integers np.ma.core.default_filler['i'] = 0 # fill value for unsigned integers v, i, c = np.unique(y, return_index=True, return_counts=True) print(v) # [-- 1 2 3 63 64]

Details

This problem is reproducible and does not apply specifically to images (note it only happens when return_index=True):

import numpy as np x = np.array([64, 0, 1, 2, 3, 62, 62, 0, 0, 0, 1, 2, 0, 62, 0], dtype='uint8') y = np.ma.masked_equal(x, 0) v, i, c = np.unique(y, return_index=True, return_counts=True) print(v) # [1 2 3 62 -- 64] x = np.array([64, 0, 1, 2, 3, 63, 63, 0, 0, 0, 1, 2, 0, 63, 0], dtype='uint8') y = np.ma.masked_equal(x, 0) v, i, c = np.unique(y, return_index=True, return_counts=True) print(v) # [1 2 3 -- 63 -- 63 -- 64] x = np.array([64, 0, 1, 2, 3, 63, 63, 0, 0, 0, 1, 2, 0, 63, 0], dtype='uint8') y = np.ma.masked_equal(x, 0) v = np.unique(y) print(v) # [1 2 3 63 64 --]

Obviously this has to do with the number 63. What's special about 63? Binary it's all ones (with two leading zeros in case of 8 bit representation).

>>> bin(63) '0b111111'

However, I do not know why this specific number (e.g. 127 works) causes weird behavior in np.unique when combined with masks.

This has to do with sorting the array. Without return_indices np.unique internally uses np.sort and otherwise it uses np.argsort:

x = np.array([64, 0, 1, 2, 3, 63, 63, 0, 0, 0, 1, 2, 0, 63, 0], dtype='uint8') y = np.ma.masked_equal(x, 0) print(np.sort(y)) # [1 1 2 2 3 63 63 63 64 -- -- -- -- -- --] print(y[np.argsort(y)]) # [1 1 2 2 3 -- 63 63 -- -- -- -- 63 -- 64]

By default np.ma.argsort used the function np.ma.default_fill_value to replace masked values during sorting. The default fill value for int (which is used for uint8 too) is 999999. This is in binary 0b11110100001000111111 - The lowest 8 bit are equal to 63! Thus, for the sorting algorithm masked values and 63 are equivalent and they are jumbled together.

It is possible to change the default fill value and thus solve the problem:

np.ma.core.default_filler['u'] = 0 # fill value for unsigned integers np.ma.core.default_filler['i'] = 0 # fill value for unsigned integers

As a workaround you can convert your data to another data type such as 16 bit integers of floating point:

x = np.array([64, 0, 1, 2, 3, 63, 63, 0, 0, 0, 1, 2, 0, 63, 0], dtype='uint8') y = np.ma.masked_equal(x.astype('int16'), 9) v, i, c = np.unique(y, return_index=True, return_counts=True) print(v) # [1 2 3 63 64 --]

Another alternative for the particular use case would be not to use masked arrays at all. Since only 0 is replaced with a mask it would be easy to simply ignore 0 in the result.

更多推荐

本文发布于:2023-04-29 02:49:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1334544.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:意外   numpy   unique   Unexpected   behavior

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!