如何控制Pandas中apply行处理的输出数据类型?
Pandas按行apply控制输出数据类型的解决方案
核心结论
在Pandas 1.5.2版本中,无法直接在apply调用时指定多返回值的输出数据类型,但可以通过调整返回值形式或换用更高效的替代方案,避免繁琐的NaN转None操作,同时精准控制列类型。
为什么会出现类型自动转换?
当使用apply(..., result_type='expand')时,Pandas会将每行的返回值(元组/列表)自动整合成DataFrame,并根据列内元素的共性推断dtype:
- 像
bar函数返回(int, None)时,None会被Pandas转为NaN,而int与NaN共存的列会被强制升级为float64(因为int类型无法存储NaN)。 - 像
foo函数返回(int, None, bool)时,由于各返回值类型差异过大,无法统一为单一dtype,Pandas会分别推断每列的类型(int64、object、bool),因此dummy列能保留object类型存储None。
可行的解决方案
1. 返回指定dtype的Series替代元组
修改函数返回值为带明确类型的Series,让Pandas直接沿用Series的类型定义,避免自动转换:
import pandas as pd def bar(x): # 用字典构造Series,指定每个字段的类型 return pd.Series( {'product': x['a'] * x['b'], 'dummy': None}, dtype={'product': 'int64', 'dummy': 'object'} ) df2 = pd.DataFrame([{'a': 10, 'b': 2}, {'a': 10, 'b': 20}]) # 无需指定result_type='expand',直接赋值即可 df2[['product', 'dummy']] = df2.apply(bar, axis=1)
此时product列保持int64,dummy列保持object且存储None,不会被转为NaN。
2. 用列表推导式替代apply,构造DataFrame时指定dtype
apply按行处理效率较低,改用列表推导式生成结果后,直接构造带指定dtype的DataFrame:
df2 = pd.DataFrame([{'a': 10, 'b': 2}, {'a': 10, 'b': 20}]) # 生成所有行的结果 results = [bar(x) for _, x in df2.iterrows()] # 构造DataFrame时指定列类型,同时保留None result_df = pd.DataFrame(results, columns=['product', 'dummy'], dtype={'product': 'int64', 'dummy': 'object'}) df2[['product', 'dummy']] = result_df
这种方式不仅能精准控制类型,还能提升处理速度(尤其当DataFrame行数较多时)。
3. 事后转换类型并批量替换NaN为None(备选方案)
如果必须使用原函数返回元组的形式,可以在赋值后统一处理类型和NaN:
import numpy as np df2[['product', 'dummy']] = df2.apply(bar, axis=1, result_type='expand') # 转换product为int,dummy为object并替换NaN为None df2['product'] = df2['product'].astype('int64') df2['dummy'] = df2['dummy'].astype('object').replace({pd.NA: None, np.nan: None})
这种方式相对繁琐,但适合快速调整已有代码的场景。
内容的提问来源于stack exchange,提问作者Frank_Coumans
相关产品推荐
相关产品推荐

