在保留列数据类型的同时将行插入到pandas DataFrame中

时间:2018-06-01 20:51:37

标签: python pandas dataframe append

在维护列数据类型的同时,将新行插入现有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列转换为对象。

这是一个真正的hacky解决方案,感觉不像是正确的方式"这样做:

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

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

2 个答案:

答案 0 :(得分:0)

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

另一个例子是,如果你有一个包含所有整数值的列并且使用float附加一个值,那么pandas会通过在剩余值中添加“.0”来将整个列更改为float。

修改

基于评论,另一种将对象转换为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

答案 1 :(得分:0)

正如您所发现的那样,由于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