我试图理解为什么用空格替换NaN会减少显示位数。
我有DataFrame:
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
如何控制它并保持像第一个DataFrame中那样显示数字的精度?
答案 0 :(得分:1)
正如评论所建议的那样,您失去精度的原因是因为当您将字符串弹出到浮点数列中时,pandas被迫将该列的dtype转换为object
。我将在此答案中尝试详细说明。这是一个示例:
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
替换为什么?答案是:取决于。只有您知道您的数据及其代表什么。这里有几个选择(还有更多选择):
您可以选择将其保留为NaN
,具体取决于您的工作。
>>> np.NaN ** 2
nan
>>> np.NaN - 100
nan
>>> np.sqrt(np.NaN)
nan
浮点运算将什么都不做:数据将保持为NaN
。某些python库也可以处理NaN
,它们非常好用。
另一个选择是将NaN
替换为其他一些浮点值。 WLOG,假设您正在尝试计算列之间的欧几里得距离,该距离代表了模型的某些含义或代表了问题的某些价值。
您可以将NaN
替换为一些“远”值。如果您的数据的大小为[-1,1](如正弦数据一样),那么一个很好的替代值可能是-999。可以肯定地认为-999将NaN
的列与其他列相距足够远。欧氏距离。因此,如果您希望使用NaN
“惩罚”列,那么您可以这样做。
OTOH,也许您希望包含NaN的列仅对w.r.t进行“平均”。欧氏距离(因此本质上只需在NaN中使用您范围内的有效值即可)。 0在[-1,1]的中间,所以它可能是一个不错的选择。这意味着NaN
不会真正“惩罚”或“帮助”他人。欧氏距离。您也可以取平均值(或其他某种形式的插值)来计算缺失值。例如,如果您的列向量是[0, 1, NaN, .5, NaN, .7]
,则可能要用[0, 1, .75, .5, .6, .7]
(线性插值)代替。
只有您可以决定什么是合适的替代品。
如有疑问,只需尝试。很难预测给定的替换将如何影响大型管道中的结果。如果您没有在下游获得预期的结果,请适当调整替代策略,然后再进行尝试。
每种替换策略都有其优缺点,并且会给您的下游模型/管道带来偏差:只知道您做了什么,并有充分的理由解释奇怪的结果并解释您可能会引入的偏差。
您可以像这样float64
进行替换(扩展上面的代码):
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