Pandas Crosstab不支持Float64(大写F)数值格式问题
问题:pandas crosstab 兼容 Float64 类型报错
场景复现
处理交易数据时,当revenue字段为**Float64(可空浮点类型)**时,使用pd.crosstab生成带合计的交叉表会抛出TypeError: Float64,而float64类型下代码可正常运行。
可复现代码
import numpy as np import pandas as pd from datetime import datetime num_variables = 100 rng = np.random.default_rng() df = pd.DataFrame({ 'id' : np.random.randint(1,999999999,num_variables), 'date' : [np.random.choice(pd.date_range(datetime(2022,6,1),datetime(2022,12,31))) for i in range(num_variables)], 'gmv' : rng.random(num_variables) * 100, 'revenue' : rng.random(num_variables) * 100}) df = df.astype({'revenue':'Float64'}) # 分组统计 clients = df[['id', 'date','revenue']].groupby(['id', df.date.dt.to_period("M")], dropna=False).aggregate({'revenue': 'sum'}) clients.reset_index(inplace=True) # 执行报错的代码 CrossTab = pd.crosstab(clients['id'], clients['date'], values=clients['revenue'], rownames=None, colnames=None, aggfunc='sum', margins=True, margins_name='All', dropna=False, normalize=False)
核心报错信息
TypeError Traceback (most recent call last) ... --> 292 raise TypeError(dtype) # pragma: no cover TypeError: Float64
原因分析
报错源于pd.crosstab内部会创建临时的__dummy__列,在调用pivot_table计算合计(margins)时,底层类型转换逻辑未兼容pandas的Nullable浮点类型(Float64),导致类型校验失败。
解决方案
方案1:临时转回float64类型
如果数据中无缺失值,或可接受将缺失值转为NaN,可在生成交叉表前将revenue转回原生float64:
# 在生成交叉表前添加类型转换 clients['revenue'] = clients['revenue'].astype('float64') CrossTab = pd.crosstab(clients['id'], clients['date'], values=clients['revenue'], rownames=None, colnames=None, aggfunc='sum', margins=True, margins_name='All', dropna=False, normalize=False)
方案2:自定义聚合函数显式处理Float64
通过自定义aggfunc,强制将结果转为可兼容的类型:
def sum_float64(x): return pd.Series(x).sum(dtype='Float64') CrossTab = pd.crosstab(clients['id'], clients['date'], values=clients['revenue'], rownames=None, colnames=None, aggfunc=sum_float64, margins=True, margins_name='All', dropna=False, normalize=False)
方案3:改用pivot_table替代crosstab
绕过crosstab的临时列逻辑,直接使用pivot_table实现相同需求:
CrossTab = clients.pivot_table( values='revenue', index='id', columns='date', aggfunc='sum', margins=True, margins_name='All', dropna=False ) # 移除索引和列名,和原crosstab输出保持一致 CrossTab.columns.name = None CrossTab.index.name = None
内容的提问来源于stack exchange,提问作者FábioRB
相关产品推荐
相关产品推荐

