Python 替换数据帧中的NaN表示数字

Python 替换数据帧中的NaN表示数字,python,pandas,dataframe,Python,Pandas,Dataframe,我试图理解为什么用空白代替NaN会减少显示位数 我有数据帧: 0 -3.030889 -3.510211 -3.502291 -3.502357 -3.502817 1 -3.460590 NaN -3.584687 NaN NaN 2 -2.151932 -2.504276 -2.494087 -2.49305

我试图理解为什么用空白代替NaN会减少显示位数

我有数据帧:

0    -3.030889       -3.510211       -3.502291       -3.502357       -3.502817
1    -3.460590             NaN       -3.584687             NaN             NaN
2    -2.151932       -2.504276       -2.494087       -2.493053       -2.493741
3    -2.462477             NaN       -2.556205             NaN             NaN
4    -1.712807       -1.906281       -1.902953       -1.902297       -1.902253
5    -1.883432             NaN       -1.932924             NaN             NaN
使用'df=df.replace(np.nan',regex=True)后,一些数字显示为5位十进制数字

0    -3.030889       -3.51021       -3.502291       -3.50236       -3.50282
1    -3.460590                      -3.584687                                                        
2    -2.151932       -2.50428       -2.494087       -2.49305       -2.49374
3    -2.462477                      -2.556205                                                        
4    -1.712807       -1.90628       -1.902953        -1.9023       -1.90225
5    -1.883432                      -1.932924                               

我如何控制它并保持第一个数据帧中显示数字的精度

正如注释所示,丢失精度的原因是,当您将字符串弹出到一列浮点数中时,pandas被迫将该列的数据类型转换为
对象
。我将试着在这个回答中详细阐述一下这一点。下面是一个例子:

import pandas as pd
import numpy as np
NaN = np.NaN

rows = [[-3.030889, -3.510211, -3.502291, -3.502357, -3.502817],
        [-3.460590, NaN, -3.584687, NaN, NaN],
        [-2.151932, -2.504276, -2.494087, -2.493053, -2.493741],
        [-2.462477, NaN, -2.556205, NaN, NaN],
        [-1.712807, -1.906281, -1.902953, -1.902297, -1.902253],
        [-1.883432, NaN, -1.932924, NaN, NaN]]

df = pd.DataFrame(rows)
print(df)
print(df.dtypes)
print()

new_df = df.replace(np.nan, '', regex=True)
print(new_df)
print(new_df.dtypes)
这将产生:

          0         1         2         3         4
0 -3.030889 -3.510211 -3.502291 -3.502357 -3.502817
1 -3.460590       NaN -3.584687       NaN       NaN
2 -2.151932 -2.504276 -2.494087 -2.493053 -2.493741
3 -2.462477       NaN -2.556205       NaN       NaN
4 -1.712807 -1.906281 -1.902953 -1.902297 -1.902253
5 -1.883432       NaN -1.932924       NaN       NaN
0    float64
1    float64
2    float64
3    float64
4    float64
dtype: object

          0        1         2        3        4
0 -3.030889 -3.51021 -3.502291 -3.50236 -3.50282
1 -3.460590          -3.584687
2 -2.151932 -2.50428 -2.494087 -2.49305 -2.49374
3 -2.462477          -2.556205
4 -1.712807 -1.90628 -1.902953  -1.9023 -1.90225
5 -1.883432          -1.932924
0    float64
1     object
2    float64
3     object
4     object
dtype: object
请注意,无论哪个列的
NaN
'
替换,现在都是
object
类型(上例中的第1、3和4列)。转换为对象时,不仅会丢失精度,还会丢失语义。您的数据不再是所有类型的
float64
。因此,如果您试图对列执行一些操作,这将是很困难的,因为列项不是所有的类型

如果我们在上面代码段的末尾进入
pdb
(通过调用
import pdb;pdb.set_trace()
),我们可以很容易地看到这一点:

(Pdb) df[1].apply(lambda x: x**2)
0    12.321581
1          NaN
2     6.271398
3          NaN
4     3.633907
5          NaN
Name: 1, dtype: float64
(Pdb) new_df[1].apply(lambda x: x**2)
*** TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
您可能希望将所有内容保持为
float64
问题是,用什么替换
NaN
s?答案是:这要视情况而定。
只有你知道你的数据及其代表的内容。这里有几个选项(还有无限多的选项):

您可以选择将它们保留为
NaN
s,这可能是适当的,具体取决于您正在做什么

>>> np.NaN ** 2
nan
>>> np.NaN - 100
nan
>>> np.sqrt(np.NaN)
nan
浮点操作将什么也不做:数据将保持为
NaN
。一些python库还可以处理
NaN
s

另一个选项是用其他浮点值替换
NaN
s。WLOG,假设您试图计算列之间的欧几里德距离,该距离表示模型的某些内容或表示问题的某些值

您可以将
NaN
s替换为一些“遥远”的值。如果您的数据是在[-1,1]的范围内(就像是正弦数据),那么一个好的替代品可能是-999。可以肯定的是-999会将
NaN
列推离其他列w.r.t.欧氏距离足够远。因此,如果您希望使用
NaN
来“惩罚”列,那么您可以这样做

OTOH,也许你想让带有NaN的列只“平均”出w.r.t.欧几里德距离(所以本质上只需要在你的范围内用一个正常值填充NaN)。0是在[-1, 1 ]的中间,所以这可能是个不错的选择。这意味着
NaN
s不会真正“惩罚”或“帮助”w.r.t.欧氏距离。您还可以采用平均值(或其他形式的插值)来计算缺少的值。例如,如果列向量是
[0,1,NaN,.5,NaN,.7]
,则可能需要将其替换为
[0,1,75,5,6,7]
(线性插值)

只有您可以决定什么是合适的替代品。

当你有疑问的时候,试一下。很难预测给定的替换将如何影响大型管道的结果。如果你没有得到你所期望的结果,那么适当地调整你的替换策略,并重新尝试

每种替换策略都有利弊,都会给下游模型/管道带来偏见:只要知道你做了什么,有充分的理由解释奇怪的结果,并解释你可能会带来的偏见。

您可以这样替换
float64
(扩展上述代码):

该输出(保持观察精度):


这可能只是一个代表性问题。您应该检查这两个数据帧并比较它们的值(对于非NaN单元格),看它们是否仍然相等。只需减去旧列和新列,看看得到的列值是多少。注意:
df=df.replace(np.nan,,,regex=True)
替换NaNs的方法似乎不正确。您现在正在将浮点数转换为字符串;这实际上可以解释您的问题:第一帧中的单元格是浮点,第二帧中的单元格是字符串。用适当的浮点值替换NaN,例如0、1、np.inf或任何您认为最合适的值。这是
Replace
操作的副作用,您通过插入空字符串将数据类型从
float64
更改为
object
(以支持混合数据类型)。一旦你这样做了,你就引入了一个新的痛苦世界。为什么要这样做?
NaN有什么问题
为什么不保持类型一致性?为什么不用浮子代替NAN?使用
fill_value = 0.0 # Make sure it's a float. Only you can decide what it should be.
float_df = df.fillna(fill_value)
print(float_df)
print(float_df.dtypes)
          0         1         2         3         4
0 -3.030889 -3.510211 -3.502291 -3.502357 -3.502817
1 -3.460590  0.000000 -3.584687  0.000000  0.000000
2 -2.151932 -2.504276 -2.494087 -2.493053 -2.493741
3 -2.462477  0.000000 -2.556205  0.000000  0.000000
4 -1.712807 -1.906281 -1.902953 -1.902297 -1.902253
5 -1.883432  0.000000 -1.932924  0.000000  0.000000
0    float64
1    float64
2    float64
3    float64
4    float64
dtype: object