为什么 NaN 的 pandas 数据帧值不能用作字典键?
Why can't a pandas dataframe value of NaN be used as a dictionary key?
我正在尝试使用以下数据框中 values
列的元素作为字典中的键。
In [1]: import numpy as np
...: import pandas as pd
...: rng = pd.date_range('2021-06-01', periods=4)
...: values = [1, -1, 0, np.nan]
...: df = pd.DataFrame(values, index=rng, columns=['values'])
In [2]: df
Out[2]:
values
2021-06-01 1.0
2021-06-02 -1.0
2021-06-03 0.0
2021-06-04 NaN
目标是将 values
列的元素映射到单独列中的一组新值以生成以下数据框:
values new_values
2021-06-01 1.0 A
2021-06-02 -1.0 B
2021-06-03 0.0 C
2021-06-04 NaN D
所以我创建了一个字典,其中键作为 values
列中的元素。
In [3]: repl = {1: 'A', 0: 'B', -1: 'C',np.nan: 'D'}
In [4]: df['rule'] = df['Val'].apply(lambda x: repl[x])
然而,'NaN' 正在创建一个密钥错误(尽管它是可哈希的)。
KeyError Traceback (most recent call last)
<ipython-input-143-2e9d3caa7f9c> in <module>
----> 1 df['rule'] = df['Val'].apply(lambda x: repl[x])
~/opt/miniconda3/envs/PyAlgo/lib/python3.7/site-packages/pandas/core/series.py in apply(self, func, convert_dtype, args, **kwds)
4136 else:
4137 values = self.astype(object)._values
-> 4138 mapped = lib.map_infer(values, f, convert=convert_dtype)
4139
4140 if len(mapped) and isinstance(mapped[0], Series):
pandas/_libs/lib.pyx in pandas._libs.lib.map_infer()
<ipython-input-143-2e9d3caa7f9c> in <lambda>(x)
----> 1 df['rule'] = df['Val'].apply(lambda x: repl[x])
KeyError: nan
显然,我可以为这个简单的示例手动创建列。但是,这只是一个最低限度的可重现示例。实际上,我有一个更大的数据框,其中包含更多潜在的键。
两个问题:
- 为什么 'NaN' 尽管它是可散列的但仍会生成密钥错误?
- 解决这个问题的最佳方法是什么?一种可能性是将 'NaN' 值设置为另一个值,例如原始数据框中的 -999?
您可以使用df["column"].map(dict)
>>> df["new_values"] = df["values"].map(repl)
>>> df
values new_values
2021-06-01 1.0 A
2021-06-02 -1.0 C
2021-06-03 0.0 B
2021-06-04 NaN D
我认为解释与以下事实有关:python 确定键是否在字典中的方式是 1. 散列键并对照字典检查它,然后 2. 检查使确保它正在寻找的键 is
它在字典中找到的键。
问题是虽然np.nan is np.nan
returnsTrue
,np.float64(np.nan) is np.float(np.nan)
returnsFalse
。同样,np.float64(np.nan) is np.nan
returns False
.
我猜你的 apply
函数不起作用的原因是你创建的 lambda 函数试图在字典 repl
并没有找到它。即使您的原始数据只包含 np.nan
,似乎 pandas 将其转换为 numpy.float64
类型。
例如
a = pd.DataFrame([[np.nan, 0], [1,1]])
a[0][0], type(a[0][0]), type(np.nan)
>> nan, numpy.float64, float
另一方面,map
将字典作为参数,专门用于处理某些值缺失或等于 np.nan
的情况(参见:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.map.html)
有关在字典中使用 nan
作为键的更多信息,请参阅此问题:NaNs as key in dictionaries
我正在尝试使用以下数据框中 values
列的元素作为字典中的键。
In [1]: import numpy as np
...: import pandas as pd
...: rng = pd.date_range('2021-06-01', periods=4)
...: values = [1, -1, 0, np.nan]
...: df = pd.DataFrame(values, index=rng, columns=['values'])
In [2]: df
Out[2]:
values
2021-06-01 1.0
2021-06-02 -1.0
2021-06-03 0.0
2021-06-04 NaN
目标是将 values
列的元素映射到单独列中的一组新值以生成以下数据框:
values new_values
2021-06-01 1.0 A
2021-06-02 -1.0 B
2021-06-03 0.0 C
2021-06-04 NaN D
所以我创建了一个字典,其中键作为 values
列中的元素。
In [3]: repl = {1: 'A', 0: 'B', -1: 'C',np.nan: 'D'}
In [4]: df['rule'] = df['Val'].apply(lambda x: repl[x])
然而,'NaN' 正在创建一个密钥错误(尽管它是可哈希的)。
KeyError Traceback (most recent call last)
<ipython-input-143-2e9d3caa7f9c> in <module>
----> 1 df['rule'] = df['Val'].apply(lambda x: repl[x])
~/opt/miniconda3/envs/PyAlgo/lib/python3.7/site-packages/pandas/core/series.py in apply(self, func, convert_dtype, args, **kwds)
4136 else:
4137 values = self.astype(object)._values
-> 4138 mapped = lib.map_infer(values, f, convert=convert_dtype)
4139
4140 if len(mapped) and isinstance(mapped[0], Series):
pandas/_libs/lib.pyx in pandas._libs.lib.map_infer()
<ipython-input-143-2e9d3caa7f9c> in <lambda>(x)
----> 1 df['rule'] = df['Val'].apply(lambda x: repl[x])
KeyError: nan
显然,我可以为这个简单的示例手动创建列。但是,这只是一个最低限度的可重现示例。实际上,我有一个更大的数据框,其中包含更多潜在的键。
两个问题:
- 为什么 'NaN' 尽管它是可散列的但仍会生成密钥错误?
- 解决这个问题的最佳方法是什么?一种可能性是将 'NaN' 值设置为另一个值,例如原始数据框中的 -999?
您可以使用df["column"].map(dict)
>>> df["new_values"] = df["values"].map(repl)
>>> df
values new_values
2021-06-01 1.0 A
2021-06-02 -1.0 C
2021-06-03 0.0 B
2021-06-04 NaN D
我认为解释与以下事实有关:python 确定键是否在字典中的方式是 1. 散列键并对照字典检查它,然后 2. 检查使确保它正在寻找的键 is
它在字典中找到的键。
问题是虽然np.nan is np.nan
returnsTrue
,np.float64(np.nan) is np.float(np.nan)
returnsFalse
。同样,np.float64(np.nan) is np.nan
returns False
.
我猜你的 apply
函数不起作用的原因是你创建的 lambda 函数试图在字典 repl
并没有找到它。即使您的原始数据只包含 np.nan
,似乎 pandas 将其转换为 numpy.float64
类型。
例如
a = pd.DataFrame([[np.nan, 0], [1,1]])
a[0][0], type(a[0][0]), type(np.nan)
>> nan, numpy.float64, float
另一方面,map
将字典作为参数,专门用于处理某些值缺失或等于 np.nan
的情况(参见:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.map.html)
有关在字典中使用 nan
作为键的更多信息,请参阅此问题:NaNs as key in dictionaries