Pandas中pd.Int64Dtype序列转DataFrame后变回浮点型的原因与解决
问题:pd.Int64Dtype的Series合并为DataFrame后自动变为浮点型?
我编写了一段代码,将数据解析为可空整数类型(pd.Int64Dtype())的Series,修改时会将部分值设为pd.NA(和填充的0含义不同),最终将这些Series合并为DataFrame。但单独的Series都是pd.Int64Dtype,合并后的DataFrame却把所有列的类型变回了浮点型。
代码逻辑如下:
sers = [] for item in items: type_name = item.name values = {pd.to_datetime(value.date_string): value.doc_count for value in item.values} series = pd.Series(values, name=type_name, dtype=pd.Int64Dtype()) reindexed_series = series.reindex(date_range, fill_value=0) exclude_inapplicable_days(reindexed_series, type_name) apply_offset(reindexed_series, type_name) sers.append(reindexed_series) df = pd.DataFrame(sers)
可复现代码:
import pandas as pd date_range = pd.date_range(start="2023-01-01", end="2023-01-05") items = [ {"name": "Type1", "values": [{"date_string": "2023-01-01", "doc_count": 1}, {"date_string": "2023-01-02", "doc_count": 2}, {"date_string": "2023-01-03", "doc_count": 3}, {"date_string": "2023-01-04", "doc_count": 4}, {"date_string": "2023-01-05", "doc_count": 5}]}, {"name": "Type2", "values": [{"date_string": "2023-01-01", "doc_count": 6}, {"date_string": "2023-01-02", "doc_count": 7}, {"date_string": "2023-01-03", "doc_count": 8}, {"date_string": "2023-01-04", "doc_count": 9}, {"date_string": "2023-01-05", "doc_count": 10}]} ] def exclude_inapplicable_days(series, type_name): series[series.index[0]] = pd.NA print(f"After exclusion in {type_name}: {series.dtype}") def apply_offset(series, type_name): offset = { "Type1": 2, "Type2": 1 }[type_name] if offset > 0: series.iloc[-offset:] = pd.NA print(f"After offset in {type_name}: {series.dtype}") sers = [] for item in items: type_name = item['name'] values = {pd.to_datetime(val['date_string']): val['doc_count'] for val in item['values']} series = pd.Series(values, name=type_name, dtype=pd.Int64Dtype()) reindexed_series = series.reindex(date_range, fill_value=0) exclude_inapplicable_days(reindexed_series, type_name) apply_offset(reindexed_series, type_name) sers.append(reindexed_series) df = pd.DataFrame(sers) print("DataFrame dtypes:") print(df.dtypes)
原因分析
问题出在pd.DataFrame(sers)的构造逻辑上:
- 你创建的Series是pandas的可空整数类型(
pd.Int64Dtype),它基于ExtensionArray实现,专门用来兼容整数和空值。 - 当用多个这样的Series作为行构造DataFrame时,pandas内部会尝试将这些Series转换为numpy数组。但numpy原生整数数组无法存储
pd.NA(底层对应浮点型的np.nan),因此会自动将类型提升为float64以兼容空值,导致最终列类型全部变为浮点型。 - 另外,
reindex时使用的fill_value=0是Python原生整数,虽然Series表面仍显示pd.Int64Dtype,但后续赋值pd.NA后,ExtensionArray的内部存储混合了整数和空值标记,进一步触发了构造DataFrame时的类型提升。
无需遍历修改类型的解决办法
方法1:使用pd.concat构造并转置
pd.concat对ExtensionArray类型的支持更完善,能保留原Series的pd.Int64Dtype。只需替换构造DataFrame的代码:
# 替换原df = pd.DataFrame(sers) df = pd.concat(sers, axis=1).T
pd.concat(sers, axis=1)将Series按列拼接(列是Type1/Type2,行是日期),.T转置后得到你需要的行是Type1/Type2、列是日期的结构,此时所有列的类型会保留Int64。
方法2:使用from_dict指定orient='index'
通过字典映射Series名称和对应Series,用from_dict构造DataFrame,同样能保留原类型:
# 替换原df = pd.DataFrame(sers) df = pd.DataFrame.from_dict({s.name: s for s in sers}, orient='index')
内容的提问来源于stack exchange,提问作者user26390854
相关产品推荐
相关产品推荐

