前言:由于全国受到新型冠状病毒的影响,我们学校在已有的学工系统开发了 “每日一报”和“i签到” 两个功能来记录学生的身体状况和位置信息,确保并监督学生无误填写,每天辅导员都要多次从系统中导出今日打卡记录,并让班长提醒未打卡同学打卡或者有信息异常的同学重新确认信息。
操作平台: win10,python37,jupyter
图片名字等信息均打码处理
● 筛选出未信息通知学生: 需要一直统计催打卡,过程艰辛复杂!
● 领导反馈: 学生出现乱填乱写的情况很严重,需要老师来做好把关工作!
import pandas as pd
data1 = pd.read_excel("./data/测试/每日一报.xlsx")#导入每日一报数据
data1.columns#查看表头
Index(['学号', '姓名', '性别代码', '性别', '联系方式', '学院', '专业代码', '专业', '班级', '年级',
'是否完成填报', '辅导员填报', '本人体温', '本人是否是疑似病例或确诊病例', '本人是否接触过疑似或确诊病例',
'本人是否是湖北、武汉经历的人', '本人是否是确诊病例的密切接触者共同居住人员',
'本人居住地是否是湖北省以外疫点人员(指生活的小区、单元楼发生确诊病例)', '本人昨天是否外出', '外出地点',
'本人是否被社区列为重点排查对象', '被确定为重点排查对象时间', '是否解除隔离', '解除隔离时间', '具体解除时间',
'家庭成员感染新冠状病毒情况', '居住地是否发生变化', '是否有发热、咳嗽等症状'],
dtype='object')
data.shape
(340, 28)
结果分析: 从学工系统中导出的《每日一报》表格一共有340行,也就是340人;一共有28列数据信息,其中大部分是需要填写的,其他信息可以更改。
data['是否完成填报'].value_counts()
已完成 282
未完成 58
Name: 是否完成填报, dtype: int64
data['是否完成填报'] == '未完成'
返回的结果为 True
和 False
,当它相等时返回True,提取返回 True
的所有数据,就是没有打卡的数据。noDo = data[data['是否完成填报'] == '未完成'] #提取出未完成的学生
noDo.head()#显示前五行
noDo = data[data['是否完成填报'] == '未完成'] #提取出未完成的学生
noDo_num = noDo.shape[0] #获取未打卡人数,如果全部完成,就不需要查找对应的同学
if noDo_num == 0:
print ("▼ 每日一报已全部打卡完毕!")
else:
print ("▼ 每日一报未打卡人数: %s(人)"%noDo_num)#记录未打卡人数
for bj in range(len(noDo['班级'].unique())): #noDo['班级'].unique()取出所有未打卡的班级,并去重,计算班级数
class_xinxi = noDo['班级'].unique()[bj] #依次取出每个
index = noDo[noDo['班级'] == class_xinxi] #在该班级中取出对应的同学
name_list = [] #每次循环到这里都会把它置空
for name in index['姓名']:
name_list.append(name)
names = "、".join(name_list)#将数组变为字符串
print (class_xinxi + ": "+ names +'\n')
结果如下:
备注: 找出《i签到》未打卡的同学,方式也是一样的,这里就不重述了。
(1)查看众数
# 取众数
mode = data['是否完成填报'].mode()[0] #它输出的值为数组,加上[0]提取第一个值为字符串,在这里几乎不会出现两个众数
mode
'已完成'
(2)提取出异常的数据
do_data = data[data['是否完成填报'] == '已完成'] #只统计完成的同学,为打卡的为空值,以免被空值干扰众数
mode = do_data['本人是否是疑似病例或确诊病例'].mode()[0] #众数
dif_do = do_data[do_data['本人是否是疑似病例或确诊病例'] != mode] #提取出完成打卡中的异常值,不等于众数的就是异常值
dif_do
(1)提取出表头
columns =['本人是否是疑似病例或确诊病例', '本人是否接触过疑似或确诊病例', '本人是否是湖北、武汉经历的人', '本人是否是确诊病例的密切接触者共同居住人员', '本人居住地是否是湖北省以外疫点人员(指生活的小区、单元楼发生确诊病例)', '家庭成员感染新冠状病毒情况', '是否有发热、咳嗽等症状']
for col in columns:
print (col)
本人是否是疑似病例或确诊病例
本人是否接触过疑似或确诊病例
本人是否是湖北、武汉经历的人
本人是否是确诊病例的密切接触者共同居住人员
本人居住地是否是湖北省以外疫点人员(指生活的小区、单元楼发生确诊病例)
家庭成员感染新冠状病毒情况
是否有发热、咳嗽等症状
(2)用法
data['本人是否是疑似病例或确诊病例']
0 否,身体健康
1 否,身体健康
2 否,身体健康
3 否,身体健康
4 否,身体健康
...
335 否,身体健康
336 否,身体健康
337 NaN
338 否,身体健康
339 否,身体健康
Name: 本人是否是疑似病例或确诊病例, Length: 340, dtype: object
NaN
表示空值,没有数据,也就是没有打卡(3)总结
我提取出我需要额外审核的列,把它放进 data[ ]
中,就可以获取到同学们打卡的所有信息了
# 移除不必要的列
columns =['本人是否是疑似病例或确诊病例', '本人是否接触过疑似或确诊病例', '本人是否是湖北、武汉经历的人', '本人是否是确诊病例的密切接触者共同居住人员', '本人居住地是否是湖北省以外疫点人员(指生活的小区、单元楼发生确诊病例)', '家庭成员感染新冠状病毒情况', '是否有发热、咳嗽等症状']
do_data = data[data['是否完成填报'] == '已完成'] #只统计完成的同学,为打卡的为空值,以免被空值干扰众数
for col in columns:
mode = do_data[col].mode()[0] #众数
dif_do = do_data[do_data[col] != mode] #提取出完成打卡中的异常值,不等于众数的就是异常值
dif_do_num = dif_do.shape[0] #统计异常值数量,如果为0,就结束这个循环
if dif_do_num == 0:
pass
else:
print ("●",col + ":",dif_do_num, "人")
for bj in range(len(dif_do['班级'].unique())):
class_xinxi = dif_do['班级'].unique()[bj]
index = dif_do[dif_do['班级'] == class_xinxi]
name_list = []
for name in index['姓名']:
name_list.append(name)
names = "、".join(name_list)
print (class_xinxi + ": "+ names)
print ("")
import re
#学生可能出现的体温填写情况
text_list = ['36','36.3', '体温:36.4', '36.5度', '体温正常', '36.6℃','36度7', '38度8','3690', '368', '370度', '体温:38度1']
for txt in text_list:
text = re.sub("[^0-9\u4e00.]", "", txt) #只保留数字“0~9”和“.”
if text == '':
print("text没有数值:", txt)
else:
if float(text) < 35.5 or float(text) > 37.2:
#如果体温中有“度”字,如:36度8,用“度”字进行分隔,分别去掉干扰因子,下一步拼接完整,末尾接“0”防止小数点在末尾
if "度" in txt:
temperature = re.sub("[^0-9\u4e00.]","", txt.split('度')[0]) + "." + re.sub("[^0-9\u4e00.]","", txt.split('度')[1]) + "0"
if float(temperature) < 35.5 or float(temperature) > 37.2:
print ("超过范围:",txt)
else:
print ("体温异常:", text)
text没有数值: 体温正常
超过范围: 38度8
体温异常: 3690
体温异常: 368
超过范围: 370度
超过范围: 体温:38度1
结果分析: 这样就可以找出没有填写具体体温的同学了。
temperature_tab = do_data['本人体温'] #体温列
for i in do_data.index:
temperature = re.sub("[^0-9\u4e00.]","", str(temperature_tab[i])) #体温清洗,只保留"数值"和“.”
if temperature == '':
print ("没有填写具体体温: ", do_data['班级'][i], do_data['姓名'][i], do_data['本人体温'][i])
print ("\n◙以下同学的体温不在35.5~37.2度之间")
for i in do_data.index:#从数据索引中循环出索引
temperature = re.sub("[^0-9\u4e00.]","", str(temperature_tab[i]))
if temperature == '':
continue #运行到这里后就结束程序当前运行,过滤掉没有数值的数据
single_tem = do_data['本人体温'][i] #遍历个人体温
# 为了预防学生填写的类型超过我的判断,设置一个异常捕捉
try:
if float(temperature) < 35.5 or float(temperature) > 37.2: #体温不在[3.5, 37.2]之间,进行下一步,初步判断异常
#如果体温中有“度”字,如:36度8,用“度”字进行分隔,分别去掉干扰因子,下一步拼接完整
if "度" in single_tem:
temperature = re.sub("[^0-9\u4e00.]","", str(single_tem.split('度')[0])) + "." + re.sub("[^0-9\u4e00.]","", str(single_tem.split('度')[1])) + "0"
print ("b"*50)
if float(temperature) < 35.5 or float(temperature) > 37.2:
print (do_data['班级'][i], do_data['姓名'][i], single_tem)
else:
print (do_data['班级'][i], do_data['姓名'][i], single_tem)
except:
print (do_data['班级'][i], do_data['姓名'][i], single_tem)
import pandas as pd
import numpy as np
from pandas import DataFrame,Series
import re
#导入数据
data1 = pd.read_excel("./data/每日一报.xlsx")
data2 = pd.read_excel("./data/i签到.xlsx")
time = input("数据导出时间:") #输入时间,目的是方便直接复制到群里
"""查找出没有完成每日一报签到的同学"""
noDo = data1[data1['是否完成填报'] == '未完成'] #提取出未打卡的同学
noDo_num = noDo.shape[0]
if noDo_num == 0:
print ("▼ 每日一报已全部打卡完毕!")
else:
print ("▼ 每日一报未打卡人数: %s(人)"%noDo_num) #打印出人数
for bj in range(len(noDo['班级'].unique())):
class_xinxi = noDo['班级'].unique()[bj]
index = noDo[noDo['班级'] == class_xinxi]
name_list = []
for name in index['姓名']:
name_list.append(name)
names = "、".join(name_list)
print (class_xinxi + ": "+ names +'\n')
print ("")
"""查找出没有完成i签到打卡的同学"""
noDo = data2[data2['签到状态'] == '未签到'] #提取出未签到的同学
noDo_num = noDo.shape[0]
if noDo_num == 0:
print ("◆ i签到已全部打卡完毕!")
else:
print ("◆ i签到未打卡人数: %s(人)"%noDo_num)
for bj in range(len(noDo['班级'].unique())):
class_xinxi = noDo['班级'].unique()[bj]
index = noDo[noDo['班级'] == class_xinxi]
name_list = []
for name in index['姓名']:
name_list.append(name)
names = "、".join(name_list)
print (class_xinxi + ": "+ names +'\n')
print ("\n☢以下同学“每日一报”打卡的信息可能有误☟☟☟")
"""查找出表格中的异常值"""
# 移除不必要的列
columns =['本人是否是疑似病例或确诊病例', '本人是否接触过疑似或确诊病例', '本人是否是湖北、武汉经历的人', '本人是否是确诊病例的密切接触者共同居住人员', '本人居住地是否是湖北省以外疫点人员(指生活的小区、单元楼发生确诊病例)', '家庭成员感染新冠状病毒情况', '是否有发热、咳嗽等症状']
do_data = data1[data1['是否完成填报'] == '已完成']
for col in columns:
mode = do_data[col].mode()[0] #众数
dif_do = do_data[do_data[col] != mode] #提取与众数不一样的值,也就是异常值
dif_do_num = dif_do.shape[0]
if dif_do_num == 0:
pass
else:
print ("●",col + ":",dif_do_num, "人")
for bj in range(len(dif_do['班级'].unique())): #班级去重dif_do['班级'].unique()
class_xinxi = dif_do['班级'].unique()[bj] #提取出班级
index = dif_do[dif_do['班级'] == class_xinxi]
name_list = []
for name in index['姓名']:
name_list.append(name)
names = "、".join(name_list)
print (class_xinxi + ": "+ names)
print ("")
"""找出没有填写具体体温的同学"""
temperature_tab = do_data['本人体温'] #体温列
for i in do_data.index:
temperature = re.sub("[^0-9\u4e00.]","", str(temperature_tab[i])) #体温清洗,只保留"数值"和“.”
if temperature == '':
print ("没有填写具体体温: ", do_data['班级'][i], do_data['姓名'][i], do_data['本人体温'][i])
"""找出体温不在35.5~37.2度之间的同学"""
print ("\n◙以下同学的体温不在35.5~37.2度之间")
for i in do_data.index:
temperature = re.sub("[^0-9\u4e00.]","", str(temperature_tab[i]))
if temperature == '':
continue #运行到这里后就结束程序当前运行,过滤掉没有数值的数据
single_tem = do_data['本人体温'][i] #遍历个人体温
# 为了预防学生填写的类型超过我的判断,设置一个异常捕捉
try:
if float(temperature) < 35.5 or float(temperature) > 37.2: #体温不在[3.5, 37.2]之间,进行下一步,初步判断异常
#如果体温中有“度”字,如:36度8,用“度”字进行分隔,分别去掉干扰因子,下一步拼接完整
if "度" in single_tem:
temperature = re.sub("[^0-9\u4e00.]","", str(single_tem.split('度')[0])) + "." + re.sub("[^0-9\u4e00.]","", str(single_tem.split('度')[1])) + "0"
print ("b"*50)
if float(temperature) < 35.5 or float(temperature) > 37.2:
print (do_data['班级'][i], do_data['姓名'][i], single_tem)#输出班级,姓名,体温
else:
print (do_data['班级'][i], do_data['姓名'][i], single_tem)
except:
print (do_data['班级'][i], do_data['姓名'][i], single_tem)
运行结果: 直接把它复制粘贴到通知群里就完事了☟☟☟
cpca官网: https://pypi.org/project/cpca/
cpca : chinese_province_city_area_mapper:一个用于识别简体中文字符串中省,市和区并能够进行映射,检验和简单绘图的python模块。
安装:目前只支持python3 pip install cpca
location_str = ["贵州省黔西南布依族苗族自治州贞丰县210省道", "湖南省岳阳市岳阳楼区对门山路", "贵州省遵义市余庆县方竹街", "贵州省黔南布依族苗族自治州都匀市75国道"]
import cpca
df = cpca.transform(location_str, cut=False)
df
省 | 市 | 区 | 地址 | |
---|---|---|---|---|
0 | 贵州省 | 黔西南布依族苗族自治州 | 贞丰县 | 黔西南布依族苗族自治州贞丰县210省道 |
1 | 湖南省 | 岳阳市 | 岳阳楼区 | 对门山路 |
2 | 贵州省 | 遵义市 | 余庆县 | 方竹街 |
3 | 贵州省 | 黔南布依族苗族自治州 | 都匀市 | 黔南布依族苗族自治州都匀市75国道 |
location_str = ["江苏省鼓楼区软件大道89号"]
import cpca
df = cpca.transform(location_str)
df
WARNING:root:鼓楼区 无法映射, 建议添加进umap中
省 | 市 | 区 | 地址 | |
---|---|---|---|---|
0 | 江苏省 | 鼓楼区 | 软件大道89号 |
在结果中,它没有把市映射出来,因为还有其他的地名和鼓楼区同名,江苏省徐州市也有一个鼓楼区:
import cpca
cpca.province_area_map.get_relational_addrs(('江苏省', '鼓楼区'))
[('江苏省', '南京市', '鼓楼区'), ('江苏省', '徐州市', '鼓楼区')]
location_str = ["江苏省鼓楼区软件大道89号"]
import cpca
df = cpca.transform(location_str, umap={"鼓楼区":"南京市"})
df
省 | 市 | 区 | 地址 | |
---|---|---|---|---|
0 | 江苏省 | 南京市 | 鼓楼区 | 软件大道89号 |
pip install folium
如我绘制《i签到》中 17级信息管理与信息系统班
班同学定位打卡的分布图:
(1)查看信息
xinguan = data2[data2['班级'] == '17信息管理与信息系统班'] #提取出17信息管理与信息系统班信息
print (xinguan.shape)
print (xinguan.columns)
(57, 9)
Index(['序号', '姓名', '学号', '学院', '班级', '签到状态', '签到时间', '地址', '备注'], dtype='object')
(2)绘图
import cpca #用于划分中国的省份
from cpca import drawer #用于画图
import folium #导入地图
from folium.plugins import HeatMap
loc = cpca.transform(xinguan['地址'], cut=False)#转化地点
drawer.draw_locations(loc, "./std_loc.html")#画出具体地点
图中显示:有两名同学打卡位置没有在贵州
贵州板块放大后:
pip install pyecharts
pip install echarts-countries-pypkg
pip install pyecharts-snapshot
绘制6个班的打卡位置:
import cpca #用于划分中国的省份库
from cpca import drawer#画中国地图库
processed = cpca.transform(data2['地址'], cut=False)#转化信管班地点
drawer.echarts_cate_draw(processed, processed["区"], "echarts_cates.html")#显示地理位置,区,并画图爆粗