将Pandas或Numpy Nan替换为None以用于MysqlDB

我试图写一个熊猫数据帧(或可以使用numpy数组)到mysql数据库使用MysqlDB。MysqlDB似乎不理解'nan',我的数据库抛出一个错误,说nan不在字段列表中。我需要找到一种方法将“nan”转换为NoneType。

什么好主意吗?

317604 次浏览

你可以在numpy数组中用None替换nan:

>>> x = np.array([1, np.nan, 3])
>>> y = np.where(np.isnan(x), None, x)
>>> print y
[1.0 None 3.0]
>>> print type(y[1])
<type 'NoneType'>

@bogatron是对的,你可以使用< >强where < / >强,值得注意的是,你可以在pandas中原生这样做:

df1 = df.where(pd.notnull(df), None)

注意:这会将所有列的dtype更改为object

例子:

In [1]: df = pd.DataFrame([1, np.nan])


In [2]: df
Out[2]:
0
0   1
1 NaN


In [3]: df1 = df.where(pd.notnull(df), None)


In [4]: df1
Out[4]:
0
0     1
1  None

注意:你不能做的是重铸DataFrame dtype以允许所有数据类型,使用< >强astype < / >强,然后使用DataFrame < >强fillna < / >强方法:

df1 = df.astype(object).replace(np.nan, 'None')

不幸的是,这都不是,也不使用replace,工作与None这(关闭)问题


顺便说一句,值得注意的是,对于大多数用例,你不需要将NaN替换为None,请参阅这个关于熊猫中NaN和None之间的差异的问题。

然而,在这个特定的情况下,你似乎是这样的(至少在回答这个问题的时候)。

很老了,但我偶然发现了同样的问题。 试着这样做:

df['col_replaced'] = df['col_with_npnans'].apply(lambda x: None if np.isnan(x) else x)

经过一番摸索,这招对我很管用:

df = df.astype(object).where(pd.notnull(df),None)
df = df.replace({np.nan: None})
注意:对于熊猫版本<1.4,所有受影响的dtype更改为object
为了避免这种情况,请使用以下语法:

df = df.replace(np.nan, None)

功劳归于这个Github问题基Huyghe注释上的这个家伙。

只是给@安迪·海登的回答补充了一句:

由于DataFrame.maskDataFrame.where的孪生兄弟,所以它们具有完全相同的签名,但含义相反:

  • DataFrame.where替换条件为False的值。有用
  • DataFrame.mask用于替换条件为True的值。

所以在这个问题中,使用df.mask(df.isna(), other=None, inplace=True)可能更直观。

另一个补充:替换倍数和将列类型从对象转换回浮动时要小心。如果你想确保你的None不会翻转回np.NaN,应用@andy-hayden的建议使用pd.where。 replace仍然会出错的例子:

In [1]: import pandas as pd


In [2]: import numpy as np


In [3]: df = pd.DataFrame({"a": [1, np.NAN, np.inf]})


In [4]: df
Out[4]:
a
0  1.0
1  NaN
2  inf


In [5]: df.replace({np.NAN: None})
Out[5]:
a
0     1
1  None
2   inf


In [6]: df.replace({np.NAN: None, np.inf: None})
Out[6]:
a
0  1.0
1  NaN
2  NaN


In [7]: df.where((pd.notnull(df)), None).replace({np.inf: None})
Out[7]:
a
0  1.0
1  NaN
2  NaN

我相信最简洁的方法是在pandas.DataFrame.to_numpy()方法(文档)中使用na_value参数:

na_value:任意,可选

用于缺失值的值。默认值取决于dtype和DataFrame列的dtypes。

1.1.0新版功能。

例如,你可以使用None替换NaN的字典

columns = df.columns.tolist()
dicts_with_nan_replaced = [
dict(zip(columns, x))
for x in df.to_numpy(na_value=None)
]

您是否有代码块需要检查?

使用.loc, pandas可以基于逻辑条件(过滤)访问记录,并对它们执行操作(当使用=时)。将.loc掩码设置为某个值将改变返回数组原地(所以在这里要小心;我建议在使用代码块之前测试一个df副本)。

df.loc[df['SomeColumn'].isna(), 'SomeColumn'] = None

外层函数是df。loc[row_label, column_label] =无。我们将为row_label使用一个布尔掩码,方法是使用.isna ()方法来查找列SomeColumn中的'NoneType'值。

我们将使用.isna ()方法返回列SomeColumn中的行/记录布尔数组,作为我们的row_label: df (' SomeColumn '] .isna ()。它将分离所有SomeColumn中含有熊猫用.isna ()方法检查的任何'NoneType'项的行。

我们将在屏蔽row_label的数据帧时使用column_label,并在标识要用于.loc掩码的列时使用column_label。

最后,我们将.loc掩码设置为没有一个,因此返回的行/记录将根据掩码索引更改为没有一个

下面是pandas关于.loc &.isna ()

< p >引用:
https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.html https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.isna.html < / p >

这招对我很管用:

df = df.fillna(0)

在替换为where语句之前,将numpy NaN转换为pandas NA:

df = df.replace(np.NaN, pd.NA).where(df.notnull(), None)

在熊猫更新到1.3.2后,我发现推荐的答案和替代建议都不适合我的应用程序,我用蛮力方法解决了安全问题:

buf = df.to_json(orient='records')
recs = json.loads(buf)

None替换np.nan在不同版本的熊猫中完成不同的任务:

if version.parse(pd.__version__) >= version.parse('1.3.0'):
df = df.replace({np.nan: None})
else:
df = df.where(pd.notnull(df), None)

这解决了熊猫版本<1.3.0的问题,如果df中的值已经是None,那么df.replace({np.nan: None})将把它们切换回np.nan(反之亦然)。

还有另一个选择,它确实对我有用:

df = df.astype(object).replace(np.nan, None)

令人惊讶的是,之前的答案都不适合我,所以我不得不对每一列都这样做。

for column in df.columns:
df[column] = df[column].where(pd.notnull(df[column]), None)

现在对我来说,徒手做是唯一可行的方法。

来自@rodney考克斯回答几乎在所有情况下都适用于我。

下面的代码将所有列设置为object数据类型,然后将任何空值替换为None。将列数据类型设置为object非常重要,因为这样可以防止pandas进一步更改类型。

for col in df.columns:
df[col] = df[col].astype(object)
df.loc[df[col].isnull(), col] = None

警告:此解决方案不是有效的,因为它处理的列可能没有np。nan值。