比较 2 个包含不同类型和 NaN 值的结构化数组
Posted
技术标签:
【中文标题】比较 2 个包含不同类型和 NaN 值的结构化数组【英文标题】:Comparing 2 Structured Arrays that contain values of different types and NaNs 【发布时间】:2021-06-16 08:37:44 【问题描述】:所以我有 2 个结构化的 Numpy 数组:
a = numpy.array([('2020-01-04', 'Test', 1, 1.0),
('2020-01-05', 'Test2', 2, NaN)],
dtype=[('Date', 'M8[D]'), ('Name', 'S8'), ('idx', 'i8'), ('value', 'f8')])
b = numpy.array([('2020-01-04', 'Test', 2, 1.0),
('2020-01-05', 'Test2', 2, NaN)],
dtype=[('Date', 'M8[D]'), ('Name', 'S8'), ('idx', 'i8'), ('value', 'f8')])
我需要比较这 2 个数组并获得一个包含 True/False
值的数组,这些值将指示数组中的哪些索引不同。
做类似的事情:
not_same = np.full(shape=a.shape, dtype=bool, fill_value=False)
for field in a.dtype.names:
not_same = np.logical_or(not_same,
a[field] != b[field])
工作到一定程度,但NaN != NaN
的比较实际上是True
,所以我需要使用np.allclose
之类的东西,但只有当你比较的值是浮点数时你才能这样做(字符串爆炸)。
所以我需要以下两件事之一:
-
确定
a[field]
中的值是否为浮点数
或
-
一种比较 2 个数组的方法,可以比较 2 个 NaN 值,结果为真
以下关于错误的请求:
dt = np.dtype([('string', 'S10'), ('val', 'f8')])
arr = np.array([('test', 1.0)], dtype=dt)
np.isreal(arr['string'])
使用 Python 3.8.5 在 Ubuntu 20.04 上运行
【问题讨论】:
这是您可以使用的解决方案.... ***.com/questions/10710328/… 所以你想要NaN == NaN
?好吧,根据 NaN 的定义,这不是真的。
我给你的链接(上面)是我能得到的最接近 Nan == Nan = True 解决方案的链接。通过那个。我认为我们可以结束这个问题,因为这已经被问及回答了
@JoeFerndz 这可以生成单个值而不是一组值。此外,我希望我们能走得更远一点,然后进行例外比较。在问我之前我已经看到了这个问题
@a_guest 是的。 np.allclose
可以选择让比较返回 True
但要调用它,您需要知道数组中值的类型。
【参考方案1】:
这是我能够用来解决此问题的解决方法。这并不漂亮,但会检查所有元素,比较并提供答案。如果 np.Nan == np.Nan,您可以扩展它以找到将答案更改为 True 的方法。
import numpy as np
a = np.array([('2020-01-04', 'Test', 1, 1.0),
('2020-01-05', 'Test2', 2, np.NaN)],
dtype=[('Date', 'M8[D]'), ('Name', 'S8'), ('idx', 'i8'), ('value', 'f8')])
b = np.array([('2020-01-04', 'Test', 2, 1.0),
('2020-01-05', 'Test2', 2, np.NaN)],
dtype=[('Date', 'M8[D]'), ('Name', 'S8'), ('idx', 'i8'), ('value', 'f8')])
idx_ab = []
for i,j in zip(a,b):
for x,y in zip(i,j):
if (isinstance(x, float) and np.isnan(x)) or (isinstance(y, float) and np.isnan(y)):
idx_ab.append(False)
elif x == y:
idx_ab.append(True)
else:
idx_ab.append(False)
print (idx_ab)
输出将是:
[True, True, False, True, True, True, True, False]
不幸的是,您不能只检查 np.isnan(x,y)。如果要检查,x 和 y 都必须是浮动的。如果它是一个字符串,它会给你一个错误。所以在检查nan之前需要先检查isinstance。
另一种方法是使用我共享链接的 np.isclose() 或 np.allclose() 选项:
comparing numpy arrays containing NaN
如果要分别检查a和b中的每个元素,可以给出:
idx_ab = []
for i,j in zip(a,b):
ab = []
for x,y in zip(i,j):
if (isinstance(x, float) and np.isnan(x)) or (isinstance(y, float) and np.isnan(y)):
ab.append(False)
elif x == y:
ab.append(True)
else:
ab.append(False)
idx_ab.append(ab)
print (idx_ab)
这个输出将是:
[[True, True, False, True], [True, True, True, False]]
如果您希望 np.NaN == np.NaN 的结果为 True,请将其添加为第一个条件,然后是其余条件:
if (isinstance(x, float) and isinstance(y, float) and all(np.isnan([x,y]))): ab.append(True)
这将导致上述答案为:
[[True, True, False, True], [True, True, True, True]]
最后一个值设置为 True,因为 a[1][3]
是 np.NaN
,b[1][3]
是 np.NaN
。
【讨论】:
arr2 = np.array([1, 2.1, 3.3, np.nan, 2]) arr1 = np.array([1, 2.0, 3.3, np.nan, 3]) arr1 == arr2 array([ True, False, True, False, False])
这里有些不对劲:nan == nan
应该是错误的:***.com/questions/20320022/…
同意。我试过很多次。它显示 False 没有几个值。当我向数组添加更多值时,它显示为 True。奇怪的行为。在我的另一台 Mac 上检查它是否有不同的行为
查看我的新回复。希望它能解决问题。然而,这不是优雅的方式。【参考方案2】:
试试isclose
(或allclose
),然后发现错误。我在下面看到的错误发生在 isclose
代码的早期,因此不会有太多的时间损失。
In [129]: for field in a.dtype.names:
...: print(field, a[field], b[field])
...: try:
...: print("1st", np.isclose(a[field],b[field],equal_nan=True))
...: except TypeError as f:
...: print(f)
...: print("2nd",a[field]==b[field])
...:
...:
Date ['2020-01-04' '2020-01-05'] ['2020-01-04' '2020-01-05']
The DTypes <class 'numpy.dtype[float16]'> and <class 'numpy.dtype[datetime64]'> do not have a common DType. For example they cannot be stored in a single array unless the dtype is `object`.
2nd [ True True]
Name [b'Test' b'Test2'] [b'Test' b'Test2']
ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
2nd [ True True]
idx [1 2] [2 2]
1st [False True]
value [ 1. nan] [ 1. nan]
1st [ True True]
【讨论】:
以上是关于比较 2 个包含不同类型和 NaN 值的结构化数组的主要内容,如果未能解决你的问题,请参考以下文章