【问题标题】:Insert rows into pandas DataFrame while maintaining column data types在维护列数据类型的同时将行插入 pandas DataFrame
【发布时间】:2018-11-12 00:49:03
【问题描述】:

在保持列数据类型的同时,将新行插入现有 pandas DataFrame 的最佳方法是什么,同时为未指定的列提供用户定义的填充值?这是一个例子:

df = pd.DataFrame({
    'name': ['Bob', 'Sue', 'Tom'],
    'age': [45, 40, 10],
    'weight': [143.2, 130.2, 34.9],
    'has_children': [True, True, False]
})

假设我想添加一条仅通过 nameage 的新记录。为了维护数据类型,我可以从df 复制行,修改值,然后将df 附加到副本中,例如

columns = ('name', 'age')
copy_df = df.loc[0:0, columns].copy()
copy_df.loc[0, columns] = 'Cindy', 42
new_df = copy_df.append(df, sort=False).reset_index(drop=True)

但这会将bool 列转换为对象。

这是一个非常老套的解决方案,感觉不是这样做的“正确方法”:

columns = ('name', 'age')
copy_df = df.loc[0:0].copy()

missing_remap = {
    'int64': 0,
    'float64': 0.0,
    'bool': False,
    'object': ''
}
for c in set(copy_df.columns).difference(columns)):
    copy_df.loc[:, c] = missing_remap[str(copy_df[c].dtype)]

new_df = copy_df.append(df, sort=False).reset_index(drop=True)
new_df.loc[0, columns] = 'Cindy', 42

我知道我一定错过了什么。

【问题讨论】:

    标签: python pandas dataframe append


    【解决方案1】:

    这是因为,NaN 值是浮点数,而 True 和 False 是布尔值。在一列中有混合的 dtypes,因此 Pandas 会自动将其转换为对象。

    另一个例子是,如果你有一列包含所有整数值并附加一个浮点值,那么 pandas 通过将“.0”添加到剩余值来将整个列更改为浮点数。


    编辑

    基于 cmets,另一种将 object 转换为 bool dtype 的 hacky 方法。

    df = pandas.DataFrame({
        'name': ['Bob', 'Sue', 'Tom'],
        'age': [45, 40, 10],
        'weight': [143.2, 130.2, 34.9],
        'has_children': [True, True, False]
    })
    row = {'name': 'Cindy', 'age': 12}
    df = df.append(row, ignore_index=True)
    df['has_children'] = df['has_children'].fillna(False).astype('bool')
    

    现在新的数据框如下所示:

        age has_children    name    weight
     0  45  True             Bob    143.2
     1  40  True             Sue    130.2
     2  10  False            Tom    34.9
     3  12  False            Cindy  NaN
    

    【讨论】:

    • 感谢您的帮助。抱歉,我不是更清楚 - 我确实理解为什么这些列正在更改数据类型,但想要最好的方法来避免这种情况。在进行追加之前似乎需要处理 NaN?
    • 是的,np.nan 需要处理,通常这取决于您正在处理的用例。如果您是数据科学家,那么价值观会对最终结果产生巨大影响。我建议将其保留为对象并维护模式以供以后使用。
    【解决方案2】:

    如您所见,由于NaNfloat,将NaN 添加到系列可能会导致它向上转换为float 或转换为object。您确定这不是一个理想的结果是正确的。

    没有直接的方法。我的建议是将您的输入行数据存储在字典中,并在附加之前将其与默认字典相结合。请注意,这是有效的,因为 pd.DataFrame.append 接受 dict 参数。

    在 Python 3.6 中,您可以使用语法 {**d1, **d2} 组合两个字典,并优先选择第二个。

    default = {'name': '', 'age': 0, 'weight': 0.0, 'has_children': False}
    
    row = {'name': 'Cindy', 'age': 42}
    
    df = df.append({**default, **row}, ignore_index=True)
    
    print(df)
    
       age  has_children   name  weight
    0   45          True    Bob   143.2
    1   40          True    Sue   130.2
    2   10         False    Tom    34.9
    3   42         False  Cindy     0.0
    
    print(df.dtypes)
    
    age               int64
    has_children       bool
    name             object
    weight          float64
    dtype: object
    

    【讨论】:

    • 反对者愿意发表评论吗?如果存在严重缺陷,我非常乐意编辑/更新/澄清。
    • 是的,不知道为什么有人会对此投反对票。你把我的乱七八糟的代码简化为更容易理解的东西......
    • 什么!!!!!!这是这个问题的答案!难怪有人反对这个答案。将列中的缺失值替换为 False,只是为了使其成为布尔类型。如问题本身所述,不是正确的方法!如果我错了,请纠正我。
    • 此外,pandas 本身通过将 np.nan 转换为 True 将对象列转换为布尔值。为什么选择 False 作为默认值?
    • 我最初的问题是如何用 user-defined 值替换 NA 值。关键是用户必须选择对他们的用例有意义的东西。就我而言,False 对我试图填充的列有意义。
    猜你喜欢
    • 1970-01-01
    • 2017-02-16
    • 1970-01-01
    • 2019-02-15
    • 2018-10-06
    • 1970-01-01
    • 2011-11-13
    相关资源
    最近更新 更多