一、需求背景
为加强贷款营销的过程管控,监测客户授信过程中各阶段的效能与转化,定位痛点堵点问题,切实促进业务增长与提升客户体验度,特制订《各支行贷款上报审批情况统计表》。
二、通报表样
三、通报说明
四、字段解释
需要作以下说明:
(1)最后一次发起贷前调查时间:存在信贷审批部门退件后,当客户经理修改授信条件时,该客户授信自动返回贷前调查节点的情形;不包括【用信阶段退回贷前调查】,否则会造成【通过时间】较大的误差;
(2)支行行长提交时间:不但作为计算【提交用时】的终止时点,而且将授信流程区域明确划分为两块,分别为基层支行与审批部门;在往期的测试中,发现【通过时间】过长的部分原因是授信流程在支行行长处滞留;
(3)退回客户经理/支行行长最后一次提交时间:该字段中“退回”特指信贷审批部门退回,但在返回的数据中出现了调查B角或支行行长退回的记录,后续会作数据清洗;由于退回有退件和补件之分,故真正最后一次提交时间是两者的最大值;
(4)数据截止时间:由【数据查询时间】调整过来,已确定为上周日的23时59分59秒,主要作为【支行行长提交时间】与【最后一次信贷管理部审批退回时间】的筛选上限,避免以上两种时点与数据查询时点相近,造成审批中、补资料的授信积留。
五、解决策略
一共做了两个不同版本的通报。
第一种,全线追溯。 以【最后一次发起贷前调查时间】在上周一至上周日的全量授信记录为基数,标记这些记录的流转状态,并计算它们的流转用时;
第二种,独立测算。 以【已录入】、【已提交】、【审批中】、【补资料】、【已拒绝】和【已通过】作为独立项,分别计量发生时点在上周一至上周日的时间区间内的监控指标。
前者的优点是, 满足各节点间的勾稽关系,即:已录入≥已提交;已提交≥审批中+补资料+已通过+已拒绝(贷款笔数为“=”,贷款金额为“≥”);
后者的优点是, 更加真实地反映各支行贷款营销的进展,利于过程的精准管控。因为,只有极少数支行可能在以上六大环节中同时没有数据,这就要核查原因了。
六、实现步骤
本项目采用了半开发的模式。首先, 由Python自动生成六大环节的数据明细;其次, 通报表格中汇总统计、条件格式及链接图片均由Excel自动生成;再次, 由Python根据需要通报的名次自动生成内容说明;最后, 手工粘贴到微信中,并发布。
七、代码实现
第一部分, 单独写了FlowMonitor.py第三方库,包括了数据清洗、计算耗时、筛选明细、上载数据及保存文件等。
#!/usr/bin/env python
# coding: utf-8
# # 1 导入第三方库
# In[1]:
# 数据读写与处理
import pandas as pd
import numpy as np
import xlwings as xw
# 操作系统专用库
import os
# 日期时间专用库
from chinese_calendar import is_workday
from datetime import datetime,date,timedelta
from dateutil.parser import parse
# 不显示执行警告
import warnings
warnings.filterwarnings('ignore')
# # 2 定义处理函数
# In[2]:
# 计算两个日期时间之间的时长(剔除法定节假日,按小时为单位)
def interval(begin,finish):
try:
# 创建数值副本
t = begin
# 时长初始值为0
consume = 0
# 判断循环执行的条件
while t <= finish:
# 判断是否为工作日
if is_workday(pd.to_datetime(t)):
# 取当天24时与最后一天的最小值
temp = min(np.datetime64(str(t)[:11] + '23:59:59'),finish)
# 计算时长,精确至秒
result = (temp - t).astype('timedelta64[s]')
# 转换为小时并累加
consume += round(eval(str(result).split(' ')[0])/3600,6)
# 调整起始值,为次日的零时
t = np.datetime64(str(t + np.timedelta64(1,'D'))[:11] + '00:00:00')
# 判断消耗时长是否等于0,若是返回起止时点的时长
if consume == 0:
consume = round(eval(str((finish - begin).astype('timedelta64[s]')).split(' ')[0])/3600,6)
# 返回过程消耗的总时长
return consume
except:
return None
# # 3 自动解决方案
# In[3]:
# 清洗原始数据、计算阶段时长、写入通报数据
def solution(original_date,start,end,original_data):
# 3.1 数据预先处理
# 部分字段转换为日期时间型
for col in original_data.columns:
if '时间' in col:
original_data[col] = pd.to_datetime(original_data[col])
# 4.1 筛选有效进件
# 筛选字段【最后一次发起贷前调查时间】,删除控制记录,筛选字段【录入金额】,剔除空值或≤10000元的记录
valid_data = original_data[~original_data['最后一次发起贷前调查时间'].isnull()].query('录入金额 >= 10000')
## 4.2 剔除撤销非空
# 删除字段【撤销时间】非空的记录
valid_data_drop = valid_data[valid_data['撤销时间'].isnull()]
# 删除字段【支行行长提交时间】为空,但字段【信贷管理部审批退回时间】、【通过时间】、【拒绝时间】至少一个非空的记录
ls = valid_data_drop[(valid_data_drop['支行行长提交时间'].isnull()) & ((~valid_data_drop['信贷管理部审批退回时间'].isnull()) | (~valid_data_drop['通过时间'].isnull()) | (~valid_data_drop['拒绝时间'].isnull()))].index
valid_data_drop.drop(index=ls,inplace=True)
## 4.3 调三字段逻辑
### 4.3.1 增减相关字段
# 新建字段【退回基层支行提交时间】(为字段【退回客户经理提交时间】、【退回支行行长提交时间】中的最大值)
for i in valid_data_drop.index:
submit_staff = valid_data_drop.loc[i,'退回客户经理提交时间']
submit_leader = valid_data_drop.loc[i,'退回支行行长提交时间']
if submit_staff == np.nan and submit_leader == np.nan:
continue
elif submit_staff == np.nan:
valid_data_drop.loc[i,'退回基层支行提交时间'] = submit_leader
elif submit_leader == np.nan:
valid_data_drop.loc[i,'退回基层支行提交时间'] = submit_staff
else:
valid_data_drop.loc[i,'退回基层支行提交时间'] = max(submit_staff,submit_leader)
# 删除字段【退回客户经理提交时间】、【退回支行行长提交时间】、【撤销时间】、【当前流程节点】、【客户经理提交时间】
valid_data_drop.drop(columns=['退回客户经理提交时间','退回支行行长提交时间','撤销时间','当前流程节点','客户经理提交时间'],inplace=True)
### 4.3.2 调整相关逻辑
# 字段【信贷管理部审批退回时间】为空,则字段【退回基层支行提交时间】必须为空
valid_data_drop.loc[valid_data_drop['信贷管理部审批退回时间'].isnull(),'退回基层支行提交时间'] = np.nan
# 字段【信贷管理部审批退回时间】非空,则【退回基层支行提交时间】应大于【信贷管理部审批退回时间】,否则字段【退回基层支行提交时间】必须为空
condition = (~valid_data_drop['信贷管理部审批退回时间'].isnull())&(valid_data_drop['信贷管理部审批退回时间']>=valid_data_drop['退回基层支行提交时间'])
valid_data_drop.loc[condition,'退回基层支行提交时间'] = np.nan
## 4.4 填充查询时间
# 调整字段【数据截止时间】:设定为上周末的23时59分59秒;
valid_data_drop['数据截止时间'] = datetime(parse(end).year,parse(end).month,parse(end).day,23,59,59)
## 4.5 新增是否审批
# 新增字段【是否审批中】:若字段【支行行长提交时间】非空,且字段【信贷管理部审批退回时间】、【通过时间】、【拒绝时间】均为空(仅字段【信贷管理部审批退回时间】、【退回基层支行提交时间】非空,字段【通过时间】、【拒绝时间】均为空),则字段【是否审批中】填“Y”,其余均置空
condition1 = (~valid_data_drop['支行行长提交时间'].isnull()) & ((valid_data_drop['信贷管理部审批退回时间'].isnull()) & (valid_data_drop['通过时间'].isnull()) & (valid_data_drop['拒绝时间'].isnull()))
condition2 = (~valid_data_drop['支行行长提交时间'].isnull()) & ((~valid_data_drop['信贷管理部审批退回时间'].isnull()) & (~valid_data_drop['退回基层支行提交时间'].isnull()) & (valid_data_drop['通过时间'].isnull()) & (valid_data_drop['拒绝时间'].isnull()))
valid_data_drop.loc[(condition1 | condition2),'是否审批中'] = 'Y'
## 4.6 非重复性校验
valid_data_drop[valid_data_drop.duplicated(subset=['客户名称','客户经理名称','机构名称'])]
## 4.7 字段重新排序
# 按模板中字段顺序排序
valid_data_drop = valid_data_drop[['客户名称','最后一次发起贷前调查时间','录入金额','支行行长提交时间','信贷管理部审批退回时间','退回基层支行提交时间','通过时间','通过金额','拒绝时间','是否审批中','数据截止时间','客户经理名称','机构名称']]
# valid_data_drop.to_excel('C:/ZeroAuto/报表自动化/各支行贷款上报审批情况统计表/测试.xlsx',index=False)
# 5 计算节点耗时
## 5.1 计算提交用时
# 遍历已处理数据的索引
for i in valid_data_drop.index:
# 分别获取起止时点
t0 = valid_data_drop.loc[i,'最后一次发起贷前调查时间']
tn = valid_data_drop.loc[i,'支行行长提交时间']
# 计算起止时点的时长
try:
valid_data_drop.loc[i,'提交用时'] = interval(np.datetime64(t0),np.datetime64(tn))
except:
pass
## 5.2 计算审批用时
# 遍历已处理数据的索引
for i in valid_data_drop.index:
# 分别获取起止时点
t0 = valid_data_drop.loc[i,'支行行长提交时间']
tn = valid_data_drop.loc[i,'数据截止时间']
# 获取字段【是否审批中】的值
flag = valid_data_drop.loc[i,'是否审批中']
# 获取字段【信贷管理部审批退回时间】、【退回基层支行提交时间】的值
department_flag = valid_data_drop.loc[i,'信贷管理部审批退回时间']
branch_flag = valid_data_drop.loc[i,'退回基层支行提交时间']
# 计算起止时点的时长
if flag == 'Y':
if str(branch_flag) == 'NaT':
valid_data_drop.loc[i,'审批用时'] = interval(np.datetime64(t0),np.datetime64(tn))
else:
valid_data_drop.loc[i,'审批用时'] = interval(np.datetime64(t0),np.datetime64(department_flag)) + interval(np.datetime64(branch_flag),np.datetime64(tn))
## 5.3 计算补充用时
# 遍历已处理数据的索引
for i in valid_data_drop.index:
# 分别获取起止时点
t0 = valid_data_drop.loc[i,'信贷管理部审批退回时间']
tn = valid_data_drop.loc[i,'数据截止时间']
# 获取字段【退回基层支行提交时间】的值
flag = valid_data_drop.loc[i,'退回基层支行提交时间']
# 计算起止时点的时长
if str(t0) != 'NaT' and str(flag) == 'NaT':
valid_data_drop.loc[i,'补充用时'] = interval(np.datetime64(t0),np.datetime64(tn))
## 5.4 计算通过用时
# 遍历已处理数据的索引
for i in valid_data_drop.index:
# 分别获取起止时点
t0 = valid_data_drop.loc[i,'支行行长提交时间']
tn = valid_data_drop.loc[i,'通过时间']
# 获取字段【信贷管理部审批退回时间】、【退回基层支行提交时间】的值
department_flag = valid_data_drop.loc[i,'信贷管理部审批退回时间']
branch_flag = valid_data_drop.loc[i,'退回基层支行提交时间']
# 计算起止时点的时长
if str(tn) != 'NaT':
if str(branch_flag) == 'NaT':
valid_data_drop.loc[i,'通过用时'] = interval(np.datetime64(t0),np.datetime64(tn))
else:
valid_data_drop.loc[i,'通过用时'] = interval(np.datetime64(t0),np.datetime64(department_flag)) + interval(np.datetime64(branch_flag),np.datetime64(tn))
## 5.5 计算拒绝用时
# 遍历已处理数据的索引
for i in valid_data_drop.index:
# 分别获取起止时点
t0 = valid_data_drop.loc[i,'支行行长提交时间']
tn = valid_data_drop.loc[i,'拒绝时间']
# 获取字段【信贷管理部审批退回时间】、【退回基层支行提交时间】的值
department_flag = valid_data_drop.loc[i,'信贷管理部审批退回时间']
branch_flag = valid_data_drop.loc[i,'退回基层支行提交时间']
# 计算起止时点的时长
if str(tn) != 'NaT':
if str(branch_flag) == 'NaT':
valid_data_drop.loc[i,'拒绝用时'] = interval(np.datetime64(t0),np.datetime64(tn))
else:
valid_data_drop.loc[i,'拒绝用时'] = interval(np.datetime64(t0),np.datetime64(department_flag)) + interval(np.datetime64(branch_flag),np.datetime64(tn))
# 6 生成通报表样
# 启动Excel程序
app = xw.App(visible=False,add_book=False)
# 读取工作簿
wb = app.books.open('C:/ZeroAuto/报表自动化/各支行贷款上报审批情况统计表/各支行贷款上报审批情况统计表.xlsx')
# 在工作表【加工明细_已录入】写入数据
data_write = valid_data_drop[(valid_data_drop['最后一次发起贷前调查时间'] >= start) & (valid_data_drop['最后一次发起贷前调查时间'] <= datetime(parse(end).year,parse(end).month,parse(end).day,23,59,59))].reset_index(drop=True)
# 确定工作表【加工明细_已录入】最后一行的行号
last_row_write = len(data_write) + 1
# 获取工作表【加工明细_已录入】
ws_write = wb.sheets['加工明细_已录入']
# 在指定区域内写入数据
ws_write.range(f'A2:R{last_row_write}').value = data_write.values.tolist()
# 在工作表【加工明细_已提交】写入数据
data_submit = valid_data_drop[(valid_data_drop['支行行长提交时间'] >= start) & (valid_data_drop['支行行长提交时间'] <= datetime(parse(end).year,parse(end).month,parse(end).day,23,59,59))].reset_index(drop=True)
# 确定工作表【加工明细_已提交】最后一行的行号
last_row_submit = len(data_submit) + 1
# 获取工作表【加工明细_已提交】
ws_submit = wb.sheets['加工明细_已提交']
# 在指定区域内写入数据
ws_submit.range(f'A2:R{last_row_submit}').value = data_submit.values.tolist()
# 在工作表【加工明细_审批中】写入数据
data_scrutiny = valid_data_drop[(~valid_data_drop['审批用时'].isnull()) & (valid_data_drop['支行行长提交时间'] <= datetime(parse(end).year,parse(end).month,parse(end).day,23,59,59))].reset_index(drop=True)
# 确定工作表【加工明细_审批中】最后一行的行号
last_row_scrutiny = len(data_scrutiny) + 1
# 获取工作表【加工明细_审批中】
ws_scrutiny = wb.sheets['加工明细_审批中']
# 在指定区域内写入数据
ws_scrutiny.range(f'A2:R{last_row_scrutiny}').value = data_scrutiny.values.tolist()
# 在工作表【加工明细_补资料】写入数据
data_add = valid_data_drop[(~valid_data_drop['补充用时'].isnull()) & (valid_data_drop['支行行长提交时间'] >= datetime(parse(end).year,parse(end).month,1,0,0,0)) & (valid_data_drop['信贷管理部审批退回时间'] <= datetime(parse(end).year,parse(end).month,parse(end).day,23,59,59))].reset_index(drop=True)
# 确定工作表【加工明细_补资料】最后一行的行号
last_row_add = len(data_add) + 1
# 获取工作表【加工明细_补资料】
ws_add = wb.sheets['加工明细_补资料']
# 在指定区域内写入数据
ws_add.range(f'A2:R{last_row_add}').value = data_add.values.tolist()
# 在工作表【加工明细_已拒绝】写入数据
data_veto = valid_data_drop[(valid_data_drop['拒绝时间'] >= start) & (valid_data_drop['拒绝时间'] <= datetime(parse(end).year,parse(end).month,parse(end).day,23,59,59))].reset_index(drop=True)
# 确定工作表【加工明细_已拒绝】最后一行的行号
last_row_veto = len(data_veto) + 1
# 获取工作表【加工明细_已拒绝】
ws_veto = wb.sheets['加工明细_已拒绝']
# 在指定区域内写入数据
ws_veto.range(f'A2:R{last_row_veto}').value = data_veto.values.tolist()
# 在工作表【加工明细_已通过】写入数据
data_pass = valid_data_drop[(valid_data_drop['通过时间'] >= start) & (valid_data_drop['通过时间'] <= datetime(parse(end).year,parse(end).month,parse(end).day,23,59,59))].reset_index(drop=True)
# 确定工作表【加工明细_已通过】最后一行的行号
last_row_pass = len(data_pass) + 1
# 获取工作表【加工明细_已通过】
ws_pass = wb.sheets['加工明细_已通过']
# 在指定区域内写入数据
ws_pass.range(f'A2:R{last_row_pass}').value = data_pass.values.tolist()
# 另存为工作簿
wb.save(f"C:/ZeroAuto/报表自动化/各支行贷款上报审批情况统计表/{original_date.replace('-','')[:8]}/各支行贷款上报审批情况统计表{start.replace('-','')[-4:]}-{end.replace('-','')[-4:]}.xlsx")
# 关闭工作簿
wb.close()
# 退出Excel程序
app.quit()
# 返回通报表样的地址
return f"C:/ZeroAuto/报表自动化/各支行贷款上报审批情况统计表/{original_date.replace('-','')[:8]}/各支行贷款上报审批情况统计表{start.replace('-','')[-4:]}-{end.replace('-','')[-4:]}.xlsx"
第二部分, 为主程序。
1 导入第三方库
# 数据读写与处理
import pandas as pd
import xlwings as xw
# 日期时间专用库
from time import time
from datetime import datetime,timedelta
from dateutil.parser import parse
# 不显示执行警告
import warnings
warnings.filterwarnings('ignore')
# 导入自动解决方案
from FlowMonitor import solution
# 启动计时器
time_begin = time()
2 读入流程数据
# 确定数据查询(反馈)日期
original_date = input('请输入数据查询(反馈)日期,如20230808:')
# 读入信贷全流程数据
original_data = pd.read_excel(f'C:/ZeroAuto/报表自动化/各支行贷款上报审批情况统计表/{original_date}/信贷全流程数据{original_date}.xlsx')
3 自动解决方案
# 确定起始日期
query_date = parse(original_date)
# 获取本月月初日期
month_start = str(datetime(query_date.year,query_date.month,1))[:10]
# 获取上周周一日期
week_start = str(datetime(query_date.year,query_date.month,query_date.day) - timedelta(7))[:10]
# 获取上周周末日期
statis_end = str(datetime(query_date.year,query_date.month,query_date.day) - timedelta(1))[:10]
# 手工录入三个日期(※跨月统计时采用※)
# month_start = '2023-07-01'
# week_start = '2023-07-24'
# statis_end = '2023-07-31'
# 统计期间为本月初至上周末
month_address = solution(original_date,month_start,statis_end,original_data)
# 统计期间为上周一至上周末
week_address = solution(original_date,week_start,statis_end,original_data)
4 自动通报说明
# 输入需要通报的名次(前/后n名)
n = eval(input('请输入需要通报的名次,如2:'))
# 强制换行
print()
# 新建阿拉伯与中文数字的映射字典
num_dict = {1:'一',2:'二',3:'三',4:'四',5:'五',6:'六',7:'七',8:'八',9:'九',10:'十'}
# 启动Excel程序
app = xw.App(visible=False, add_book=False)
# 遍历【当月累计】及【上周累计】的存储地址
for address in [month_address,week_address]:
## 4.1 获取日期区间
# 打开工作簿
inform_wb = app.books.open(f'{address}')
# 获取工作表
ws = inform_wb.sheets['各支行贷款上报审批情况统计表']
# 读取区域数据
data = ws.range('A2').expand('table').value
# 将数据重新写入区域
ws.range('A2').expand('table').value = data
# 获取单元格内容
inform_date = ws['A2'].value.split(':')[1]
# 关闭工作簿
inform_wb.close()
## 4.2 撰写通报说明
# 读取【当月累计】及【上周累计】的通报数据
inform_df = pd.read_excel(f'{address}',sheet_name='各支行贷款上报审批情况统计表',header=3)[:37]
# 指定各字段的名称
colnames = ['机构名称','数据查询时间',
'贷款笔数_已录入','贷款金额_已录入',
'贷款笔数_已提交','贷款金额_已提交','平均时限_已提交','最长时限_已提交',
'贷款笔数_审批中','贷款金额_审批中','平均时限_审批中','最长时限_审批中',
'贷款笔数_补资料','贷款金额_补资料','平均时限_补资料','最长时限_补资料',
'贷款笔数_已拒绝','贷款金额_已拒绝','平均时限_已拒绝','最长时限_已拒绝',
'贷款笔数_已通过','贷款金额_已通过','平均时限_已通过','最长时限_已通过'
]
# 字段重命名
inform_df.columns = colnames
# 计算【各机构】中【贷款笔数】、【贷款金额】排名-已录入、已提交、已通过
df_input = inform_df.query("机构名称 != '全行'").sort_values(by=['贷款笔数_已录入','贷款金额_已录入','机构名称'],ascending=False).reset_index(drop=True)
df_submit = inform_df.query("机构名称 != '全行'").sort_values(by=['贷款笔数_已提交','贷款金额_已提交','机构名称'],ascending=False).reset_index(drop=True)
df_pass = inform_df.query("机构名称 != '全行'").sort_values(by=['贷款笔数_已通过','贷款金额_已通过','机构名称'],ascending=False).reset_index(drop=True)
# 按固定格式设置通报的内容
df_input['通报内容'] = df_input[['机构名称','贷款笔数_已录入','贷款金额_已录入']].apply(lambda x: f'{x[0]}{int(x[1])}笔、{int(x[2])}万元',axis=1)
df_submit['通报内容'] = df_submit[['机构名称','贷款笔数_已提交','贷款金额_已提交']].apply(lambda x: f'{x[0]}{int(x[1])}笔、{int(x[2])}万元',axis=1)
df_pass['通报内容'] = df_pass[['机构名称','贷款笔数_已通过','贷款金额_已通过']].apply(lambda x: f'{x[0]}{int(x[1])}笔、{int(x[2])}万元',axis=1)
# 计算【各机构】中【平均时限】排名-已提交、已通过
df_submit_time = inform_df.query("(机构名称 != '全行') & (平均时限_已提交 > 0)").sort_values(by=['平均时限_已提交','贷款笔数_已提交','贷款金额_已提交','机构名称'],ascending=[True,False,False,False]).reset_index(drop=True)
df_pass_time = inform_df.query("(机构名称 != '全行') & (平均时限_已通过 > 0)").sort_values(by=['平均时限_已通过','贷款笔数_已通过','贷款金额_已通过','机构名称'],ascending=[True,False,False,False]).reset_index(drop=True)
# 按固定格式设置通报的内容
df_submit_time['通报内容'] = df_submit_time[['机构名称','平均时限_已提交']].apply(lambda x: f"{x[0]}平均{round(x[1],2)}h",axis=1)
df_pass_time['通报内容'] = df_pass_time[['机构名称','平均时限_已通过']].apply(lambda x: f"{x[0]}平均{round(x[1],2)}h",axis=1)
# 撰写第一部分:全行贷款上报审批笔数及金额
print(f"【各支行贷款上报审批情况{inform_date[0]}月通报】")
print(f"I)2023年{inform_date[:inform_date.index('-')+1]}{inform_date.split('-')[1][inform_date.split('-')[1].index('月')+1:]},全行贷款上报审批笔数及金额如下:")
print(f"①有效进件:{int(inform_df.iloc[0,2])}笔、{int(inform_df.iloc[0,3])}万元;")
print(f"其中:前{num_dict[n]}名为{';'.join(list(df_input.head(n)['通报内容']))};后{num_dict[n]}名为{';'.join(list(df_input.tail(n)['通报内容'])[::-1])};")
print(f"②提交审批:{int(inform_df.iloc[0,4])}笔、{int(inform_df.iloc[0,5])}万元;")
print(f"其中:前{num_dict[n]}名为{';'.join(list(df_submit.head(n)['通报内容']))};后{num_dict[n]}名为{';'.join(list(df_submit.tail(n)['通报内容'])[::-1])};")
print(f"③正在审批:{int(inform_df.iloc[0,8])}笔、{int(inform_df.iloc[0,9])}万元;")
print(f"④补充调查:{int(inform_df.iloc[0,12])}笔、{int(inform_df.iloc[0,13])}万元;")
print(f"⑤审批拒绝:{int(inform_df.iloc[0,16])}笔、{int(inform_df.iloc[0,17])}万元;")
print(f"⑥授信通过:{int(inform_df.iloc[0,20])}笔、{int(inform_df.iloc[0,21])}万元。")
print(f"其中:前{num_dict[n]}名为{';'.join(list(df_pass.head(n)['通报内容']))};后{num_dict[n]}名为{';'.join(list(df_pass.tail(n)['通报内容'])[::-1])}。")
# 撰写第二部分:全行贷款上报审批节点及用时
print(f"II)2023年{inform_date[:inform_date.index('-')+1]}{inform_date.split('-')[1][inform_date.split('-')[1].index('月')+1:]},全行贷款上报审批节点及用时如下:")
print(f"①提交审批:平均用时{round(inform_df.iloc[0,6],2)}h、最长用时{round(inform_df.iloc[0,7],2)}h;")
print(f"其中:前{num_dict[n]}名为{';'.join(list(df_submit_time.head(n)['通报内容']))};后{num_dict[n]}名为{';'.join(list(df_submit_time.tail(n)['通报内容'])[::-1])};")
print(f"②正在审批:平均用时{round(inform_df.iloc[0,10],2)}h、最长用时{round(inform_df.iloc[0,11],2)}h;")
print(f"③补充调查:平均用时{round(inform_df.iloc[0,14],2)}h、最长用时{round(inform_df.iloc[0,15],2)}h;")
print(f"④审批拒绝:平均用时{round(inform_df.iloc[0,18],2)}h、最长用时{round(inform_df.iloc[0,19],2)}h;")
print(f"⑤授信通过:平均用时{round(inform_df.iloc[0,22],2)}h、最长用时{round(inform_df.iloc[0,23],2)}h。")
print(f"其中:前{num_dict[n]}名为{';'.join(list(df_pass_time.head(n)['通报内容']))};后{num_dict[n]}名为{';'.join(list(df_pass_time.tail(n)['通报内容'])[::-1])}。\n")
# 退出Excel程序
app.quit()
# 打印处理时间
print(f"用时{datetime.fromtimestamp(time()-time_begin).strftime('%M:%S:%f')}")
八、运行结果
因涉及经营业务,仅展示下运行的时间,为45秒左右。
九、末尾总结
第一, 只有深刻理解业务,才能正确地分析解读数据,获得结论。前期因为对“信贷全流程”系统的授信流转节点不熟悉,匆忙动手后得出了与实际天壤之别的判断。在“摸着石头过河”的过程中,叨扰了许多客户经理,在这里一并表示感谢;
第二, 刚接收这个任务的时候,因为“想当然”,所以觉得不难。随着领导的要求越来越细化,也是感受到了压力。从着手项目到最终验收,前后经历了6次数据口径、加工逻辑和通报表样等调整,花费了大约半个月的时间。在这里也感谢领导的信任;
第三, 最后,表达下我的愿望。我相信,以本项目为例,在未来,从数据获取、数据加工、结果展示到渠道发布,可能只是一个单击的问题。清华大学陆向镰教授在回答“ChatGPT取代程序员?孩子们还需要学编程吗?”的问题时,说了一句使我受益终身的话——互联网人工智能,在颠覆所有行业,也在不断颠覆自己,所以让自己站在颠覆这边,别站在被颠覆这边。
学习资源推荐
除了上述分享,如果你也喜欢编程,想通过学习Python获取更高薪资,这里给大家分享一份Python学习资料。
😝朋友们如果有需要的话,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓
👉CSDN大礼包🎁:全网最全《Python学习资料》免费赠送🆓!(安全链接,放心点击)
学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

一、Python学习路线
二、Python基础学习
1. 开发工具
2. 学习笔记
3. 学习视频
三、Python小白必备手册
四、数据分析全套资源
五、Python面试集锦
1. 面试资料
2. 简历模板

因篇幅有限,仅展示部分资料,添加上方即可获取