df = pd.DataFrame({'b':[False,True,False,True,False]})
# changes all False values to NaN
df.loc[~df['b'], 'b'] = np.nan
print(df.to_dict())
# {'b': {0: nan, 1: 1.0, 2: nan, 3: 1.0, 4: nan}}
由于loc仅更改了列中的特定值,所以我希望像{'b': {0: nan, 1: True, 2: nan, 3: True, 4: nan}}
这样的事情,并非如此。为什么.loc将布尔值更改为浮点数,对此有什么好的解决方法?
答案 0 :(得分:4)
Python,NumPy和Pandas中的类型bool
只能为True或False。不能是NaN。因此,当您将NaN值引入bool
(或int
)系列时,它会变成float
。
一种选择是使用第二个bool
列来表示NaN值。另一个是使用NumPy“蒙版数组”。第三种可能是将列类型更改为i1
并使用-1
表示NaN。
答案 1 :(得分:4)
如果将dtype
更改为np.object
,以使其支持混合dtypes
并显式测试False
,则此方法有效:
In[200]:
df = pd.DataFrame({'b':[False,True,False,True,False]})
df['b'] = df['b'].astype(np.object)
# changes all False values to NaN
df.loc[df['b']==False, 'b'] = np.nan
df
Out[200]:
b
0 NaN
1 True
2 NaN
3 True
4 NaN
如果您尝试做df.loc[~df['b'],'b']=np.nan
,则会引发错误:
KeyError: '[-1 -2 -1 -2 -1] not in index'
如果您打印类型,则表明值实际上是float
和bool
:
print(type(df['b'].iloc[0]))
print(type(df['b'].iloc[1]))
<class 'float'>
<class 'bool'>
如其他答案所述,bool
不能代表NaN
,只有float
dtype可以,所以pandas
正在上转换{{ 1}}到最兼容的类型,在这种情况下为dtype
。如果将Series
设置为float
,则这将允许异构dtype
,因此不会进行np.object
转换。
更新
如注释中所述,使用混合dtype将严重影响性能和存储,如果您必须具有混合类型,则这是唯一可行的方法。否则,您可能会有另外一列,只是按照建议将dtype
的行标记出来。
答案 2 :(得分:3)
在开始时,列“ b”的类型为bool
,因为所有条目均为bool
。然后,您更改了一些条目,因此类型更改为具有所有值的下一行。在这种情况下,这是float
,因为bool
和int
(bool
继承的)都没有NaN值,而float
却没有NaN值。>
例如,如果您设置了df.loc[~df['b'], 'b'] = "False"
,则必须进一步升级,直到达到object
。所有类型都继承自Python 3中的object
,因此objects
的列可以包含任何对象。
换句话说,pandas列中的所有条目都必须是同一类型。该类型将动态调整为与其中所有对象共享的最接近的类型。在您的情况下为float
。