You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)的构造逻辑上:

  1. 你创建的Series是pandas的可空整数类型(pd.Int64Dtype),它基于ExtensionArray实现,专门用来兼容整数和空值。
  2. 当用多个这样的Series作为行构造DataFrame时,pandas内部会尝试将这些Series转换为numpy数组。但numpy原生整数数组无法存储pd.NA(底层对应浮点型的np.nan),因此会自动将类型提升为float64以兼容空值,导致最终列类型全部变为浮点型。
  3. 另外,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 01:42:06