【问题标题】:Pandas .loc[] side effect changes bools to floatsPandas .loc[] 副作用将布尔值更改为浮点数
【发布时间】:2018-12-21 22:26:55
【问题描述】:
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 将布尔值更改为浮点数,对此有什么好的解决方法?

【问题讨论】:

  • .loc 没有改变类型;这是您包含np.NaN 的值。 DataFrame 中的列必须都具有相同类型的数据。没有bool 表示NaN,所以pandas 决定由于np.NaNFalse=0True=1 都可以表示为float,因此整个列成为一个浮点列。

标签: python pandas numpy nan


【解决方案1】:

Python 和 NumPy 和 Pandas 中的类型 bool 只能为 True 或 False。它不能是 NaN。因此,当您将 NaN 值引入 bool(或 int)系列时,它会变为 float

另一种方法是使用第二个bool 列来指示NaN 值。另一种是使用 NumPy“掩码数组”。第三种可能是将列类型更改为i1,并使用-1 表示NaN。

【讨论】:

    【解决方案2】:

    如果您将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'
    

    如果您打印类型,那么这表明值确实是floatbool

    print(type(df['b'].iloc[0]))
    print(type(df['b'].iloc[1]))
    <class 'float'>
    <class 'bool'>
    

    正如其他答案中所述,bool 不能代表NaN,只有float dtype 可以,所以pandasSeriesdtype 上转换为最兼容的类型,在这种情况下是float。如果您将dtype 设置为np.object,则这允许异构dtype,因此没有dtype 转换。

    更新

    如 cmets 中所述,使用混合 dtype 将严重影响性能和存储,如果您必须使用混合类型,那么这是唯一可行的方法。否则,您可以有一个额外的列来按照建议标记NaN 的行。

    【讨论】:

    • 您应该注意dtype=object 严重影响大型阵列的性能和内存使用。此解决方案使用 8 倍内存,比存储简单的三值 i1 dtype 慢 8 倍以上。
    • @johnzwink 这是一个很好的观点,我不喜欢混合类型,你会失去性能和矢量化操作。我回来后会更新答案。
    【解决方案3】:

    一开始,列“b”的类型是bool,因为所有条目都是bools。然后您更改了一些条目,因此类型更改为具有所有值的下一行。在这种情况下,这是float,因为boolint(其中bool 继承)都没有NaN 值,但float 有。

    例如,如果您设置df.loc[~df['b'], 'b'] = "False",则必须进一步升级,直到达到object。所有类型都继承自 Python 3 中的object,因此objects 的列可以包含任何对象。

    换句话说,pandas 列中的所有条目都必须属于同一类型。该类型会动态调整为其中所有对象共享的最接近的类型。在你的情况下是float

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-17
      • 2020-03-16
      • 1970-01-01
      • 2021-04-01
      • 2019-03-06
      • 1970-01-01
      • 2016-12-08
      • 2010-12-16
      相关资源
      最近更新 更多