为什么更改一个`np.nan`值会改变pandas数据帧中的所有nan值?

时间:2016-01-15 05:16:44

标签: python numpy pandas nan

当我在整个DataFrame中更改一个值时,它会更改其他值。比较方案1和方案2:

情况1:请注意,我float(np.nan) s只有NaN个值

info_num = np.array([[random.randint(0,9) for x in range(4)]+['ui'],
[random.randint(0,8) for x in range(3)]+[float(np.nan)]+['g'],
[random.randint(0,7) for x in range(2)]+[float(np.nan)]+[90]+[float(np.nan)],
[random.randint(0,9) for x in range(4)]+['q'],
[random.randint(0,9) for x in range(4)]+['w']])

result_df = pd.DataFrame(data=info_num, columns=['G','Bd', 'O', 'P', 'keys'])

result_df = result_df.fillna(0.0)  # does NOT fill in NaNs

方案1的结果只是没有填充NaN的数据帧。

场景2:注意我在一个地方只有None

info_num = np.array([[random.randint(0,9) for x in range(4)]+['ui'],
[random.randint(0,8) for x in range(3)]+[None]+['g'],
[random.randint(0,7) for x in range(2)]+[float(np.nan)]+[90]+[float(np.nan)],
[random.randint(0,9) for x in range(4)]+['q'],
[random.randint(0,9) for x in range(4)]+['w']])

result_df = pd.DataFrame(data=info_num, columns=['G','Bd', 'O', 'P', 'keys'])

result_df = result_df.fillna(0.0)  # this works!?!

即使我只使用“无”填充其中一个NaN值,其他float(np.nan)也会填入0.0,就好像它们也是NaN一样。

为什么NaN之间存在某种关系?

1 个答案:

答案 0 :(得分:1)

第一个info_numdtype='S3'(字符串)。在第二个中,它是dtype=object,是整数的混合,nan(浮点数)和字符串(和None)。

在数据框中,我看到在一个中打印为“nan”的内容,在另一个中打印为NoneNaN的混合。看起来fillnaNoneNaN的处理方式相同,但忽略字符串'nan'。

fillna

的文档
  

使用指定的方法填充NA / NaN值

Pandas NaNnp.nan相同。

fillna使用pd.isnull来确定0.0值的放置位置。

def isnull(obj):
    """Detect missing values (NaN in numeric arrays, None/NaN in object arrays)

对于第二种情况:

In [116]: pd.isnull(result_df)
Out[116]: 
       G     Bd      O      P   keys
0  False  False  False  False  False
1  False  False  False   True  False
2  False  False   True  False   True
3  False  False  False  False  False
4  False  False  False  False  False

(第一个,字符串,案例的全部False

In [121]: info_num0
Out[121]: 
array([['4', '8', '5', '6', 'ui'],
       ['1', '5', '6', 'nan', 'g'],
       ['6', '1', 'nan', '90', 'nan'],
       ['5', '2', '8', '4', 'q'],
       ['1', '6', '4', '3', 'w']], 
      dtype='<U3')
In [122]: info_num
Out[122]: 
array([[1, 8, 3, 0, 'ui'],
       [1, 5, 1, None, 'g'],
       [0, 2, nan, 90, nan],
       [7, 7, 1, 4, 'q'],
       [3, 7, 0, 3, 'w']], dtype=object)

np.nanfloat

In [125]: type(np.nan)
Out[125]: float

如果您已将dtype=object添加到初始数组定义中,则会获得与使用None相同的效果:

In [140]: np.array([[random.randint(0,9) for x in range(4)]+['ui'],
[random.randint(0,8) for x in range(3)]+[np.nan]+['g'],
[random.randint(0,7) for x in range(2)]+[np.nan]+[90]+[np.nan],
[random.randint(0,9) for x in range(4)]+['q'],
[random.randint(0,9) for x in range(4)]+['w']],dtype=object)
Out[140]: 
array([[6, 7, 8, 1, 'ui'],
       [5, 2, 5, nan, 'g'],
       [3, 0, nan, 90, nan],
       [5, 2, 1, 3, 'q'],
       [1, 7, 7, 2, 'w']], dtype=object)

更好的是,将初始数据创建为列表列表,而不是数组。 numpy数组必须统一元素;使用整数,整数,字符串和字符串,只能使用dtype=object。但这只不过是列表中的数组包装器。 Python列表已经允许这种多样性。

In [141]: alist = [[random.randint(0,9) for x in range(4)]+['ui'],
[random.randint(0,8) for x in range(3)]+[np.nan]+['g'],
[random.randint(0,7) for x in range(2)]+[np.nan]+[90]+[np.nan],
[random.randint(0,9) for x in range(4)]+['q'],
[random.randint(0,9) for x in range(4)]+['w']]
In [142]: alist
Out[142]: 
[[4, 0, 2, 6, 'ui'],
 [3, 3, 3, nan, 'g'],
 [3, 5, nan, 90, nan],
 [4, 0, 6, 7, 'q'],
 [0, 8, 3, 8, 'w']]
In [143]: result_df1 = pd.DataFrame(data=alist, columns=['G','Bd', 'O', 'P', 'keys'])
In [144]: result_df1
Out[144]: 
   G  Bd   O   P keys
0  4   0   2   6   ui
1  3   3   3 NaN    g
2  3   5 NaN  90  NaN
3  4   0   6   7    q
4  0   8   3   8    w

我不确定pandas是如何在内部存储的,但是result_df1.values会返回一个对象数组。

In [146]: result_df1.values
Out[146]: 
array([[4, 0, 2.0, 6.0, 'ui'],
       [3, 3, 3.0, nan, 'g'],
       [3, 5, nan, 90.0, nan],
       [4, 0, 6.0, 7.0, 'q'],
       [0, 8, 3.0, 8.0, 'w']], dtype=object)

因此,如果列具有nan,则所有数字都为float(nan是一种浮点数)。前2列保持整数。最后一个是字符串和nan的混合。

但是dtypes表明pandas正在使用结构化数组,每列都是field,并且具有相关的dtype。

In [147]: result_df1.dtypes
Out[147]: 
G         int64
Bd        int64
O       float64
P       float64
keys     object
dtype: object

等效的numpy dtype将是:

dt = np.dtype([('G',np.int64),('Bd',np.int64),('O',np.float64),('P',np.float64), ('keys',object)])

我们可以用这个dtype制作一个结构化数组。我必须将列表列表转换为元组列表(结构化记录):

X = np.array([tuple(x) for x in alist],dt)
制造

array([(4, 0, 2.0, 6.0, 'ui'), 
       (3, 3, 3.0, nan, 'g'),
       (3, 5, nan, 90.0, nan), 
       (4, 0, 6.0, 7.0, 'q'), 
       (0, 8, 3.0, 8.0, 'w')], 
      dtype=[('G', '<i8'), ('Bd', '<i8'), ('O', '<f8'), ('P', '<f8'), ('keys', 'O')])

这可以直接进入熊猫:

In [162]: pd.DataFrame(data=X)
Out[162]: 
   G  Bd   O   P keys
0  4   0   2   6   ui
1  3   3   3 NaN    g
2  3   5 NaN  90  NaN
3  4   0   6   7    q
4  0   8   3   8    w