一、思路
背景
EXCEL 表格中有每天大家到场的记录,每页格式相同,包含人名、日期和是否到场参加(也可线上)。如下:
思路
目标:统计每个人来了几次(进阶一点的话,包括线下线上)。
思路:(字典,pandas)
- 为了统计每个人来了几次。那就准备好一个字典,key是人名,value是次数。重名算同一个人;
- pandas 循环读取 EXCEL 文件中的每一页,得到一个包含“名字”,“次数”的二维列表;
- 把这个二维表中的数按人名统计到之前的字典中。
把 EXCEL 表格中的数据,按名字加一加个数,放到字典中
注意点:
-
字典的操作: 当统计一个名字出现的次数时,需要先读取字典中的值,再写回去。
aud_count = Name_Dict.get(aud_name, 0) Name_Dict[aud_name] = aud_count + 1
字典的排序,既可以根据 key 值排,也可以根据 value 值排。
#根据名字首字符排序 #Name_Dict_S = sorted(Name_Dict.items(), key=lambda x: x[0]) #根据次数排序 Name_Dict_S = sorted(Name_Dict.items(), key=lambda x: x[1])
-
EXCEL的读取: 我用的是 Pandas 的 pd.read_excel() 函数来读取,里面各个参数如何使用这里不细讲。我只稍微指定了一下数据类型方便后续处理,其中日期的读取需要稍微钻研下。另外,数据源需要做好清洗,去除错乱值,避免函数报错。 同时我使用了 mask 方法来过滤数据,区分线下线上。
mask = Name_df[‘onsite’] == True Name_df_onsite = Name_df[(mask)]
-
人名的处理: 正则表达式 匹配出名字。如果是是中文的,直接匹配。如是英文的,中间会有大小写,空格。先把人名变成小写字母,再用正则表达式匹配出英文名字,这里多试试。
name_low = name.lower() ret = re.search("([a-z]+\s{0,2}.?)+[a-z]+",name_l)
二、程序
导入 pandas 和 正则匹配模块。
import pandas as pd
import re
attendence_sum = 0
onsite_sum = 0
定义一个主函数,主函数中遍历每一页。从每一页得到一个名字列表,把每一名字和总的字典的名字作比较,有一样的就加1,说明这个人又参加了一次。遍历完了所有页就得到了每个名字出现的次数。
然后,按名字或次数排个序。
最后,按次数统计人名个数。即1次的几人,2次的几人,3次的几人,等等。
def main():
file_path = r'C:\Auto Test\Auto_Name_Statistic\data\Name_Static.xlsx'
pages = 18
print('===================== 每场统计结果:')
Name_Dict = {}
for i in range(pages):
Name_Record = get_DF_from_file(i, file_path)
lenth = Name_Record['name'].count()
for j in range(lenth):
aud_name = format_name(Name_Record['name'][j])
aud_count = Name_Dict.get(aud_name, 0)
Name_Dict[aud_name] = aud_count + 1
sort_name(Name_Dict)
static_audiance_attend_count(pages, Name_Dict)
用到了Pandas 去读取 Excel 文件,按每个 sheet 页读取,并统计这一页的人数
def get_DF_from_file(sheet_i, file_path):
Name_df = pd.read_excel(file_path,
sheet_name=sheet_i, index_col=None,
dtype={'name': 'string', 'onsite': 'bool'},
parse_dates=["date"],
)
global attendence_sum, onsite_sum
attendence_count = Name_df.shape[0]
attendence_sum += attendence_count
mask = Name_df['onsite'] == True
Name_df_onsite = Name_df[(mask)]
onsite_count = Name_df_onsite.shape[0]
onsite_sum += onsite_count
date_Tstamp = Name_df.iloc[1, 1]
date_str = date_Tstamp._date_repr
print('场次:', (sheet_i+1), ' - ', date_str, ' 参与人数: ',
attendence_count, ' Onsite 人数:', onsite_count)
return Name_df
正则匹配英文人名
def format_name(name):
name_low = name.lower()
ret = re.search("([a-z]+\s{0,2}\.?)+[a-z]+", name_low)
if ret:
aud_name = ret.group()
else:
print("debug -- ", name_low, ", resul ----------------- error")
aud_name = 'error'
return aud_name
字典排序
def sort_name(Name_Dict):
Name_Dict_S = sorted(Name_Dict.items(), key=lambda x: x[1])
print('===================== 排序后统计结果:')
for na in Name_Dict_S:
print(na[0], ' : ', na[1])
再创建一个空字典,key 值是次数,value 值是人数。这个函数有点儿绕~
def static_audiance_attend_count(pages, Name_Dict):
CountAdu_Dict = {}
for name, count in Name_Dict.items():
aud_amount = CountAdu_Dict.get(count, 0)
CountAdu_Dict[count] = aud_amount + 1
print("===================== 分次统计人数:")
CountAdu_Dict_S = sorted(CountAdu_Dict.items(), key=lambda x: x[0])
for item in CountAdu_Dict_S:
print(item[0], '次: ', item[1], ' 人')
|