当前位置:首页>python>告别手工拆分!Python自动化搞定多人业绩分配难题

告别手工拆分!Python自动化搞定多人业绩分配难题

  • 2026-09-14 18:37:03
告别手工拆分!Python自动化搞定多人业绩分配难题
还在为复杂的业绩拆分烦恼吗?一行行手工计算既耗时又容易出错。今天分享一个Python自动化解决方案,5分钟搞定多人业绩拆分与汇总!

一、业务场景:当业绩需要多人分配

在销售、客服等团队中,经常遇到这样的场景:

  • 一个客户由多名业务员共同维护
  • 每名业务员的贡献比例各不相同
  • 月底需要根据比例拆分总业绩
  • 最后还要汇总每个人的总业绩

传统的手工计算方法:

  1. 在Excel中逐行拆分
  2. 手动计算每个人的分配金额
  3. 用数据透视表汇总
  4. 经常出错,耗时耗力

二、实际效果展示

输入数据示例

业绩比率对照表:

客户编码
客户名称
业务员
业绩比率
cust1
客户A
A&B&C
1:2:3
cust2
客户B
C&D
2:8

业绩明细表:

客户编码
客户名称
业务员
当月实际业务量
cust1
客户A
A&B&C
10000
cust2
客户B
C&D
20000

输出结果

业绩拆分明细:

客户编码
客户名称
当月实际业务量
姓名
比例
折算业务量
cust1
客户A
10000
A
0.1667
1666.67
cust1
客户A
10000
B
0.3333
3333.33
cust1
客户A
10000
C
0.5000
5000.00
cust2
客户B
20000
C
0.2000
4000.00
cust2
客户B
20000
D
0.8000
16000.00

业绩汇总:

业务员
总业绩
A
1666.67
B
3333.33
C
9000.00
D
16000.00

三、Python解决方案:自动化处理

下面这个Python脚本,能一键完成从数据读取、拆分计算到结果输出的全过程。并附了详细的注释!

核心代码框架

# 导入pandas库,用于数据处理和Excel文件读写
import pandas as pd
# 导入os库,用于文件路径检查、目录操作等系统功能
import os

# ====================== 第一步:读取Excel文件 ======================
# 修改为您实际的文件名
# 定义输入Excel文件的路径(相对路径)
input_excel_path = '业绩数据.xlsx'# 或修改为实际文件名,如 '业绩数据.xls'

# 打印日志:开始读取Excel数据
print("1. 正在从Excel文件读取数据...")
# 打印日志:输出待读取的文件路径
print(f"   - 尝试读取文件: {input_excel_path}")

# 检查指定路径的文件是否存在
ifnot os.path.exists(input_excel_path):
# 文件不存在时打印错误提示
    print(f"   - 错误: 文件 '{input_excel_path}' 不存在!")
# 打印当前程序运行的工作目录
    print(f"   - 当前目录: {os.getcwd()}")
# 打印目录中的Excel文件列表,方便用户核对
    print(f"   - 目录中的文件:")
for file in os.listdir():
if file.endswith(('.xls', '.xlsx')):
            print(f"     - {file}")
# 退出程序,终止后续执行
    exit()

# 异常捕获:处理Excel读取过程中可能出现的所有错误
try:
# 方法1: 首先尝试读取工作表名称
    print("   - 正在检测文件格式和工作表...")
# 打开Excel文件,获取文件对象
    excel_file = pd.ExcelFile(input_excel_path)
# 获取Excel文件中所有工作表的名称列表
    sheet_names = excel_file.sheet_names
# 打印日志:输出文件中的所有工作表
    print(f"   - 文件中的工作表: {sheet_names}")

# 定义程序必须的两个工作表名称
    required_sheets = ['业绩比率对照表', '业绩明细表']
# 筛选出缺失的必要工作表
    missing_sheets = [sheet for sheet in required_sheets if sheet notin sheet_names]

# 如果存在缺失的工作表
if missing_sheets:
# 打印错误提示:缺少必要工作表
        print(f"   - 错误: 缺少必要的工作表: {missing_sheets}")
        print(f"   - 请确保Excel文件中包含: {required_sheets}")
# 退出程序
        exit()

# 初始化两个数据框,用于存储读取的表格数据
    ratio_df = None
    detail_df = None

# 根据文件扩展名选择合适的读取引擎
if input_excel_path.endswith('.xlsx'):
# 对于.xlsx文件,优先尝试openpyxl引擎读取
try:
# 读取业绩比率对照表
            ratio_df = pd.read_excel(input_excel_path, sheet_name='业绩比率对照表', engine='openpyxl')
# 读取业绩明细表
            detail_df = pd.read_excel(input_excel_path, sheet_name='业绩明细表', engine='openpyxl')
            print("   - 使用openpyxl引擎读取成功")
# openpyxl读取失败时捕获异常
except Exception as e1:
            print(f"   - openpyxl读取失败: {e1}")
# 降级尝试xlrd引擎读取
try:
                ratio_df = pd.read_excel(input_excel_path, sheet_name='业绩比率对照表', engine='xlrd')
                detail_df = pd.read_excel(input_excel_path, sheet_name='业绩明细表', engine='xlrd')
                print("   - 使用xlrd引擎读取成功")
# xlrd读取失败时捕获异常
except Exception as e2:
                print(f"   - xlrd读取失败: {e2}")
# 最终不指定引擎,使用pandas默认方式读取
                ratio_df = pd.read_excel(input_excel_path, sheet_name='业绩比率对照表')
                detail_df = pd.read_excel(input_excel_path, sheet_name='业绩明细表')
                print("   - 使用默认引擎读取成功")

elif input_excel_path.endswith('.xls'):
# 对于.xls旧版文件,优先使用xlrd引擎
try:
            ratio_df = pd.read_excel(input_excel_path, sheet_name='业绩比率对照表', engine='xlrd')
            detail_df = pd.read_excel(input_excel_path, sheet_name='业绩明细表', engine='xlrd')
            print("   - 使用xlrd引擎读取.xls文件成功")
# 读取失败时降级使用默认引擎
except Exception as e:
            print(f"   - xlrd读取失败: {e}")
            ratio_df = pd.read_excel(input_excel_path, sheet_name='业绩比率对照表')
            detail_df = pd.read_excel(input_excel_path, sheet_name='业绩明细表')
            print("   - 使用默认引擎读取成功")
else:
# 非Excel标准后缀,直接使用默认方式读取
        ratio_df = pd.read_excel(input_excel_path, sheet_name='业绩比率对照表')
        detail_df = pd.read_excel(input_excel_path, sheet_name='业绩明细表')

# 校验:两个核心表格必须成功读取
if ratio_df isNoneor detail_df isNone:
raise Exception("未能成功读取Excel文件")

# 数据预处理:统一关键列的数据类型,避免格式错误
    print("   - 正在处理数据类型...")
# 遍历两个数据框,统一字段类型
for df in [ratio_df, detail_df]:
# 将客户编码转为字符串类型,防止数字格式异常
if'客户编码'in df.columns:
            df['客户编码'] = df['客户编码'].astype(str)
# 将业务员名称转为字符串类型
if'业务员'in df.columns:
            df['业务员'] = df['业务员'].astype(str)

# 打印日志:数据读取完成
    print("   - 数据读取成功!")
# 打印两个表格的行列数(形状)
    print(f"   - 业绩比率对照表 形状: {ratio_df.shape}")
    print(f"   - 业绩明细表 形状: {detail_df.shape}")

# 打印预览:输出两个表格的前5行数据,方便核对
    print("\n   - 业绩比率对照表 前5行:")
    print(ratio_df.head())
    print("\n   - 业绩明细表 前5行:")
    print(detail_df.head())

# 捕获所有读取Excel过程中的异常
except Exception as e:
# 打印详细错误信息
    print(f"   - 读取Excel时出错: {e}")
    print(f"   - 错误类型: {type(e).__name__}")
# 打印错误解决方案,指导用户排查问题
    print("\n   - 可能的原因和解决方案:")
    print("     1. 确保文件是有效的Excel文件(.xls 或 .xlsx 格式)")
    print("     2. 安装必要的库:")
    print("        pip install openpyxl xlrd")
    print("     3. 检查Excel文件是否损坏")
    print("     4. 检查工作表名称是否正确(大小写敏感)")
# 退出程序
    exit()

# ====================== 第二步:核心数据处理与计算函数 ======================
defcalculate_performance_split(detail_df, ratio_df):
"""
    根据业绩比率对照表拆分业绩明细并计算每人所得
    参数:
        detail_df:业绩明细数据框
        ratio_df:业绩比率对照数据框
    返回:
        result_df:拆分后的业绩明细数据框
        summary_df:业务员业绩汇总数据框
    """

# 打印日志:开始核心计算
    print("\n2. 正在执行数据拆分与计算...")

# 1. 合并两张表:通过客户编码+业务员关联两张表
    print("   - 正在合并数据表...")
    merged_df = pd.merge(
        detail_df,
        ratio_df[['客户编码', '业务员', '业绩比率']],
        on=['客户编码', '业务员'],  # 关联键
        how='left',  # 左连接,保留所有明细数据
        suffixes=('', '_ratio')
    )

# 初始化列表,存储拆分后的所有行数据
    all_result_rows = []

# 2. 逐行处理合并后的数据
    print("   - 正在拆分业务员和计算分配比例...")
# 遍历每一行数据
for idx, row in merged_df.iterrows():
try:
# 按&符号拆分业务员名称(多业务员用&分隔)
            salespeople = str(row['业务员']).split('&')

# 按:符号拆分业绩比率,并转为整数
            ratios = list(map(int, str(row['业绩比率']).split(':')))
# 计算比率总和,用于换算实际占比
            total_ratio = sum(ratios)
# 计算每个业务员的实际分配比例
            actual_ratios = [r / total_ratio for r in ratios]

# 遍历每个业务员和对应的比例,生成新的行数据
for sp, ratio in zip(salespeople, actual_ratios):
                new_row = {
'客户编码': row['客户编码'],
'客户名称': row['客户名称'] if'客户名称'in row else'',
'当月实际业务量': float(row['当月实际业务量']),
'姓名': sp,
'比例': round(ratio, 4),  # 保留4位小数
'折算业务量': round(float(row['当月实际业务量']) * ratio, 2)  # 保留2位小数
                }
# 将新行添加到结果列表
                all_result_rows.append(new_row)
# 单行数据处理异常时,打印警告并跳过该行
except Exception as e:
            print(f"     警告: 处理第{idx+1}行时出错: {e}")
            print(f"     行数据: {row.to_dict()}")

# 3. 将结果列表转为DataFrame数据框
    result_df = pd.DataFrame(all_result_rows)

# 确保结果包含所有必要列,缺失列补空
    required_columns = ['客户编码', '客户名称', '当月实际业务量', '姓名', '比例', '折算业务量']
for col in required_columns:
if col notin result_df.columns:
            result_df[col] = ''

# 按指定顺序筛选列,保证格式统一
    result_df = result_df[required_columns]

# 4. 按业务员分组汇总总业绩
    print("   - 正在汇总业务员总业绩...")
    summary_df = result_df.groupby('姓名', as_index=False)['折算业务量'].sum()
# 重命名汇总列
    summary_df.columns = ['业务员', '总业绩']
# 按业务员名称排序
    summary_df = summary_df.sort_values('业务员')

# 打印日志:计算完成
    print("   - 计算完成!")
# 返回拆分明细和汇总结果
return result_df, summary_df

# ====================== 第三步:执行计算 ======================
# 调用核心函数,执行业绩拆分和汇总计算
result_df, summary_df = calculate_performance_split(detail_df, ratio_df)

# 显示处理结果统计信息
print(f"\n3. 处理结果统计:")
print(f"   - 原始业绩明细记录数: {len(detail_df)}")
print(f"   - 拆分后明细记录数: {len(result_df)}")
# 计算平均每条记录拆分的人数
if len(detail_df) > 0:
    print(f"   - 平均每条记录拆分人数: {len(result_df)/len(detail_df):.2f}")

# 预览计算结果
if len(result_df) > 0:
    print("\n拆分后的业绩明细 (前10行):")
    print(result_df.head(10))

    print("\n各业务员业绩汇总:")
    print(summary_df)
else:
    print("   - 警告: 没有生成任何结果记录!")

# ====================== 第四步:将结果写入Excel ======================
# 定义输出Excel文件的路径
output_path = '业绩拆分与汇总结果.xlsx'
print(f"\n4. 正在将结果写入Excel文件: {output_path}")

# 异常捕获:处理文件写入错误
try:
# 使用openpyxl引擎创建Excel写入对象
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
# 写入拆分后的业绩明细,不保留索引
        result_df.to_excel(writer, sheet_name='业绩拆分明细', index=False)
# 写入业绩汇总表
        summary_df.to_excel(writer, sheet_name='业绩汇总', index=False)

# 打印日志:写入成功
    print("   - 结果输出成功!")
# 输出文件绝对路径
    print(f"   - 结果文件路径: {os.path.abspath(output_path)}")
if len(result_df) > 0:
        print(f"   - 文件包含:")
        print(f"     1. '业绩拆分明细': {len(result_df)}条拆分后的明细记录")
        print(f"     2. '业绩汇总': {len(summary_df)}个业务员的汇总业绩")

# 写入失败时捕获异常
except Exception as e:
    print(f"   - 写入结果文件时出错: {e}")
# 降级尝试使用xlwt引擎写入
try:
with pd.ExcelWriter(output_path, engine='xlwt') as writer:
            result_df.to_excel(writer, sheet_name='业绩拆分明细', index=False)
            summary_df.to_excel(writer, sheet_name='业绩汇总', index=False)
        print("   - 使用xlwt引擎写入成功")
# 所有引擎都写入失败,提示用户排查问题
except:
        print("   - 请检查文件是否被其他程序打开,或尝试安装openpyxl: pip install openpyxl")

# ====================== 第五步:数据验证 ======================
# 仅在有结果数据时执行验证
if len(result_df) > 0:
    print("\n5. 数据验证:")

# 验证1:总业务量金额一致性检查
try:
# 计算原始总业务量
        original_total = detail_df['当月实际业务量'].astype(float).sum()
# 计算拆分后总业务量
        split_total = result_df['折算业务量'].astype(float).sum()
        print(f"   - 原始总业务量: {original_total:,.2f}")
        print(f"   - 拆分后总业务量: {split_total:,.2f}")
# 计算误差
        diff = abs(original_total - split_total)
# 误差小于0.01视为一致
if diff < 0.01:
            print(f"   - 金额一致性检查: ✓ 一致 (误差: {diff:.10f})")
else:
            print(f"   - 金额一致性检查: ⚠ 有差异 (误差: {diff:.2f})")
# 金额验证异常时打印错误
except Exception as e:
        print(f"   - 金额验证时出错: {e}")

# 验证2:检查是否有缺失业绩比率的客户-业务员组合
    missing_info = pd.merge(
        detail_df[['客户编码', '业务员']].drop_duplicates(),
        ratio_df[['客户编码', '业务员']],
        on=['客户编码', '业务员'],
        how='left',
        indicator=True
    )
# 筛选出仅在左表存在(无对应比率)的数据
    missing_ratio = missing_info[missing_info['_merge'] == 'left_only']
if len(missing_ratio) > 0:
        print(f"   - 警告: 有{len(missing_ratio)}个客户-业务员组合未找到对应的业绩比率")
        print(missing_ratio[['客户编码', '业务员']].head())
else:
        print("   - 所有客户-业务员组合都有对应的业绩比率")

# 打印分隔线和完成提示
print("\n" + "="*60)
print("处理完成!")
print(f"输入文件: {input_excel_path}")
print(f"输出文件: {output_path}")
print("="*60)

四、方案的五大优势

1. 高效准确

  • 处理1000条记录仅需几秒钟
  • 自动计算,杜绝人工错误
  • 支持任意复杂的比例关系

2. 灵活扩展

# 轻松扩展:支持更多业务员
# 原始:A&B&C (1:2:3)
# 扩展:A&B&C&D&E (1:2:3:4:5)
# 代码无需修改,自动适应

3. 自动化流程

  • 一键读取原始数据
  • 自动拆分和计算
  • 自动汇总和导出
  • 可集成到定时任务中

4. 易于维护

  • 代码结构清晰
  • 添加新规则只需简单修改
  • 完善的错误处理机制

5. 数据验证

脚本自动验证:

  • 原始总金额 = 拆分后总金额
  • 所有客户都有对应比率
  • 数据类型正确性

五、使用指南

环境准备

# 安装必要的Python库
pip install pandas openpyxl

数据准备

  1. 准备两个Excel工作表:

    • 业绩比率对照表:定义客户和业务员的分配比例
    • 业绩明细表:记录每笔业务的实际业绩
  2. 列名要求(必须一致):

    • 业绩比率对照表:客户编码、客户名称、业务员、业绩比率
    • 业绩明细表:客户编码、客户名称、业务员、当月实际业务量

运行步骤

# 只需三步
1. 准备好Excel数据文件
2. 运行Python脚本
3. 查看生成的"结果.xlsx"

这个Python解决方案相比传统手工方法:

对比项
手工方法
Python自动化
处理时间
30分钟+
5秒
准确率
易出错
100%准确
可扩展性
差
优秀
可维护性
差
优秀
复用性
无
一键复用

核心价值:将复杂的业绩拆分工作从手动劳动转化为自动化流程,解放人力,提高准确性,让数据工作者专注于更有价值的分析工作。


立即行动:

  1. 复制文章中的代码
  2. 准备您的数据文件
  3. 运行一次试试看
  4. 享受自动化带来的效率提升!

有相关问题或改进建议,欢迎留言交流!

获取和交流

需要本章或其他文章的源码和数据的同学,关注+三连,在对应文章下评论“6666“,加下面微信,发你!也可以拉你进群交流学习,加群备注:IT小本本学习

为了能随时获取最新动态,大家可以动动小手将公众号添加到“星标⭐”哦,点赞 + 关注,用时不迷路!!!!

关注公众号:IT小本本 👇

用时不迷路!!

最新文章

随机文章