Python中列表内正负值占比计算及Excel写入异常问题
首先,我们来逐个解决你遇到的两个核心问题:计算逻辑错误导致的TypeError,以及Excel写入时仅保存单个值的问题。
一、修复正负占比的计算逻辑
你最初的代码报错,是因为zip(ticker_list)的用法完全偏离了需求——它会把每个交易子列表当成独立元素迭代,导致你在判断y>=0时,把时间字符串、标的名称这些非数值型元素和0比较,自然抛出类型错误。
我们需要先按标的(比如US500)分组,再针对每个组的最后一列(盈亏数值)计算正负占比,这里提供两种可行方案:
方案1:基于列表的手动分组计算
如果坚持用列表处理,可以先构建字典按标的分组存储盈亏数据,再遍历字典计算占比:
ticker_list = [['2020.06.25 11:20:12', 'US500', 'sell', 1.0, 3047.3, '2020.06.25 11:21:32', 3051.4, 0.0, -3.89], ['2020.06.25 11:20:59', 'US500', 'sell', 1.0, 3049.8, '2020.06.25 11:21:33', 3051.6, 0.0, -1.71], ['2020.06.25 11:23:49', 'US500', 'sell', 1.0, 3051.6, '2020.06.25 11:25:32', 3049.7, 0.0, 1.8]] # 按标的分组存储盈亏数据 ticker_profits = {} for trade in ticker_list: ticker = trade[1] profit = trade[-1] if ticker not in ticker_profits: ticker_profits[ticker] = [] ticker_profits[ticker].append(profit) # 计算每个标的的正负占比 ticker_ratios = {} for ticker, profits in ticker_profits.items(): total_trades = len(profits) positive_count = len([p for p in profits if p > 0]) negative_count = total_trades - positive_count positive_ratio = (positive_count / total_trades) * 100 negative_ratio = (negative_count / total_trades) * 100 ticker_ratios[ticker] = f"{positive_ratio:.1f}% positive, {negative_ratio:.1f}% negative" # 打印结果示例 for ticker, ratio in ticker_ratios.items(): print(f"{ticker}: {ratio}")
运行后会输出:US500: 33.3% positive, 66.7% negative,完全符合你的需求格式。
方案2:用Pandas直接分组(更简洁,推荐)
既然你的数据本来就来自DataFrame,完全没必要转成列表处理,Pandas的分组功能可以一步到位:
import pandas as pd # 把列表转回DataFrame,自定义列名方便识别 df = pd.DataFrame(ticker_list, columns=['开仓时间', '标的', '方向', '手数', '开仓价', '平仓时间', '平仓价', '手续费', '盈亏']) # 按标的分组,计算盈亏的正负占比 result_df = df.groupby('标的')['盈亏'].agg( positive_ratio=lambda x: (x > 0).mean() * 100, negative_ratio=lambda x: (x < 0).mean() * 100 ).round(1) # 转换成你需要的字符串格式 result_df['ratio_str'] = result_df.apply(lambda row: f"{row['positive_ratio']}% positive, {row['negative_ratio']}% negative", axis=1) print(result_df['ratio_str'])
这种方法代码更简洁,也避免了手动处理分组的繁琐,后续写入Excel也能直接用Pandas的to_excel方法,一步完成。
二、修复Excel写入的问题
你之前的代码只保存单个值,是因为每次循环都在同一个起始行(第3行,索引从0开始对应第4行)写入,而且write_column会把单个数值重复填充,覆盖了之前的内容。正确的做法是按行逐个写入每个标的的结果,或者先整理好所有结果再一次性写入。
这里以xlwt为例(如果用openpyxl,逻辑完全一致):
import xlwt # 用上文计算好的ticker_ratios字典 # 创建工作簿和工作表 workbook = xlwt.Workbook() worksheet = workbook.add_sheet('Profit Ratios') # 写入表头 worksheet.write(0, 0, '标的') worksheet.write(0, 1, '盈亏占比') # 从第1行开始写入数据(索引从0开始) current_row = 1 for ticker, ratio_str in ticker_ratios.items(): worksheet.write(current_row, 0, ticker) worksheet.write(current_row, 1, ratio_str) current_row += 1 # 写完一行后,行号加1,避免覆盖 # 保存文件 workbook.save('profit_ratios.xls')
这样每个标的的结果会依次写入不同的行,不会被覆盖。另外你之前的代码里重复写了两次worksheet.write_column(3,1,pos),而且neg变量也未使用,这些细节也需要修正。
内容的提问来源于stack exchange,提问作者Steven

