2023 年“泰迪杯”数据分析技能赛 A 题 档案数字化加工流程数据分析

完整代码请私聊 博主

一、 背景

档案数字化是随着扫描、OCR、数字摄影、数据库、多媒体、存储等技术的发展而产生的一种新型档案信息处理技术,它把各种载体的档案资源转化为数字化档案信息,以数字化的形式存储,网络化的形式互相连接,利用计算机系统进行管理,形成一个有序结构的档案信息库。我国档案工作采取“存量数字化、增量电子化”的信息化战略。当前我国各行业的存量档案数量巨大,档案数字化的需求不断增加,档案数字化加工行业的市场规模呈现逐年增长的趋势。

二、 目标

对加工流程数据进行统计分析,并作可视化展示,便于管理人员及时了解档案加工处理动态。

  1. 统计档案数字化流程的耗时和进度情况。
  2. 统计操作人员的工作量和工作效率情况。

三、 案卷加工流程说明

  1. 加工流程按先后顺序分为以下几个工序:扫描、图像处理、自检全检、PDF 处理。
  2. 操作人员领取、提交案卷:一个操作人员可以胜任多个工序的工作。启动某个工序时,操作人员首先在系统上批量领取一定数量的加工任务,文件 data.xlsx 中的字段“dUPDATE_TIME”记录了每份案卷的领取时间;档案处理完成后,在系统上进行批量提交,文件 data.xlsx 中的字段“dNODE_TIME”记录了每份案卷的提交时间。当领取的案卷数量较多时,通常会在中午休息前或下午下班前提交已完成的部分案卷。允许操作人员在未完成已领取的任务前领取新任务。
  3. 工作效率按批进行计算,将同一批案卷的最后提交时间减去这批案卷的最早领取时间作为该批案卷的总耗时,以此计算该批案卷的平均耗时。所谓“批”是对同一个操作人员在同一个工序中,从领取第一份案卷开始,直到该操作人员在该工序中所有案卷都提交完成,在这段时间内处理的所有案卷。文件 data.xlsx 中的字段“sBatch_number”记录了批的编号。
    2
  4. 文件 data.xlsx 中的字段“iNODE_STATUS”(工序状态)为 2,表明案卷已完成并提交,且不需要返工;该字段为 5,表明案卷经过返工,已完成并提交。
  5. 工作时间为周一至周六上午 8:30-12:00,下午 13:00-18:00,案卷的处理时间和操作人员的工作时长应去掉非工作时间。注意:实际工作中,可能有提前上岗或推迟下岗的情况。

四、 任务

data.xlsx 记录了某档案数字化加工单位 2020 年 7 月加工处理过程中各个工序的管理数据。请编程完成以下任务并撰写报告,在报告中详细描述各项任务的处理思路、过程及必要的结果。结果的模板文件在文件夹“result”中。

任务 1 数据预处理与统计

任务 1.1

统计完成四道工序的案卷数量,在报告中列出统计结果。汇总各案卷各工序的开始时间及各案卷的完成时长,以表 1 的格式将汇总结果保存到文件“result1_1.xlsx”中,同时在报告中列出案卷完成时长最长的三个案卷的结果。
注 1 每个案卷的完成时长是扫描、图像处理、自检全检三个工序的耗时之和,PDF 处理无需计算耗时,各工序的耗时是该工序的开始时间至结束时间的时长。
注 2 完成时长应去掉非工作时间(“三、案卷加工流程说明”第 5 条),单位:h,保留 3 位小数。
在这里插入图片描述

import pandas as pd
import numpy as np
df1_1 = pd.read_excel('data.xlsx')
df1_1.head()
df1_1 = df1_1[df1_1['iNODE_STATUS']==2]
df1_1['iNODE_STATUS'].count()
135143
data = pd.DataFrame(columns=['案卷号','扫描开始时间','扫描结束时间'])
data

data2 = pd.DataFrame(columns=['案卷号','图像处理开始时间','图像处理结束时间'])
data2

data3 = pd.DataFrame(columns=['案卷号','自检全检开始时间','自检全检结束时间'])
data3

data4 = pd.DataFrame(columns=['案卷号','PDF处理开始时间','PDF处理结束时间'])
data4
data['案卷号'] = df1_1['sARCH_ID']

data2['案卷号'] = df1_1['sARCH_ID']

data3['案卷号'] = df1_1['sARCH_ID']

data4['案卷号'] = df1_1['sARCH_ID']
data['扫描开始时间'] = df1_1[df1_1['iFLOW_NODE_NO']==1]['dUPDATE_TIME']
data['扫描结束时间'] = df1_1[df1_1['iFLOW_NODE_NO']==1]['dNODE_TIME']

data2['图像处理开始时间'] = df1_1[df1_1['iFLOW_NODE_NO']==2]['dUPDATE_TIME']
data2['图像处理结束时间'] = df1_1[df1_1['iFLOW_NODE_NO']==2]['dNODE_TIME']

data3['自检全检开始时间'] = df1_1[df1_1['iFLOW_NODE_NO']==3]['dUPDATE_TIME']
data3['自检全检结束时间'] = df1_1[df1_1['iFLOW_NODE_NO']==3]['dNODE_TIME']

data4['PDF处理开始时间'] = df1_1[df1_1['iFLOW_NODE_NO']==4]['dUPDATE_TIME']
data4['PDF处理结束时间'] = df1_1[df1_1['iFLOW_NODE_NO']==4]['dNODE_TIME']

data.dropna(inplace=True)
data.reset_index(inplace=True,drop=True)
data

data2.dropna(inplace=True)
data2.reset_index(inplace=True,drop=True)
data2

data3.dropna(inplace=True)
data3.reset_index(inplace=True,drop=True)
data3

data4.dropna(inplace=True)
data4.reset_index(inplace=True,drop=True)
data4
		案卷号			扫描开始时间				扫描结束时间
0		托644031-册一	2020-07-01 09:17:22.313	2020-07-01 09:21:10
1		托644032-册一	2020-07-01 09:17:42.867	2020-07-01 09:21:17
2		托7181-册一		2020-07-01 08:39:08.370	2020-07-01 09:26:29
3		托7182-册一		2020-07-01 08:39:08.397	2020-07-01 09:26:36
4		托7183-册一		2020-07-01 08:39:08.420	2020-07-01 09:26:42
...		...				...						...
33823	托750599-册一	2020-07-30 15:27:57.460	2020-07-30 16:22:13
33824	托750600-册一	2020-07-30 15:28:27.477	2020-07-30 16:22:20
33825	托698742-册一	2020-07-30 13:10:03.703	2020-07-30 16:22:44
33826	托750590-册一	2020-07-30 15:27:57.380	2020-07-30 16:25:02
33827	托750591-册一	2020-07-30 15:27:57.390	2020-07-30 16:27:27
df = data.merge(data2)
df2 = df.merge(data3)
df3 = df2.merge(data4)
df3
df3['扫描开始时间'] = df3['扫描开始时间'].dt.floor('1s')
df3['扫描开始day'] = df3['扫描开始时间'].dt.day
df3['扫描结束day'] = df3['扫描结束时间'].dt.day
df3['图像处理开始day'] = df3['图像处理开始时间'].dt.day
df3['图像处理结束day'] = df3['图像处理结束时间'].dt.day
df3['自检全检开始day'] = df3['自检全检开始时间'].dt.day
df3['自检全检结束day'] = df3['自检全检结束时间'].dt.day
date_time = pd.to_datetime(df3['扫描开始时间'])
df3['扫描开始time'] = date_time.dt.hour + date_time.dt.minute / 60 + date_time.dt.second / 3600

date_time = pd.to_datetime(df3['扫描结束时间'])
df3['扫描结束time'] = date_time.dt.hour + date_time.dt.minute / 60 + date_time.dt.second / 3600

date_time = pd.to_datetime(df3['图像处理开始时间'])
df3['图像处理开始time'] = date_time.dt.hour + date_time.dt.minute / 60 + date_time.dt.second / 3600

date_time = pd.to_datetime(df3['图像处理结束时间'])
df3['图像处理结束time'] = date_time.dt.hour + date_time.dt.minute / 60 + date_time.dt.second / 3600

date_time = pd.to_datetime(df3['自检全检开始时间'])
df3['自检全检开始time'] = date_time.dt.hour + date_time.dt.minute / 60 + date_time.dt.second / 3600

date_time = pd.to_datetime(df3['自检全检结束时间'])
df3['自检全检结束time'] = date_time.dt.hour + date_time.dt.minute / 60 + date_time.dt.second / 3600
def clean(sd,ed,st,et):
    if sd == ed:
        if 8.5<=et<=12:
            return et-st
        elif 13<=et<=18:
            if 13<=st<=18:
                return et-st
            else:
                return et-st-1
.....................................................
        else:
            if 8.5<=et<=12:
                return (18-st)+(et-8.5)
            else:
                return (18-st)+(3.5+18-et)


df3['扫描时长'] = df3.apply(lambda x:clean(x['扫描开始day'],x['扫描结束day'],x['扫描开始time'],x['扫描结束time']),axis=1)
.......................................................
df3['完成时长'] = df3['扫描时长'].values+df3['图像时长'].values+df3['自检全检时长'].values

df3 = df3[['案卷号','扫描开始时间','扫描结束时间','图像处理开始时间',
           '图像处理结束时间','自检全检开始时间','自检全检结束时间','PDF处理开始时间','PDF处理结束时间','完成时长']]
df3
案卷号	扫描开始时间	扫描结束时间	图像处理开始时间	图像处理结束时间	自检全检开始时间	自检全检结束时间	PDF处理开始时间	PDF处理结束时间	完成时长
0	托644031-册一	2020-07-01 09:17:22	2020-07-01 09:21:10	2020-07-01 15:01:56	2020-07-01 16:44:24	2020-07-08 08:35:26	2020-07-08 10:54:15	2020-07-10 15:05:18	2020-07-10 15:18:02	4.084722
1	托644032-册一	2020-07-01 09:17:42	2020-07-01 09:21:17	2020-07-01 15:01:56	2020-07-01 16:44:26	2020-07-08 08:35:26	2020-07-08 10:54:17	2020-07-10 15:05:18	2020-07-10 15:18:02	4.082222
2	托7181-册一	2020-07-01 08:39:08	2020-07-01 09:26:29	2020-07-02 10:47:50	2020-07-02 11:30:47	2020-07-02 11:31:18	2020-07-02 11:43:48	2020-07-03 08:49:13	2020-07-03 09:04:24	1.713333
3	托7182-册一	2020-07-01 08:39:08	2020-07-01 09:26:36	2020-07-02 10:47:50	2020-07-02 11:31:08	2020-07-02 11:31:18	2020-07-02 11:43:50	2020-07-03 08:49:13	2020-07-03 09:04:24	1.721667
4	托7183-册一	2020-07-01 08:39:08	2020-07-01 09:26:42	2020-07-02 13:37:15	2020-07-02 13:53:05	2020-07-02 15:07:37	2020-07-02 15:15:12	2020-07-03 08:49:13	2020-07-03 09:04:24	1.183056
...	...	...	...	...	...	...	...	...	...	...
33356	托750599-册一	2020-07-30 15:27:57	2020-07-30 16:22:13	2020-07-31 10:10:06	2020-07-31 10:21:15	2020-07-31 10:23:55	2020-07-31 13:35:57	2020-07-31 14:06:17	2020-07-31 14:28:47	3.290833
33357	托750600-册一	2020-07-30 15:28:27	2020-07-30 16:22:20	2020-07-30 16:52:21	2020-07-31 08:38:13	2020-07-31 10:24:12	2020-07-31 13:36:06	2020-07-31 14:06:17	2020-07-31 14:28:47	4.360833
33358	托698742-册一	2020-07-30 13:10:03	2020-07-30 16:22:44	2020-07-30 16:19:40	2020-07-30 16:22:29	2020-07-31 08:27:52	2020-07-31 10:09:09	2020-07-31 11:07:01	2020-07-31 11:21:18	4.946389
33359	托750590-册一	2020-07-30 15:27:57	2020-07-30 16:25:02	2020-07-31 10:10:05	2020-07-31 10:20:51	2020-07-31 10:23:54	2020-07-31 13:35:31	2020-07-31 14:06:17	2020-07-31 14:28:46	3.324444
33360	托750591-册一	2020-07-30 15:27:57	2020-07-30 16:27:27	2020-07-31 10:10:05	2020-07-31 10:20:52	2020-07-31 10:23:54	2020-07-31 13:35:32	2020-07-31 14:06:17	2020-07-31 14:28:46	3.365278

df3['完成时长'].sort_values( ascending=False)[:5]
df3.to_excel('result1_1.xlsx',index=None)
27963    30.738611
27962    30.718056
27961    30.700833
27960    30.674167
2292     30.617778

任务 1.2

统计需要返工的案卷数量及其占完工案卷总数的百分比,在报告中列出结果。
汇总返工案卷的返工工序和返工开始时间,以表 2 的格式将汇总结果保存到文件“result1_2.xlsx”中,同时在报告中列出返工案卷号“托 40606-册六”“托 40606-册七”“托 5901_1-册三”的结果。
注 未返工工序的时间为空。
在这里插入图片描述

df1_2 = pd.read_excel('data.xlsx')
df1_2.head()
.......................
rework_percentage = (rework_count / total_count) * 100  
print("需要返工的案卷数量:", rework_count)  
print("占完工案卷总数的百分比:", rework_percentage, "%")
需要返工的案卷数量: 797
占完工案卷总数的百分比: 0.5862880682654112 %
df1_2.reset_index(drop=True,inplace=True)
df1_2
fg = pd.DataFrame(columns=['案卷号','扫描','图像处理','自检全检','PDF 处理'])
fg['案卷号'] = df1_2['sARCH_ID']
fg['扫描'] = df1_2[df1_2['iFLOW_NODE_NO']==1]['dUPDATE_TIME']
fg['图像处理'] = df1_2[df1_2['iFLOW_NODE_NO']==2]['dUPDATE_TIME']
fg['自检全检'] = df1_2[df1_2['iFLOW_NODE_NO']==3]['dUPDATE_TIME']
fg['PDF 处理'] = df1_2[df1_2['iFLOW_NODE_NO']==4]['dUPDATE_TIME']
fg[(fg['案卷号']=='托40606-册六')|(fg['案卷号']=='托40606-册七')|(fg['案卷号']=='托5901_1-册三')]
fg.to_excel('result1_2.xlsx',index=None)
	案卷号	扫描	图像处理	自检全检	PDF 处理
50	托40606-册六	NaT	NaT	2020-07-07 10:58:05	NaT
51	托40606-册七	NaT	NaT	2020-07-07 10:58:05	NaT
193	托5901_1-册三	NaT	2020-07-11 11:53:34	NaT	NaT

任务 1.3

对自检全检工序,汇总每个操作人员的返工案卷数,计算其占该操作人员该工序工作总量的百分比,按百分比降序排列,以表 3 的格式将结果保存到文件“result1_3.xlsx”中,同时在报告中列出前三位操作人员的结果。结果保留 3 位小数,例如:返工案卷占比为 1%,在结果表中填写“1.000”。
在这里插入图片描述

	操作人员ID	count	返工案卷占比(%)
1	10			11579	0.341
2	12			8339	0.245
3	13			7224	0.213

任务 1.4

按工序分别统计完成案卷的数量、总耗时和平均耗时,以表 4 的格式将结果保存到文件“result1_4.xlsx”中,并在报告中列出结果。结果保留 3 位小数。
注 按工序计算总耗时,是该工序各个批次的案卷集最早开始时间至案卷集最晚结束时间之和,而不是各个案卷完成时长的总和。
在这里插入图片描述

	工序	完成案卷的数量	总耗时(h)	平均耗时(h/卷)
0	扫描	33828	24.837	0.001
1	图像处理	33815	27.306	0.001
2	自检全检	33619	35.187	0.001
3	PDF 处理	33881	32.901	0.001

任务 1.5

按操作人员、工序统计工作时长、完成案卷的数量和每个案卷的平均耗时(h/卷),以表 5 的格式将结果按操作人员 ID 升序排列保存到文件“result1_5.xlsx”中,同时在正文中列出操作人员 ID“10”“33”“48”的结果。结果保留 3 位小数。
注 按操作人员、工序统计工作时长是按批进行的(“三、案卷加工流程说明”第 3条),应去除非工作时间(“三、案卷加工流程说明”第 5 条)。
在这里插入图片描述

df1_5 = pd.read_excel('data.xlsx')
date_time = pd.to_datetime(df1_5['dUPDATE_TIME'])
df1_5['开始'] = date_time.dt.hour + date_time.dt.minute / 60 + date_time.dt.second / 3600

date_time = pd.to_datetime(df1_5['dNODE_TIME'])
df1_5['结束'] = date_time.dt.hour + date_time.dt.minute / 60 + date_time.dt.second / 3600

df1_5['工作时长(h)'] = round(abs(df1_5['结束']-df1_5['开始']),3)

result = df1_5[df1_5['iNODE_STATUS'] == 2]
result = result.groupby(['iUSER_ID','iFLOW_NODE_NO'],as_index=False).agg({'工作时长(h)':'sum','sARCH_ID':'nunique'})
result['每个案卷的平均耗时(h/卷)'] = round(result['工作时长(h)']/result['sARCH_ID'],3)
result = result.reset_index()
result = result.rename(columns={'iUSER_ID':'操作人员ID','iFLOW_NODE_NO':'工序','sARCH_ID':'完成案卷的数量'})

result = result.drop('index',axis=1)

result.to_excel('result1_5.xlsx',index=None)
result[(result['操作人员ID']==10)|(result['操作人员ID']==33)|(result['操作人员ID']==48)]
	操作人员ID	工序	工作时长(h)	完成案卷的数量	每个案卷的平均耗时(h/卷)
3	10	1	4.951	9	0.550
4	10	2	0.422	9	0.047
5	10	3	20489.869	11501	1.782
25	33	1	6870.677	2300	2.987
31	48	2	10104.625	3579	2.823

任务 2 数据分析与可视化

读取数据
import pandas as pd
import matplotlib.pyplot as plt
import pyecharts
from pyecharts import options as opts

plt.rcParams['font.sans-serif'] = 'SimHei'
df2 = pd.read_excel('data.xlsx')
df2.head(4)
	iID	iPID	uFILE_FLAG	sARCH_ID	sFLOW_NAME	sNODE_NAME	iNODE_STATUS	iUSER_ID	iWF_ID	iWN_ID	...	iFLOW_NODE_NO	iPROC_USERID	sPIC_SERVER_PATH	sPDF_SERVER_PATH	iARCH_TYPE	sORDER_ARCH_ID	dUPDATE_TIME	dNODE_TIME	dPROC_TIME	sBatch_number
0	725975	186250	0B71F6DD-E7EC-4FB2-87C4-EB576B70F4C2	托644031-册一	不动产工作流	扫描	2	68	20	12	...	1	NaN	\\127.0.0.1\tlscan\tlscanfile	\\192.168.1.253\tlscan\tlscanpdf	91	托00644031-册001	2020-07-01 09:17:22.313	2020-07-01 09:21:10	NaT	902
1	725976	186251	7B0B1758-12F7-4A44-91F9-96C5B9B2E6FD	托644032-册一	不动产工作流	扫描	2	68	20	12	...	1	NaN	\\127.0.0.1\tlscan\tlscanfile	\\192.168.1.253\tlscan\tlscanpdf	91	托00644032-册001	2020-07-01 09:17:42.867	2020-07-01 09:21:17	NaT	902
2	725249	185781	94CC72C0-A6B4-4627-868E-EE3B423877C7	托7181-册一	不动产工作流	扫描	2	44	20	12	...	1	NaN	\\127.0.0.1\tlscan\tlscanfile	\\192.168.1.253\tlscan\tlscanpdf	91	托00007181-册001	2020-07-01 08:39:08.370	2020-07-01 09:26:29	NaT	604
3	725250	185782	FA6E9CC1-5579-41D5-918B-6B9F0D3B2486	托7182-册一	不动产工作流	扫描	2	44	20	12	...	1	NaN	\\127.0.0.1\tlscan\tlscanfile	\\192.168.1.253\tlscan\tlscanpdf	91	托00007182-册001	2020-07-01 08:39:08.397	2020-07-01 09:26:36	NaT	604

任务 2.1

计算并绘制每天不同工序完成案卷数量的簇状柱形图:x 轴表示时间,y 轴表示完成案卷的数量,用不同颜色标记不同工序。

df2_1 = df2[df2['iNODE_STATUS']==2]
df2_1
df2_1 = df2_1.groupby(['iFLOW_NODE_NO','dNODE_TIME']).size().reset_index(name='完成案卷的数量')
df2_1
df2_1['dNODE_TIME'] = df2_1['dNODE_TIME'].dt.date
df2_1
df2_1 = df2_1.groupby(['dNODE_TIME','iFLOW_NODE_NO'],as_index=False).agg({'完成案卷的数量':'sum'})
df2_1
x = df2_1['dNODE_TIME'].unique().tolist()

y1 = df2_1[df2_1['iFLOW_NODE_NO']==1]['完成案卷的数量'].tolist()

y2 = df2_1[df2_1['iFLOW_NODE_NO']==2]['完成案卷的数量'].tolist()

y3 = df2_1[df2_1['iFLOW_NODE_NO']==3]['完成案卷的数量'].tolist()

y4 = df2_1[df2_1['iFLOW_NODE_NO']==4]['完成案卷的数量'].tolist()
from pyecharts.charts import Bar

bar_1 = (
    Bar(
        init_opts=opts.InitOpts(bg_color='white',)
    )
    .add_xaxis(x)
    .add_yaxis("扫描", y1, gap="0%")
    .add_yaxis("图像处理", y2, gap="0%")
    .add_yaxis("自检全检", y3, gap="0%")
    .add_yaxis("PDF 处理", y4, gap="0%")
    .set_global_opts(
        title_opts=opts.TitleOpts(title="每天不同工序完成案卷数量的簇状柱形图"),
        xaxis_opts=opts.AxisOpts(
            type_="category",
            boundary_gap=False,
            axislabel_opts=opts.LabelOpts(rotate=80),
        ),
        legend_opts=opts.LegendOpts(
            type_='plain',
            pos_left='80%',
            pos_top='5%',
        ),
    )
)
bar_1.render_notebook()

在这里插入图片描述

任务 2.2

计算并绘制各工序每天投入工作量(单位:人·小时)的多重折线图:x 轴表示时间,y 轴表示每天投入的工作量,用不同颜色标记不同工序。

在这里插入图片描述

任务 2.3

绘制每天各工序返工案卷数占当天返工案卷总数的百分比堆积面积图:x 轴表示时间,y 轴表示百分比,用不同颜色标记不同工序。

在这里插入图片描述

任务 2.4

对图像处理工序,汇总每个操作人员返工案卷数,计算其占该工序返工案卷总数的百分比,并按百分比进行排序,绘制饼图,其中排名第 10 位及以后的合并成一个扇区。

在这里插入图片描述

任务 3 领取提交模式分析

档案的数字化加工中,操作人员在某个工序中的正常领取提交模式是在相对集中的时间内领取若干案卷,全部加工完成后在相对集中的时间内按照领取的顺序提交该批案卷。但在现实中会出现更多类型的领取提交模式,例如操作人员有时会分多次领取案卷,处理完后一起集中提交;或在未完全提交已领取案卷的情况下又领取了新的案卷。出现这种情况的可能原因是,在处理已领取的案卷时发现这些案卷的处理难度低于平均难度,操作人员出于提高个人工作效率的考虑通过多次领取的方式“囤积”易处理案卷。
可通过可视化的方法分析案卷领取提交时序,例如在图 1 所示的桑基图中,每份案卷对应图中一条直线,左端点的纵坐标表示领取时间,右端点的纵坐标表示提交时间。
在这里插入图片描述
图 1(b)对应于分两次领取、分两次提交,不同的案卷集在处理时序上出现交叉的领取提交模式。也可以使用图 2 中的模式示意图来表达。
在这里插入图片描述
请根据文件 data.xlsx 的批次数据,通过可视化的方法分析批次内案卷的领取提交时序,总结有哪几种领取提交模式。对每一种模式给出一个实际例子,以表 6 的格式保存到文件“result3.xlsx”中,同时在报告中参照图 1 和图 2 的方式分别绘制两种不同的示意图。
在这里插入图片描述
略。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

附录 数据说明
数据文件 data.xlsx 中的每条记录对应于一个案卷某个工序的处理记录,其中的字段名及其含义如表 7 所示。
在这里插入图片描述

完整代码请私聊 博主

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐