Python办公——1分钟搞定每周业务通报及说明

一、需求背景

为加强贷款营销的过程管控,监测客户授信过程中各阶段的效能与转化,定位痛点堵点问题,切实促进业务增长与提升客户体验度,特制订《各支行贷款上报审批情况统计表》。

二、通报表样

三、通报说明

四、字段解释

需要作以下说明:

(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扫描下方二维码联系领取

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

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

image-20230619144606466

二、Python基础学习
1. 开发工具

2. 学习笔记

在这里插入图片描述

3. 学习视频

在这里插入图片描述

三、Python小白必备手册

图片

四、数据分析全套资源

在这里插入图片描述

五、Python面试集锦
1. 面试资料

在这里插入图片描述

在这里插入图片描述

2. 简历模板

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值