用None替换Pandas或Numpy Nan,以便与MyqlDB一起使用



我正在尝试使用MysqlDB将Pandas数据帧(或者可以使用numpy数组(写入mysql数据库。MySQL数据库似乎不理解"nan",我的数据库抛出一个错误,说nan不在字段列表中。我需要找到一种方法将"nan"转换为NoneType。

有什么想法吗?

@bogatron是对的,你可以使用where,值得注意的是,你可以在Panda中原生地做到这一点:

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

注意:这会将所有列的数据类型更改为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

注意:您不能使用astype重写DataFrames dtype以允许所有数据类型,然后使用fillna方法:

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

不幸的是,无论是这一点,还是使用replace,都不能与None一起使用—请参阅此(已关闭(问题


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

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

df = df.replace({np.nan: None})

注意:对于熊猫版本<1.4,这将所有受影响的的数据类型更改为object
为了避免这种情况,请使用以下语法:

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

这要归功于这个Github问题上的家伙和Killian Huyghe的评论。

您可以在numpy数组中将nan替换为None

>>> 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'>

在跌跌撞撞之后,这对我来说很有效:

df = df.astype(object).where(pd.notnull(df),None)

None替换np.nan在不同版本的Panda中的实现方式不同:

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,反之亦然

另一个补充:在替换倍数和将列的类型从对象转换回浮点时要小心。如果你想确定你的None不会回到np.NaN,那么就用pd.where来应用@andy hayden的建议。更换仍然可能出现"错误"的说明:

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

只是对@Andy Hayden的回答的补充:

由于DataFrame.maskDataFrame.where的对双胞胎,它们具有完全相同的签名,但含义相反:

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

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

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

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

我认为最干净的方法是在pandas.DataFrame.to_numpy()方法(docs(中使用na_value参数:

na_value:任意,可选

用于缺少值的值。默认值取决于数据类型和DataFrame列的数据类型。

1.1.0版本新增。

例如,您可以使用转换为NaN替换为None的词典

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

有时最好使用此代码。注意,np指的是numpy:

df = df.fillna(np.nan).replace([np.nan], [None])

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

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

令人惊讶的是,以前的答案都不适用于我,所以我必须为每一列都这样做。

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

您有一个代码块可以偶然查看吗?

使用.loc,panda可以根据逻辑条件访问记录(筛选(并对其执行操作(使用=时(。将.loc掩码设置为某个值将更改返回数组的位置(所以这里要小心;我建议在代码块中使用之前测试df副本(。

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

外部函数为df.loc[row_label,column_label]=None。我们将使用.isna((方法在我们的列SomeColumn中查找"NoneType"值,从而为row_label使用布尔掩码。

我们将使用.isna((方法返回列SomeColumn中的行/记录的布尔数组,作为我们的row_labeldf['SomeColumn'].isna。

在为row_label屏蔽数据帧时,以及在为.loc屏蔽识别要操作的列时,我们都将使用column_label。

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

以下是有关.loc&.isna((.

参考文献:
https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.htmlhttps://pandas.pydata.org/docs/reference/api/pandas.DataFrame.isna.html

在Pandas更新到1.3.2后,我发现推荐的答案和建议的替代答案都不适用于我的应用程序,我决定使用暴力方法来确保安全:

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

还有一个选项,它实际上对我很有帮助:

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

手工操作是目前对我唯一有效的方法。

这个来自@rodney cox的软件几乎在所有情况下都对我有效。

以下代码将所有列设置为object数据类型,然后将任何null值替换为None。将列数据类型设置为object至关重要,因为它可以防止panda进一步更改类型。

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

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

这应该可以工作:df["column"]=df["column"].apply(lambda x:如果pd.isnull(x(else x,则为None(

这对我有效:

df = df.fillna(0)

最新更新