Python 在索引和插入行时防止强制数据帧
我正在处理pandas数据帧的各个行,但在索引和插入行时,我遇到了强制问题。Pandas似乎总是想将混合int/float强制为所有float类型,我看不到对这种行为有任何明显的控制 例如,这里是一个简单的数据框,其中Python 在索引和插入行时防止强制数据帧,python,pandas,coercion,Python,Pandas,Coercion,我正在处理pandas数据帧的各个行,但在索引和插入行时,我遇到了强制问题。Pandas似乎总是想将混合int/float强制为所有float类型,我看不到对这种行为有任何明显的控制 例如,这里是一个简单的数据框,其中a为int,b为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 pr
a
为int
,b
为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
这里是插入一行时的强制问题:
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
列保持为整数类型,而不是强制为浮点类型。经过一些挖掘,下面是一些非常糟糕的解决方法。(我们会接受更好的答案。)
一个怪癖是非数字列会停止强制,因此下面是如何将一行索引到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
这两个技巧都不是针对大数据帧优化的,因此我非常希望有更好的答案 问题的根源在于
type(df.loc[0])
# pandas.core.series.Series
并且一个系列只能有一个数据类型,在您的例子中是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}
或
df.append(pd.Series({'a': 5, 'b': 4.4}, dtype=object, name=1))
# a b
# 0 1 2.2
# 1 5 4.4
在第一种情况下,您可以使用。序列选择不会强制为
浮点
,值被放置在对象
容器中。然后正确创建字典,并将基础值存储为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
对于您的语法,这几乎也适用于第二种情况,但这会向上转换到对象
,所以不太好:
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
稍微进行数据操作的另一种方法: 假设您有一个字典(或数据帧)列表
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
并维护列的类型。看
因此,如果您有一个数据帧和一个dict列表,您可以使用
pd.concat([df] + [pd.DataFrame(dct) for dct in lod])
无论何时从数据帧获取数据或将数据附加到数据帧,并且需要保持数据类型不变,都应避免转换为不知道所需数据类型的其他内部结构 当您执行
df.loc[0]
时,它会转换为
选择需要作为帧的行,然后转换为dict
>>> df.loc[[0]].to_dict(orient='records')
[{'a': 1, 'b': 2.2}]
类似地,要添加新行,请使用pandas函数
>>> 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
我发现了,但我无法发现问题是否得到了有效解决。与此同时,我想您可以这样做:
df.loc[[0],df.columns]
Duplicates?&。听起来pd.DataFrame不支持实例化时的类型混合?dtype param仅支持一种类型.read.[type]
支持多种数据类型,但您始终可以强制post appenddf['a']=df.a.aType(mytype)
。。。但它仍然很脏,可能效率不高。.astype()
对于float->integer是危险的;将1.1
更改为1
没有问题,因此在执行此操作之前,您确实需要确保所有值都是“类似整数的”。可能最好使用pd。要使用downcast='integer'
Wow读取第二个代码块三次才能得到它。这是非常微妙的。这比我过去做的好多了。。。循环遍历最终的数据帧,并使用正确的数据类型重新分配值(是的,我所做的是一个可怕的解决方案,它确实无法扩展。)。哦。很高兴使用对象
数据类型帮助了这个好主意!另一种方法是从头创建一个对象数据帧:df=pd.DataFrame({'a':[1],'b':[2.2]},dtype=object)
>>> 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