python报错求解:ZeroDivisionError: float division by zero

问题遇到的现象和发生背景

是定义方程里面一个循环语句中对各个股票赋予权重的环节

img


代码运行到weights = num * [1. /num]的时候就会报错(如下图),但是把循环语句从方程定义中剥离出来一步步算的时候num = momentum_portfolio.shape[1]这一代码print出来是一个int。

img

img

问题相关代码,请勿粘贴截图
def momentum_and_contrarian(all_stock, start_date, end_date, window,observation):  #window=形成期,observation=观测期
    """
    :param all_stock: 所有股票的数据集
    :param start_date: 起始日期(包含排名期)
    :param end_date: 结束日期
    :param window: 排名期的月份数,默认为3周
    :return: 返回动量策略和反转策略的收益率和资金曲线
    """
    # 取出指数数据作为交易天数的参考标准, 此处为指数数据文件的本地路径,请自行修改
    index_data = pd.read_csv('C:\\Users\\SHIMAN\\Desktop\\沪深300英文\\沪深300英文1.csv',encoding='gbk', parse_dates=True, index_col='Date')
    index_data.sort_index(inplace=True)
    index_data = index_data[start_date:end_date]
    # 转换成周度数据
    by_week = index_data[['Closing Price (CNY)']].resample('W').last()
    by_week.reset_index(inplace=True)

    momentum_portfolio_all = pd.DataFrame()
    contrarian_portfolio_all = pd.DataFrame()

    for i in range(window, len(by_week) - observation):
        start_week = by_week['Date'].iloc[i - window]  # 排名期第一个月
        end_week = by_week['Date'].iloc[i]  # 排名期最后一个月

        # 取出在排名期内的数据
        stock_temp = all_stock[(all_stock['Date'] > start_week) & (all_stock['Date'] <= end_week)]

        # 将指数在这段时间的数据取出作为交易日天数的标准
        index_temp = index_data[start_week:end_week]
    
        # 统计每只股票在排名期的交易日天数
        trading_days = stock_temp['Symbol'].value_counts()
        # 剔除在排名期内累计停牌超过(1*周数)天的股票,即如果排名期为3周,就剔除累计停牌超过3天的股票
        keep_list = trading_days[trading_days >= (len(index_temp) - 1 * window)].index
        stock_temp = stock_temp[stock_temp['Symbol'].isin(keep_list)]
        stock_temp['% Chg']=pd.to_numeric(stock_temp['% Chg'], downcast='float',errors='coerce')
            
        # 计算每只股票在排名期的累计收益率
        grouped = stock_temp.groupby('Symbol')['% Chg'].agg([('return', lambda x: (x + 100).prod() - 1)])

        # 将累计收益率排序
        grouped.sort_values(by='return', inplace=True)
        # 取排序后前5%的股票构造反转策略的组合,后5%的股票构造动量策略的组合
        num = floor(len(grouped) * 0.05)
        momentum_Symbol_list = grouped.index[-num:]  # 动量组合的股票代码列表
        contrarian_Symbol_list = grouped.index[0:num]  # 反转组合的股票代码列表

        # ============================动量组合============================
        # 取出动量组合内股票当月的数据
        momentum = all_stock.loc[(all_stock['Symbol'].isin(momentum_Symbol_list)) &
                                (all_stock['Date'] > end_week) & (all_stock['Date'] <= by_week['Date'].iloc[i + observation])]

        # 剔除动量组合里在当月第一个交易日涨停的股票
        temp = momentum.groupby('Symbol')['limit_up'].first()
        hold_list = temp[temp == 0].index
        momentum = momentum[momentum['Symbol'].isin(hold_list)].reset_index(drop=True)
        # 动量组合
        momentum_portfolio = momentum.pivot('Date', 'Symbol', '% Chg').fillna(0)

        # 计算动量组合的收益率
        num = momentum_portfolio.shape[1]
        weights = num * [1. /num]
        weights = [float(x) for x in weights]
        momentum_portfolio=momentum_portfolio.astype(float)
        momentum_portfolio['pf_rtn'] = np.dot(np.array(momentum_portfolio), np.array(weights))
        momentum_portfolio.reset_index(inplace=True)
        
        # 将每个月的动量组合收益数据合并
        momentum_portfolio_all = momentum_portfolio_all.append(momentum_portfolio[['Date', 'pf_rtn']],
                                                       ignore_index=True)
        # 计算动量策略的资金曲线
        momentum_portfolio_all['capital'] = ((100 + momentum_portfolio_all['pf_rtn'])/100).cumprod()

        # ============================反转组合=============================
        # 取出反转组合内股票当月的数据
        contrarian = all_stock.loc[(all_stock['Symbol'].isin(contrarian_Symbol_list)) &
                                  (all_stock['Date'] > end_week) & (all_stock['Date'] <= by_week['Date'].iloc[i + observation])]
    
        # 剔除反转组合里在当月第一个交易日涨停的股票
        temp = contrarian.groupby('Symbol')['limit_up'].first()
        hold_list = temp[temp == 0].index
        contrarian = contrarian[contrarian['Symbol'].isin(hold_list)].reset_index(drop=True)
        # 反转组合
        contrarian_portfolio = contrarian.pivot('Date', 'Symbol', '% Chg').fillna(0)

        # 计算反转组合的收益率
        num = contrarian_portfolio.shape[1]
        weights = num * [1. / num]
        weights = [float(x) for x in weights]
        contrarian_portfolio=contrarian_portfolio.astype(float)
        contrarian_portfolio['pf_rtn'] = np.dot(np.array(contrarian_portfolio), np.array(weights))
        contrarian_portfolio.reset_index(inplace=True)
    
        # 将每个月的反转组合收益合并
        contrarian_portfolio_all = contrarian_portfolio_all.append(contrarian_portfolio[['Date', 'pf_rtn']],
                                                                       ignore_index=True)
        # 计算反转策略的资金曲线
        contrarian_portfolio_all['capital'] = ((100 + contrarian_portfolio_all['pf_rtn'])/100).cumprod()

    return momentum_portfolio_all, contrarian_portfolio_all

m, c = momentum_and_contrarian(all_stock, '2019-01-01', '2021-12-31', window=3, observation=1)

运行结果及报错内容

img

我的解答思路和尝试过的方法
我想要达到的结果

成功为个股赋值

建议先对数据框进行处理,用dropna()滤除缺失数据,保证num在循环中不出现零值。
如果先不处理的话,用上述数据框直接遍历计算的话,应用if条件判断过滤,但是这样会出现空列表,可能会对后续的计算有影响。

for num in [3,5,8,0,1,2]:
    weights = num * [1. / num] if num!=0 else num*[0]
    print(weights)

我发现从循环语句里面print出来的num如下图

img


想问一下该怎么解决

ZeroDivisionError: float division by zero这个错误表示
除数num的值为0了
除数是不能为0啊
对num判断下,为0时让weights 赋值为空列表即可

if num!=0:
    weights = num * [1. / num] 
else:
    weights = []

如有帮助,请点击我的回答下方的【采纳该答案】按钮帮忙采纳下,谢谢!

img