在索引和插入行时防止强制熊猫数据帧


16

我正在处理熊猫数据帧的各个行,但在索引和插入行时遇到了强制问题。熊猫似乎总是想将int / float混合类型强制转换为全浮点类型,我看不出对此行为有任何明显的控制。

例如,这是一个带有aas intbas 的简单数据框float

import pandas as pd
pd.__version__  # '0.25.2'

df = pd.DataFrame({'a': [1], 'b': [2.2]})
print(df)
#    a    b
# 0  1  2.2
print(df.dtypes)
# a      int64
# b    float64
# dtype: object

在索引一行时,这是一个强制问题:

print(df.loc[0])
# a    1.0
# b    2.2
# Name: 0, dtype: float64
print(dict(df.loc[0]))
# {'a': 1.0, 'b': 2.2}

这是插入一行时的强制问题:

df.loc[1] = {'a': 5, 'b': 4.4}
print(df)
#      a    b
# 0  1.0  2.2
# 1  5.0  4.4
print(df.dtypes)
# a    float64
# b    float64
# dtype: object

在这两种情况下,我都希望该a列保留为整数类型,而不是被强制转换为浮点类型。


我找到,但是找不到有效解决此问题的方法。同时,我想您可以做到:df.loc[[0], df.columns]
Dani Mesejo


听起来pd.DataFrame不支持实例化类型混合? pandas.pydata.org/pandas-docs/stable/reference/api/…dtype 参数仅支持一种类型。 .read_[type]虽然支持多种dtypes
Quentin

Answers:


4

经过一番挖掘后,这里有一些非常丑陋的解决方法。(一个更好的答案将被接受。)

此处发现的一个怪癖是非数字列会停止强制转换,因此这是如何将一行索引到dict

dict(df.assign(_='').loc[0].drop('_', axis=0))
# {'a': 1, 'b': 2.2}

插入一行可以通过创建一行新的数据框来完成:

df = df.append(pd.DataFrame({'a': 5, 'b': 4.4}, index=[1]))
print(df)
#    a    b
# 0  1  2.2
# 1  5  4.4

这两个技巧都没有针对大型数据帧进行优化,因此,我将不胜感激!


您总是可以强迫添加附加内容df['a'] = df.a.astype(mytype)……尽管它仍然很脏,并且可能效率不高。
昆汀,

.astype()对于float-> integer是危险的;更改1.1为没问题1,因此您确实需要在执行操作之前确保所有值都是“整数型”的。可能最好pd.to_numericdowncast='integer'
ALollz '19

2

问题的根源在于

  1. 熊猫数据框的索引返回熊猫系列

我们可以看到:

type(df.loc[0])
# pandas.core.series.Series

在您的情况下,一系列只能具有一个dtype,即int64或float64。

我有两种解决方法:

print(df.loc[[0]])
# this will return a dataframe instead of series
# so the result will be
#    a    b
# 0  1  2.2

# but the dictionary is hard to read
print(dict(df.loc[[0]]))
# {'a': 0    1
# Name: a, dtype: int64, 'b': 0    2.2
# Name: b, dtype: float64}

要么

print(df.astype(object).loc[0])
# this will change the type of value to object first and then print
# so the result will be
# a      1
# b    2.2
# Name: 0, dtype: object

print(dict(df.astype(object).loc[0]))
# in this way the dictionary is as expected
# {'a': 1, 'b': 2.2}
  1. 将字典追加到数据框时,它将首先将字典转换为Series,然后追加。(因此,同样的问题再次发生)

https://github.com/pandas-dev/pandas/blob/master/pandas/core/frame.py#L6973

if isinstance(other, dict):
    other = Series(other)

因此,您的解决方案实际上是一个可靠的解决方案,否则我们可以:

df.append(pd.Series({'a': 5, 'b': 4.4}, dtype=object, name=1))
#    a    b
# 0  1  2.2
# 1  5  4.4

使用object数据类型的好主意!另一个是从一开始就创建对象DataFrame:df = pd.DataFrame({'a': [1], 'b': [2.2]}, dtype=object)
Mike T

2

每当您从数据框获取数据或将数据追加到数据框并需要保持数据类型相同时,请避免转换为其他内部结构,这些内部结构不了解所需的数据类型。

完成后,df.loc[0]它会转换为pd.Series

>>> type(df.loc[0])
<class 'pandas.core.series.Series'>

而现在,Series将只有一个dtype。因此强迫intfloat

而是将结构保留为pd.DataFrame

>>> type(df.loc[[0]])
<class 'pandas.core.frame.DataFrame'>

选择所需的行作为框架,然后转换为 dict

>>> df.loc[[0]].to_dict(orient='records')
[{'a': 1, 'b': 2.2}]

同样,要添加新行,请使用pandas pd.DataFrame.append函数,

>>> df = df.append([{'a': 5, 'b': 4.4}]) # NOTE: To append as a row, use []
   a    b
0  1  2.2
0  5  4.4

以上不会引起类型转换,

>>> df.dtypes
a      int64
b    float64
dtype: object

哇,必须读第二遍代码块三遍才能得到它。那是非常微妙的。这比我过去做的要好得多...遍历最终数据框,然后使用正确的数据类型重新分配值(是的,我做的是一个可怕的解决方案,实际上无法扩展)。
VanBantam,

1
哦。很高兴它helped😊@VanBantam
Vishnudev

1

稍作数据处理的另一种方法:

假设您有一个字典列表(或数据框)

lod=[{'a': [1], 'b': [2.2]}, {'a': [5], 'b': [4.4]}]

每个字典代表一行(请注意第二个字典中的列表)。然后,您可以通过以下方式轻松创建数据框:

pd.concat([pd.DataFrame(dct) for dct in lod])
   a    b
0  1  2.2
0  5  4.4

然后您维护列的类型。见concat

因此,如果您有一个数据框和一列字典,则可以使用

pd.concat([df] + [pd.DataFrame(dct) for dct in lod])

0

在第一种情况下,您可以使用空的整数数据类型。系列选择不强制,float并且值放置在object容器中。然后正确创建字典,并将基础值存储为np.int64

df = pd.DataFrame({'a': [1], 'b': [2.2]})
df['a'] = df['a'].astype('Int64')

d = dict(df.loc[0])
#{'a': 1, 'b': 2.2}

type(d['a'])
#numpy.int64

使用您的语法,这几乎也适用于第二种情况,但是这种转换对object,因此效果不佳:

df.loc[1] = {'a': 5, 'b': 4.4}
#   a    b
#0  1  2.2
#1  5  4.4

df.dtypes
#a     object
#b    float64
#dtype: object

但是,我们可以对在末尾添加行(带有RangeIndex)的语法进行一些小的更改,现在可以正确处理类型了。

df = pd.DataFrame({'a': [1], 'b': [2.2]})
df['a'] = df['a'].astype('Int64')

df.loc[df.shape[0], :] = [5, 4.4]
#   a    b
#0  1  2.2
#1  5  4.4

df.dtypes
#a      Int64
#b    float64
#dtype: object
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.