最近在进行大创项目的结题工作,一开始的数据处理过程,是用C#处理的,想着最近在学python,就试了试用python做了下。下面来分享下我的处理流程,目前还处于初学阶段,有不足之处欢迎指点。
先看一下要处理的数据。
.
下面是具体20190101的站点数据,只列出了其中一部分。
两个文件夹分别 为19年和20年的全国气象站点数据,目标是要从这里面筛选出江苏省内的以及周边区域邻近的站点的PM2.5数据,并计算其月均值数据。我将要筛选的站点数据存储在了一个excel表格里,样式如下:(数据只截取了一小部分)
既然要筛选数据,那第一步就是将需要的站点编码读取出来。简单介绍下我的数据处理流程,读取目标站点,筛选天小时数据,计算日均值,计算月均值。
站点存储在excel文件里,因此要使用python来操作excel文件,这里我引用了openpyxl,下面是处理的代码(跳转至完整代码)
第一步导入openpyxl,
import openpyxl as xl
使用openpyxl库的load_workbook()来获得存储站点的excel文件
wb = xl.load_workbook(filename)
因为数据都是存储在工作簿的表里的,因此我们要获得工作簿里的表,也就是Sheet1,
sheet = wb['Sheet1']
在开始读数据前,先定义一个用于存储站点数据的列表,这里我定义的初始列表里有两个值,'date','hour',这两个值用来标识所读取的PM2.5的数据的生产时间。
station_id = ['date', 'hour']
下面是开始读数据,遍历sheet1的每一行,将数据存储在station_id里,
for row in range(2, sheet.max_row+1): cell = sheet.cell(row, 2) station_id.append(cell.value)
因为我这里存放目标站点编号的表格里存在多个空行,因此会station_id的后面会存放很多None(excel里的单元格为空的话就是None)
于是需要把station_id里的多余的None去除
if(None in station_id): index = station_id.index(None) del station_id[index:]
将上面的代码封装在一个函数里,完整代码如下:
import openpyxl as xl ''' 获得站点坐标,此处是以站点存储在excel里为例,并且是存放在一列,且是在第2列 ''' def get_station_id(filename): # 获得路径对应的工作簿 wb = xl.load_workbook(filename) # 获得工作簿里的表 sheet = wb['Sheet1'] # 定义一个存储站点的数据列表 station_id = ['date', 'hour'] # 遍历表,将站点信息存储在list里 for row in range(2, sheet.max_row+1): cell = sheet.cell(row, 2) station_id.append(cell.value) # 删除id_list中的空数据,因为有可能最大行数会超过excel的实际数据行数 if(None in station_id): index = station_id.index(None) del station_id[index:] return station_id
以上代码我单独放在了get_station_id.py文件里
简单说下处理流程,先是获得存放上面两个csv文件夹的文件夹,也叫父级路径,再获得文件夹下的所有csv文件(这一步要尽量保证没有其他csv文件),最后是遍历读取需要的数据并写入一个csv,存放着天小时的目标站点的PM2.5数据。(跳转至完整代码)
第一步,通过pathlib的Path来获得父级路径。导入pathlib 下的Path类,以及接下来要进行处理csv文件所需的csv库
from pathlib import Path import csv
获得存放csv文件夹的路径,并定义一个要存放数据的csv文件路径,
csv_dir = Path(r'F:\College\FileRecv\大创项目\站点数据201901-202012') target = r'F:\College\FileRecv\大创项目\19-20-hours.csv'
获得路径下的所有csv文件
csv_list = list(csv_dir.rglob('*.csv'))
定义一个写入流,做好写入数据的准备,这里用dictwriter的写入方法,是因为在要处理的数据文件中,有的站点在某一年或某几个月中并不存在,这样处理更为准确方便。
with open(target, 'w', newline='') as out_file: writer = csv.DictWriter(out_file, fieldnames=station_id)
接下来是写入列头,将station_id写入要存放数据的csv(target)的第一行:
writer.writeheader()
遍历读取站点csv文件,筛选数据写入target,
for filename in csv_list: with open(filename, 'r') as file: # 将行数据映射到字典 reader = csv.DictReader(file) for row in reader: # 判断当前数据是否是PM2.5 if row['type'] == datatype: # 查找对应station_id的数据,并存储在一个list里 # data = {} # for id in station_id: # if id in row: # data[id] = row[id] data = {id: row[id] for id in station_id if id in row} writer.writerow(data)
这一步数据处理成功,我将其封装在一个方法里,完整代码如下:
from pathlib import Path import csv import get_station_id # """ 获得指定站点编号的数据,并写入一个csv文件 输入的参数分别是 csv_dir----csv文件所在的目录的路径, 以及要写到目标文件的路径 target station_id 站点编号 """ def get_write_from_csv(csv_dir, target, station_id=['date', 'hour', '1141A'], datatype='PM2.5'): # 判断路径是否正确 if not csv_dir.is_dir(): return # 获得路径下所有的csv文件 csv_list = list(csv_dir.rglob('*.csv')) with open(target, 'w', newline='') as out_file: writer = csv.DictWriter(out_file, fieldnames=station_id) # 写入头,station_id writer.writeheader() # 遍历csv文件并选择数据写入target for filename in csv_list: with open(filename, 'r') as file: # 将行数据映射到字典 reader = csv.DictReader(file) for row in reader: # 判断当前数据是否是PM2.5 if row['type'] == datatype: # 查找对应station_id的数据,并存储在一个list里 # data = {} # for id in station_id: # if id in row: # data[id] = row[id] data = {id: row[id] for id in station_id if id in row} writer.writerow(data) print('successed') csv_dir = Path(r'F:\College\FileRecv\大创项目\站点数据201901-202012') target = r'F:\College\FileRecv\大创项目\19-20-hours.csv' # 存放着stationID的excel文件 filename = r'F:\College\FileRecv\大创项目\1920.xlsx' # 获得stationid station_id = get_station_id.get_station_id(filename) get_write_from_csv(csv_dir, target, station_id)
观察一下数据构成,发现可以通过date这一列进行分组来进行计算日均值。(跳转至完整代码)
谈到分组就想到了pandas的groupby函数,要得到日均值只要按date这列分组就行了,首先导入需要的库,
import pandas as pd import numpy as np
读取已筛选好的csv数据
df=pd.read_csv(r'F:\College\FileRecv\大创项目\target.csv')
将读取到的数据按date分组
day_group=df.groupby('date')
可以用下面的代码查看一下分组的结果,
for date,group in day_group: print(date) print(group)
接下来是对分组进行聚合求平均,并查看下聚合的结果
data=day_group.agg(np.mean) print(data)
发现hour这列也被求平均了,这一列在接下来的处理中是不需要的,因此将它删去。
day_data=data.drop('hour',axis='columns')
将删去后的数据写入daydata.csv(存储日均值数据)
day_data.to_csv('daydata.csv')
完整代码如下:
import pandas as pd import numpy as np df=pd.read_csv(r'F:\College\FileRecv\大创项目\target.csv') day_group=df.groupby('date') data=day_group.agg(np.mean) day_data=data.drop('hour',axis='columns') day_data.to_csv('daydata.csv')
对处理好的日均值数据来求月均值,首先是要将数据按月来归类,简单讲下我的思路,首先将数据按年分开分为19年和20年的数据。再对19和20年的数据按月分类聚合求均值。(跳转至完整代码)
第一步,按年分割数据,
df=pd.read_csv('daydata.csv') # 年份区开数据 data2019=df[df['date']<=20191231] data2020=df[df['date']>=20200101]
第二步,对各年的按月分类聚合求均值。考虑到date这列的数据类型是数字,可以通过按条件筛选属于某一月的数据,
def get_month_data(data,month_start,month_end): month=data[(data['date']<month_end)&(data['date']>=month_start)] # 这里聚合操作也将日期进行聚合了 return month.agg(np.mean)
第三步,获得某年的月均值数据,并写入csv文件。考虑到0101到0201之间差了100,(实际上两个月之间最多只差31天)设置了步长为100的形式来获得月均值,
def write_month_data(year_data,outfilename,month_start=20190101,step=100): month_list=[] # 获得每月均值数据,并添加到list里 for num in range(12): month_data=get_month_data(year_data,month_start,month_start+step) month_list.append(month_data) month_start+=step # 将list生成dataframe df=pd.DataFrame(month_list) # 修改日期格式为201901这种年加月形式 df['date']=df['date'].apply(lambda x: int(x/100)) df.to_csv(outfilename)
下面是完整的代码
import pandas as pd import numpy as np df=pd.read_csv('daydata.csv') # 年份区开数据 data2019=df[df['date']<=20191231] data2020=df[df['date']>=20200101] # data2020.agg(np.mean) def get_month_data(data,month_start,month_end): month=data[(data['date']<month_end)&(data['date']>=month_start)] # 这里聚合操作也将日期进行聚合了 return month.agg(np.mean) def write_month_data(year_data,outfilename,month_start=20190101,step=100): month_list=[] # 获得每月均值数据,并添加到list里 for num in range(12): month_data=get_month_data(year_data,month_start,month_start+step) month_list.append(month_data) month_start+=step # 将list生成dataframe df=pd.DataFrame(month_list) # 修改日期格式为201901这种年加月形式 df['date']=df['date'].apply(lambda x: int(x/100)) df.to_csv(outfilename) month_start2019=20190101 month_start2020=20200101 step=100 #因为20190101-20190201=-100 write_month_data(data2019,'19month.csv',month_start2019,step) write_month_data(data2020,'20month.csv',month_start2020,step)
结果图:
结语:以上就是我使用python处理数据的全流程了,作为一个python新手,如有错误还请指点,感谢大家花费宝贵的时间来阅读。