实习中的第二次实战,相比于第一次处理数据,这一次我更清晰地划分了函数功能,使得开发过程比第一次更快速了(比上次快了半天),尽管还是花了一天半(捂脸)。
第一次实战总结
文件夹中的excel文件,格式如下:
蝇类监测记录表(笼诱法) | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
调查日期:2030 年 4 月 | |||||||||||||||
调查地点: YY 省(自治区、直辖市) XX 地(市) ZZZ 县(区) | |||||||||||||||
气温: 12.0 ℃; 风力: 3 级; 天气:晴√ 多云□ 阴□ | |||||||||||||||
诱饵种类:规定诱饵√; 其他□: | |||||||||||||||
序号 | 乡镇(街道) | 日期 | 环境类型 | 监测地点 | 布笼数 | 苍蝇品种1 | 苍蝇品种2 | 苍蝇品种3 | 苍蝇品种4 | …… | 苍蝇品种10 | 其他 | 合计 | 蝇种列合计 | 备注 |
1 | a村 | 1.29 | 农贸市场 | 第一百菜市场 | 1 | 1 | …… | 1 | 1 | ||||||
2 | a村 | 1.29 | 居民区 | 第90中学宿舍 | 1 | …… | 0 | 0 | |||||||
3 | a村 | 1.29 | 绿化带 | 自然生态公园 | 1 | …… | 0 | 0 | |||||||
…… | …… | ||||||||||||||
8 | a村 | 1.29 | 餐饮外环境 | 最好吃餐厅 | 1 | 0 | …… | 0 | 0 | ||||||
9 | …… | ||||||||||||||
10 | …… | ||||||||||||||
11 | …… | ||||||||||||||
…… | …… | ||||||||||||||
填报单位: zz区天气预报中心 填报人: Sky 审核人:John |
调查日期 | 调查地点 | 环境类型 | 诱饵 | 监测地点 | 苍蝇品种1 | 苍蝇品种2 | 苍蝇品种3 | 苍蝇品种4 | …… | 苍蝇品种10 | 苍蝇品种11 | 苍蝇品种12 | 其他 | 经度 | 纬度 | 气温(℃) | 风力(级) | 天气 | 笼编号 | 监测单位 | 监测人 | 审核人 | 备注 |
2016/1/7 | 福建省福州市闽侯区aa街道(乡镇) | 餐饮区外环境 | 规定诱饵 | 最好吃餐厅 | 0 | 0 | 0 | 0 | …… | 0 | 0 | 0 | 0 | 20 | 1 | 晴 | 有或空 | xx中心 | Sky | John | |||
2016/2/31 | 福建省福州市福州大学区bb街道(乡镇) | 绿化带 | 规定诱饵 | 沧海公园 | 0 | 0 | 0 | 0 | …… | 0 | 0 | 0 | 0 | 20 | 1 | 晴 | 有或空 | xx中心 | Sky | John | |||
2016/3/2 | 福建省福州市鼓楼区uu街道(乡镇) | 农贸市场 | 规定诱饵 | 第一市场 | 0 | 0 | 0 | 0 | …… | 0 | 0 | 0 | 0 | 20 | 1 | 晴 | 有或空 | xx中心 | Sky | John | |||
…… | …… | ||||||||||||||||||||||
年-月-日 | xx省yy市zz区aa街道(乡镇) | 餐饮区外环境 | 规定诱饵 | 最好吃餐厅 | 0 | 0 | 0 | 0 | …… | 0 | 0 | 0 | 0 | 20 | 1 | 晴 | 有或空 | xx中心 | Sky | John |
第一行是表头(无实际意义)
第二行是调查日期,其实可以使用正则表达式提取年份和月份,但我直接从文件名种提取了,所以这一行对我也没有用。
第三行是调查地点,在这行需要提取省(自治区、直辖市),地(市)和县(区)
第四行需要提取气温,风力和天气
第五行需要提取诱饵种类
第7行-第8行的每一列都需要提取,不论有信息还是NaN
第9行-倒数第2行为空,需要跳过
最后一行需要提取填报单位,填报人和审核人
比第一次实战总结做出了改进,使用了os.path.join和file.endswith这两个函数
def get_file_name(base_path): # base_path是最基本的文件夹绝对路径
file_collection = []
for dir, subDir, files in os.walk(base_path):
# print(dir,'\t', subDir,'\t', files)
for file in files:
in_path = os.path.join(dir, file) # 替换 in_path = dir + '/' + file
if file.endswith('xlsx') or file.endswith('xls'): # 筛选后缀为.xlsx和.xls的文件
file_collection.append(in_path)
return file_collection
从文件名中提取年和月,file是文件名(叫file_name更好)
def get_year_month(file):
ym = re.findall(r'([0-9]{4}\.?[0-9]{2})', file) #文件名是包含yyyy.mm或yyyymm的格式
if ym[0][4] == '.': # 去掉小数点
ym[0] = ym[0][:4] + ym[0][5:]
ym[0] = ym[0][:4] + '-' + ym[0][4:] #将格式转为yyyy-mm
return ym[0]
value是Input表格中日期列的值,是小数;ym是get_year_month(file)提取的年月,格式为yyyy-mm
def set_df_date(value, ym):
string = str(value) # 将小数强转为str
date = string[string.find('.') + 1:] # 找到日
date = ym + '-' + date # 将年月和日结合形成时间:yyyy-mm-dd
return date
file_name为传入的文件名,sheet_name为sheet名,col_names是行数,即从第几行开始是表头(所有列的列名)
def get_sheet_df(file_name, sheet_name, col_names):
work_book = xlrd.open_workbook(file_name) # 打开excel文件
sheet = work_book.sheet_by_name(sheet_name) # 根据sheet_name找sheet
# print(sheet.row_values(col_names)[0])
df = pd.DataFrame([], columns=sheet.row_values(col_names)) # 根据列名建一个空的DataFrame
for i in range(col_names + 1, sheet.nrows):
if sheet.cell_value(i, 1) is '': # excel中的空单元格数据为空字符串,也就是''
break
df.loc[i] = sheet.row_values(i)
df.drop(['合计', '蝇种列合计', '布笼数'], axis=1, inplace=True) # 丢掉没用的列,axis=1代表[row,col]的col
df.replace('', 0, inplace=True)
df.reset_index(drop=True, inplace=True) # 重设索引,drop=True表示丢掉原本的索引
# print(df)
# 使用不同的函数得到每一列的准确数据
invs_place = set_invs_place(sheet)
temp, wind, weather = get_temp_wind_weather(sheet) # temp为temperature缩写
bait_type = get_bait_type(sheet)
unit, reporter, people_in_charge = get_unit_Reporter_PeopleInCharge(sheet)
date = set_df_date(df.loc[0, '日期'], get_year_month(file_name)) # df.loc[0,'日期']因为同一个表格同一天的日期都是一样的,所以可以直接取一个点
# 赋值与调整值
for i in range(df.shape[0]):
df.loc[i, '乡镇(街道)'] = invs_place + df.loc[i, '乡镇(街道)'] + '乡镇(街道)'
df.loc[i, '气温(℃)*'] = temp
df.loc[i, '风力(级)*'] = wind
df.loc[i, '天气*'] = weather
df.loc[i, '诱饵*'] = bait_type
df.loc[i, '监测单位*'] = unit
df.loc[i, '监测人*'] = reporter
df.loc[i, '审核人'] = people_in_charge
df.loc[i, '日期'] = date
if df.loc[i, '环境类型'] == '餐饮外环境':
df.loc[i, '环境类型'] = '餐饮区外环境'
df.rename(columns={
'序号': '笼编号', '日期': '调查日期*', '乡镇(街道)': '调查地点*'}, inplace=True) # 重命名列名
# 补充新空列
df[['经度', '纬度', '棕尾别麻蝇*', '瘦叶带绿蝇*']] = df.apply(lambda x: ('', '', '', ''), axis=1, result_type='expand')
# 调整列的位置
df = adjust_columns_position(df)
return df
因为列的顺序有变换,所以这里手动调整位置(不懂有没有更好的方法)
补充:DataFrame调整列顺序有两个常见方法:
df.columns = ['aa','bb','cc']
def adjust_columns_position(df):
df_time, df_no, df_bz, df_bait, df_jd, df_wd, df_sy, df_zy = \
df['调查日期*'], df['笼编号'], df['备注'], df['诱饵*'], df['经度'], df['纬度'], df['瘦叶带绿蝇*'], df['棕尾别麻蝇*']
df.drop(['调查日期*', '笼编号', '备注', '诱饵*', '经度', '纬度', '棕尾别麻蝇*', '瘦叶带绿蝇*'], axis=1, inplace=True)
df.insert(0, '调查日期*', df_time)
df.insert(3, '诱饵*', df_bait)
df.insert(18, '棕尾别麻蝇*', df_zy)
df.insert(20, '瘦叶带绿蝇*', df_sy)
df.insert(22, '经度', df_jd)
df.insert(23, '纬度', df_wd)
df.insert(27, '笼编号', df_no)
df.insert(31, '备注', df_bz)
return df
第三行是调查地点,本来是要根据正则表达式提取结果,但是有的表格没有填写省市,为了方便起见遂直接定义省市,且已知区县,其实这边更好的处理是如果有就返回正确值,没有就返回空,之后会进行改进。
正则表达式零宽断言的用法:
(?<=expression):表示匹配expression之后的值
(?=expression):表示匹配expression之前的值
这边结合两者,就可以直接提取值了
[\u4e00-\u9fa5]:只匹配汉字
\s:匹配空格,tab等
之后的几个函数都有用到这边列举的思想
def set_invs_place(sheet):
total = re.findall(r'(?<=\s)[\u4e00-\u9fa5]+(?=\s)', sheet.row_values(2)[0]) # 第三行是调查地点
base_place = '福建省福州市'
for value in total:
if value == '闽侯' or value == '鼓楼':
return base_place + value + '区'
\d:匹配数字
.:匹配小数点,注意和.区分,没有转义的小数点什么都能匹配
def get_temp_wind_weather(sheet):
temp_wind = re.findall(r'(?<=[\s:])[\d\.]+(?=[\s℃])', sheet.row_values(3)[0]) # 第四行是气温,风力,天气
weather = re.findall(r'(?<=[(天气:)\s])[\u4e00-\u9fa5]+(?=[√☑])', sheet.row_values(3)[0])
# print(temp_wind)
# print(weather)
return temp_wind[0], temp_wind[1], weather
def get_bait_type(sheet):
bait_type = re.findall(r'(?<=诱饵种类:)[\u4e00-\u9fa5]+(?=[√□☑])', sheet.row_values(4)[0]) # 第五行是诱饵种类
# print(bait_type)
return bait_type
def get_unit_Reporter_PeopleInCharge(sheet):
total = re.findall(r'(?<=\s)[\u4e00-\u9fa5a-z]+(?=\s)', sheet.row_values(56)[0]) # 第五十七行是填报单位,填报人,审核人
# [\u4e00-\u9fa5]代表只匹配汉字
# print(total)
if len(total) == 3: ## 有的没有审核人,所以len可能是2或3
return total[0], total[1], total[2]
elif len(total) == 2:
return total[0], total[1], None
def save_file(df, path, region):
df.to_csv(path + '\\' + region + '汇总.csv', encoding='gbk', index=False) # 保存为csv
import os
import re
import pandas as pd
import numpy as np
import xlrd
def get_file_name(base_path): # 第一篇实战同款函数,但进行了大升级
file_collection = []
for dir, subDir, files in os.walk(base_path):
# print(dir,'\t', subDir,'\t', files)
for file in files:
in_path = os.path.join(dir, file) # 替换 in_path = dir + '/' + file
if file.endswith('xlsx') or file.endswith('xls'): # 筛选后缀为.xlsx和.xls的文件
file_collection.append(in_path)
return file_collection
def get_year_month(file):
ym = re.findall(r'([0-9]{4}\.?[0-9]{2})', file)
if ym[0][4] == '.': # 去掉.
ym[0] = ym[0][:4] + ym[0][5:]
ym[0] = ym[0][:4] + '-' + ym[0][4:]
# for v in ym_total:
# print(v)
return ym[0]
def set_df_date(value, ym):
string = str(value)
date = string[string.find('.') + 1:] # 找到日
date = ym + '-' + date # 将年月和日结合形成时间
return date
def get_sheet_df(file_name, sheet_name, col_names):
work_book = xlrd.open_workbook(file_name)
sheet = work_book.sheet_by_name(sheet_name)
# print(sheet.row_values(col_names)[0])
df = pd.DataFrame([], columns=sheet.row_values(col_names))
for i in range(col_names + 1, sheet.nrows):
if sheet.cell_value(i, 1) is '': # excel中的空单元格数据为空字符串,也就是''
break
df.loc[i] = sheet.row_values(i)
df.drop(['合计', '蝇种列合计', '布笼数'], axis=1, inplace=True) # 丢掉没用的列,axis=1代表[row,col]的col
df.replace('', 0, inplace=True)
df.reset_index(drop=True, inplace=True) # 重设索引,drop=True表示丢掉原本的索引
# print(df)
# 得到每一列的准确数据
invs_place = set_invs_place(sheet)
temp, wind, weather = get_temp_wind_weather(sheet)
bait_type = get_bait_type(sheet)
unit, reporter, people_in_charge = get_unit_Reporter_PeopleInCharge(sheet)
date = set_df_date(df.loc[0, '日期'], get_year_month(file_name)) # df.loc[0,'日期']因为同一个表格同一天的日期都是一样的,所以可以直接取一个点
# 赋值与调整值
for i in range(df.shape[0]):
df.loc[i, '乡镇(街道)'] = invs_place + df.loc[i, '乡镇(街道)'] + '乡镇(街道)'
df.loc[i, '气温(℃)*'] = temp
df.loc[i, '风力(级)*'] = wind
df.loc[i, '天气*'] = weather
df.loc[i, '诱饵*'] = bait_type
df.loc[i, '监测单位*'] = unit
df.loc[i, '监测人*'] = reporter
df.loc[i, '审核人'] = people_in_charge
df.loc[i, '日期'] = date
if df.loc[i, '环境类型'] == '餐饮外环境':
df.loc[i, '环境类型'] = '餐饮区外环境'
df.rename(columns={
'序号': '笼编号', '日期': '调查日期*', '乡镇(街道)': '调查地点*'}, inplace=True)
# 补充新空列
df[['经度', '纬度', '棕蝇*', '绿蝇*']] = df.apply(lambda x: ('', '', '', ''), axis=1, result_type='expand')
# 调整列的位置
df = adjust_columns_position(df)
return df
def adjust_columns_position(df):
df_time, df_no, df_bz, df_bait, df_jd, df_wd, df_sy, df_zy = \
df['调查日期*'], df['笼编号'], df['备注'], df['诱饵*'], df['经度'], df['纬度'], df['绿蝇*'], df['棕蝇*']
df.drop(['调查日期*', '笼编号', '备注', '诱饵*', '经度', '纬度', '棕蝇*', '绿蝇*'], axis=1, inplace=True)
df.insert(0, '调查日期*', df_time)
df.insert(3, '诱饵*', df_bait)
df.insert(18, '棕蝇*', df_zy)
df.insert(20, '绿蝇*', df_sy)
df.insert(22, '经度', df_jd)
df.insert(23, '纬度', df_wd)
df.insert(27, '笼编号', df_no)
df.insert(31, '备注', df_bz)
return df
def set_invs_place(sheet):
total = re.findall(r'(?<=\s)[\u4e00-\u9fa5]+(?=\s)', sheet.row_values(2)[0]) # 第三行是调查地点
base_place = '福建省福州市'
for value in total:
if value == '鼓楼' or value == '闽侯':
return base_place + value + '区'
def get_temp_wind_weather(sheet):
temp_wind = re.findall(r'(?<=[\s:])[\d\.]+(?=[\s℃])', sheet.row_values(3)[0]) # 第四行是气温,风力,天气
weather = re.findall(r'(?<=[(天气:)\s])[\u4e00-\u9fa5]+(?=[√☑])', sheet.row_values(3)[0])
# print(temp_wind)
# print(weather)
return temp_wind[0], temp_wind[1], weather
def get_bait_type(sheet):
bait_type = re.findall(r'(?<=诱饵种类:)[\u4e00-\u9fa5]+(?=[√□☑])', sheet.row_values(4)[0]) # 第五行是诱饵种类
# print(bait_type)
return bait_type
def get_unit_Reporter_PeopleInCharge(sheet):
total = re.findall(r'(?<=\s)[\u4e00-\u9fa5a-z]+(?=\s)', sheet.row_values(56)[0]) # 第五十七行是填报单位,填报人,审核人
# [\u4e00-\u9fa5]代表只匹配汉字
# print(total)
if len(total) == 3:
return total[0], total[1], total[2]
elif len(total) == 2:
return total[0], total[1], None
def save_file(df, path, region):
df.to_csv(path + '\\' + region + '汇总.csv', encoding='gbk', index=False) # 保存为csv
if __name__ == '__main__':
base_path = r'E:\蝇密度汇总\2018-2020蝇密度'
file_collection = get_file_name(base_path)
df = [pd.DataFrame([]) for _ in range(2)]
for i, file in enumerate(file_collection):
print(i, ' ', file)
for i, file in enumerate(file_collection):
# print(file)
if i < 12 or i >= 24 and i < 33:
df[0] = df[0].append(get_sheet_df(file_name=file, sheet_name='县区1', col_names=5))
else:
df[1] = df[1].append(get_sheet_df(file_name=file, sheet_name='县区2', col_names=5))
print(df[0])
print(df[1])
regions = ['鼓楼区', '闽侯区']
for i in range(2):
save_file(df=df[i], path=base_path, region=regions[i])