pandas季度数据计算同比pct_change(periods=4)报除零错如何解决
问题描述
- 计算目标:基于季度财务数据计算个股营收的同比变化
- 运行异常:执行计算代码时抛出
ZeroDivisionError: float division by zero(浮点数除零)错误 - 初始实现代码:
df_all_revenue['revtq_yoy_chg'] = df_all_revenue.groupby('cusip')['revtq'].pct_change(periods=4)
初始逻辑说明
- 数据框
df_all_revenue存储多只股票的季度财务数据,初始逻辑按股票唯一识别码cusip分组后计算百分比变化 - 设置
periods=4偏移4行,意图对应4个季度的时间间隔,自动匹配上一年同季度数据,计算结果存入新列revtq_yoy_chg - 待确认问题:是否需要将
datadate(数据日期)作为cusip之外的额外分组依据?
附:样例数据结构
{'tic': {0: 'AAPL', 1: 'AAPL', 2: 'AAPL', 3: 'AAPL', 4: 'AAPL'}, 'cusip': {0: '037833100', 1: '037833100', 2: '037833100', 3: '037833100', 4: '037833100'}, 'datadate': {0: datetime.date(1979, 12, 31), 1: datetime.date(1980, 3, 31), 2: datetime.date(1980, 6, 30), 3: datetime.date(1980, 9, 30), 4: datetime.date(1980, 12, 31)}, 'fyearq': {0: 1980.0, 1: 1980.0, 2: 1980.0, 3: 1980.0, 4: 1981.0}, 'fqtr': {0: 1.0, 1: 2.0, 2: 3.0, 3: 4.0, 4: 1.0}, 'fdateq': {0: None, 1: None, 2: None, 3: None, 4: None}, 'pdateq': {0: None, 1: None, 2: None, 3: None, 4: None}, 'revtq': {0: 19.54, 1: 23.55, 2: 32.569, 3: 41.467, 4: 67.621}, 'oiadpq': {0: 5.178, 1: 5.509, 2: 5.488, 3: 7.411, 4: 14.914}, 'niq': {0: 2.647, 1: 2.788, 2: 2.735, 3: 3.528, 4: 7.421}}
问题原因与修正方案
错误根因
- 除零错误直接原因:
pct_change(periods=4)的计算逻辑为(当前值 - 偏移N期值)/偏移N期值,当分组内某条记录对应的4行前revtq值为0时,就会触发除零报错,和是否添加datadate作为分组键无直接关联。 - 固定行偏移的逻辑漏洞:偏移4行无法保证一定匹配到上一年同季度数据,如果单只股票存在季度数据缺失、重复、未按时间排序的情况,直接偏移4行会匹配到错误的基期数据,得到完全失真的同比结果。
- 分组逻辑误区:不需要将
datadate加入分组键。分组的作用是划定计算边界,同比计算仅需在单只股票的时间序列范围内匹配上年同季度数据即可,若将datadate加入分组键,会导致每个分组仅包含单条记录,无法完成跨期变化计算。
修正步骤
- 第一步:预处理数据,保证时序正确性与唯一性
import pandas as pd import numpy as np # 按股票识别码、报告日期升序排序,保证时序顺序正确 df_all_revenue = df_all_revenue.sort_values(by=['cusip', 'datadate']).reset_index(drop=True) # 去重:同一股票同一财季仅保留一条最新记录,避免重复数据干扰偏移逻辑 df_all_revenue = df_all_revenue.drop_duplicates(subset=['cusip', 'fyearq', 'fqtr'], keep='last')
- 第二步:放弃固定行偏移逻辑,通过财年+季度字段显式匹配基期数据,同时规避除零错误
# 构造唯一键用于匹配:当前期唯一键、上年同季度唯一键 df_all_revenue['curr_period_key'] = list(zip(df_all_revenue['cusip'], df_all_revenue['fyearq'], df_all_revenue['fqtr'])) df_all_revenue['last_year_key'] = list(zip(df_all_revenue['cusip'], df_all_revenue['fyearq'] - 1, df_all_revenue['fqtr'])) # 建立当期营收映射字典,匹配上年同季度营收 rev_mapping = dict(zip(df_all_revenue['curr_period_key'], df_all_revenue['revtq'])) df_all_revenue['last_year_revtq'] = df_all_revenue['last_year_key'].map(rev_mapping) # 计算同比:基期值缺失或为0时返回空值,避免除零报错 df_all_revenue['revtq_yoy_chg'] = np.where( (df_all_revenue['last_year_revtq'].isna()) | (df_all_revenue['last_year_revtq'] == 0), np.nan, (df_all_revenue['revtq'] - df_all_revenue['last_year_revtq']) / df_all_revenue['last_year_revtq'] )
内容的提问来源于stack exchange,提问作者Katsu
相关产品推荐
相关产品推荐

