在Python中从numpy数组中移除NaN(或其他值)的元素对
我有一个包含两列的numpy数组。例如:
a = array([[1, 5, nan, 6],
[10, 6, 6, nan]])
a = transpose(a)
我想高效地遍历这两列,a[:, 0] 和 a[:, 1],并删除任何满足特定条件的配对,在这个例子中就是如果它们是NaN(不是一个数字)。我想到的明显方法是:
new_a = []
for val1, val2 in a:
if val2 == nan or val2 == nan:
new_a.append([val1, val2])
但这样做感觉有点笨。有没有更符合Python风格的numpy做法呢?
谢谢。
4 个回答
3
我并不是想贬低ig0774的回答,他的回答非常正确、符合Python的风格,而且在普通Python中确实是处理这些事情的常规方法。不过,numpy有一个布尔索引系统,也可以完成这个任务。
new_a = a[(a==a).all(1)]
我现在不太确定哪种方法更高效(或者执行得更快)。
如果你想用不同的条件来选择行,那就需要进行相应的更改,具体怎么改要看条件是什么。如果这个条件可以独立地对每个数组元素进行评估,你只需把 a==a
替换成合适的测试条件。例如,如果你想去掉所有大于100的数字所在的行,可以这样做:
new_a = a[(a<=100).all(1)]
但是如果你想做一些复杂的事情,比如去掉所有行的和大于100的行,那可能会复杂一些。如果是这种情况,如果你愿意分享你的具体条件,我可以尝试给出更具体的答案。
3
你可以把这个数组转换成一个掩码数组,然后使用compress_rows
方法:
import numpy as np
a = np.array([[1, 5, np.nan, 6],
[10, 6, 6, np.nan]])
a = np.transpose(a)
print(a)
# [[ 1. 10.]
# [ 5. 6.]
# [ NaN 6.]
# [ 6. NaN]]
b=np.ma.compress_rows(np.ma.fix_invalid(a))
print(b)
# [[ 1. 10.]
# [ 5. 6.]]
31
如果你想要只保留那些没有NAN(缺失值)的行,你需要用这个表达式:
>>> import numpy as np
>>> a[~np.isnan(a).any(1)]
array([[ 1., 10.],
[ 5., 6.]])
如果你想要那些行中没有特定数字,比如5:
>>> a[~(a == 5).any(1)]
array([[ 1., 10.],
[ NaN, 6.],
[ 6., NaN]])
后面的这个表达式其实是等价于:
>>> a[(a != 5).all(1)]
array([[ 1., 10.],
[ NaN, 6.],
[ 6., NaN]])
解释:首先我们来创建一个示例输入
>>> import numpy as np
>>> a = np.array([[1, 5, np.nan, 6],
... [10, 6, 6, np.nan]]).transpose()
>>> a
array([[ 1., 10.],
[ 5., 6.],
[ NaN, 6.],
[ 6., NaN]])
这个步骤是用来确定哪些元素是NAN的
>>> np.isnan(a)
array([[False, False],
[False, False],
[ True, False],
[False, True]], dtype=bool)
这个步骤用来找出哪些行有任何元素是True的
>>> np.isnan(a).any(1)
array([False, False, True, True], dtype=bool)
因为我们不想要这些,所以我们对最后的表达式取反:
>>> ~np.isnan(a).any(1)
array([ True, True, False, False], dtype=bool)
最后,我们用这个布尔数组来选择我们想要的行:
>>> a[~np.isnan(a).any(1)]
array([[ 1., 10.],
[ 5., 6.]])