文章目录
【任务一】显卡日志
下面给出了3090显卡的性能测评日志结果,每一条日志有如下结构:
Benchmarking #2# #4# precision type #1#
#1# model average #2# time : #3# ms
其中#1#代表的是模型名称,#2#的值为train(ing)或inference,表示训练状态或推断状态,#3#表示耗时,#4#表示精度,其中包含了float, half, double三种类型,下面是一个具体的例子:
Benchmarking Inference float precision type resnet50
resnet50 model average inference time : 13.426570892333984 ms
请把日志结果进行整理,变换成如下状态,model_i用相应模型名称填充,按照字母顺序排序,数值保留三位小数:
解决思路
1.文本数据正则抽取,去缺失值,列重命名,重置index
根据数据特点,可以看出需要统计的数据都是一个格式,首先使用正则表达式抽取需要的第一行和第二行信息,并将抽取的信息重命名。这里也可以直接使用子组的命名达到重命名列的效果,下面演示的是第一种方法:
df=pd.read_table('data/benchmark.txt', header=None)
pat1='Benchmarking (\w+) (\w+) precision type (\w+)'
pat2='(\w+) model average (\w+) time : (.+) ms'
bench_info=df[0].str.extract(pat1).rename(columns={0:'type_x',
1:'precision',
2:'model_name_x'}).dropna()
.reset_index(drop=True)
使用子组的方法重命名列名:
df=pd.read_table('data/benchmark.txt', header=None)
pat1='Benchmarking (?P<type_x>\w+) (?P<precision>\w+) precision type (?P<model_name_x>\w+)'
pat2='(?P<model_name_y>\w+) model average (?P<type_y>\w+) time : (?P<time_val>.+) ms'
bench_info=df[0].str.extract(pat1).dropna()
.reset_index(drop=True)
bench_info
下面是对应的第一行信息,去掉了缺失值,以及重置了index,命名为bench_info:
类似地可以得到每个模型地第二个行信心,同样处理,命名为model_info,可以看到这里获取地两个信息数量相同,是一一对应的:
model_info=df[0].str.extract(pat2).rename(
columns={0:'model_name_y',
1:'type_y',2:'time_val'}).dropna()
.reset_index(drop=True)
2.横向连接两表-concat
将两个表合并成一个表:
temp=pd.concat([bench_info,model_info],axis=1).reset_index(
drop=True)
temp
注意这里不能用merge或者merge_table,merge是因为不唯一,merge_table用了的话会有很多重复数据。这里之前花了很多时间定位问题。
3.去除重复列,精度保留三位小数
temp=temp[['model_name_x','type_y','precision',
'time_val']].rename(columns={'model_name_x':'model','type_y':'type'})
temp.time_val=pd.to_numeric(temp.time_val,
errors='coerce').round(3)
temp
4.表的变型 长变宽pivot
长表变宽表,使用pivot
#变型 长变宽
temp=temp.pivot(index=['model','type'],
columns='precision', values='time_val')
temp
5.索引变型及多级索引的压缩
下面使用unstack,将最里面一层index进行行列转换:
temp=temp.unstack()
temp.head()
使用map函数对多级index进行组合变型:
temp.columns=temp.columns.map(lambda x:(x[1]+'_'+x[0]))
temp=temp.reset_index()
temp.head()
6.调整,按模型名称排序
最后进行行和列的重新排序以达到最好的显示效果,这里对列试了一下sort_index,但是model列会被放到中间,最终还是选择了最基础的方法。对行以模型名称按照字母顺序排序:
# temp.sort_index(axis=1,ascending=False)
temp=temp[['model','train_half','train_float',
'train_double','inference_half',
'inference_float','inference_double']]
temp=temp.sort_values('model',ascending=True)
temp.head()
【任务二】水压站点的特征工程
df1和df2中分别给出了18年和19年各个站点的数据,其中列中的H0至H23分别代表当天0点至23点;df3中记录了18-19年的每日该地区的天气情况,请完成如下的任务:
import pandas as pd
import numpy as np
df1 = pd.read_csv('yali18.csv')
df2 = pd.read_csv('yali19.csv')
df3 = pd.read_csv('qx1819.csv')
问题1:
- 通过df1和df2构造df,把时间设为索引,第一列为站点编号,第二列为对应时刻的压力大小,排列方式如下(压力数值请用正确的值替换):
站点 压力
2018-01-01 00:00:00 1 1.0
2018-01-01 00:00:00 2 1.0
... ... ...
2018-01-01 00:00:00 30 1.0
2018-01-01 01:00:00 1 1.0
2018-01-01 01:00:00 2 1.0
... ... ...
2019-12-31 23:00:00 30 1.0
解决思路
原表样式 df2为19年水站数据,
df118年数据,与之类似:
1.表变型 宽表变长表-melt
#宽表变长表
H_list=['H'+str(i) for i in range(12)]
df1=df1.melt(id_vars =['Time','MeasName'],
value_vars =H_list,var_name = 'H',
value_name = '压力')
df1
这里后来检查的时候发现最终少了一半数据,定位问题发现是这里时间H0-H23一共24h,我给写成了12个小时,修改后:
#宽表变长表
H_list=['H'+str(i) for i in range(24)]
df1=df1.melt(id_vars =['Time','MeasName'],
value_vars =H_list,var_name = 'H',
value_name = '压力')
df1
2.修改格式-文本正则,时间格式化
# 修改对应格式 str正则
df1.MeasName=df1.MeasName.str.replace('站点','')
df1.H=df1.H.str.replace('H','')
df1.Time=df1.Time+'-'+df1.H
df1.Time=pd.to_datetime(df1.Time,format='%Y-%m-%d-%H')
df1=df1.rename(columns={'MeasName':'站点'}).drop(columns='H')
df1
3.设置时间为index
df1=df1.rename(columns={'Time':' '}).set_index(' ')
df1
df2按照完全一致的方式处理,处理后样式:
4.纵向合并两个表 concat
df=pd.concat([df1,df2],axis=0)
df
问题2:
表3为当天的天气情况:
- 在上一问构造的df基础上,构造下面的特征序列或DataFrame,并把它们逐个拼接到df的右侧
- 当天最高温、最低温和它们的温差
解决思路
1.取df的时间年月日构成date列
df['date']=df.index.astype('str').str[0:10]
df
这里数据应该是52万5千6百行,少一半的原因上面已经说了,是因为匹配的时候只匹配了H0-H11,之后的操作应该都没问题,所以就不改了。
2.正则表达式获取最高温和最低温
df3 = pd.read_csv('./data/qx1819.csv')
pat_temp='(.?\d+).{0,2}~\s{0,2}(.?\d+).?'
df3_temp=df3['气温'].str.extract(pat_temp).rename(columns={0:'最高温',1:'最低温'})
df3=pd.concat([df3,df3_temp],axis=1)
df3
这里可以使用isna()函数查看是否有没用匹配到的,可以用来检查正则规则是否合适,以及数据是否正常,这里我都花了些功夫修改正则表达式:
df3[df3['最高温'].isna()]
发现有两天数据只有一个值,我暂时把他丢弃。
df3=df3.dropna()
df3['温差']=df3['最高温'].astype('int')-df3['最低温'].astype('int')
df3
3.获取温差
df3.loc[df3['温差']<0]
有一天数据不符和左边下右边大的规则,可以修改下。
4.关系连接 merge
将处理好的df和含有温度信息的df3通过日期相连,这里两个日期的列名不同,需要手动指定。
注意保存df的index,如果不保存,连接后会形成新的index,原有的时间信息会丢失。
res1=df3[['日期','最高温','最低温','温差']]
df_index=df.index
df=df.merge(res1,left_on='date',right_on='日期',how='left').drop('date',1)
df.index=df_index
df
最终结果:
问题3:
当天是否有沙暴、是否有雾、是否有雨、是否有雪、是否为晴天
解决思路
1.contains
先看下有沙暴的
df3 = pd.read_csv('./data/qx1819.csv')
df3.loc[df3['天气'].str.contains('沙')]
设置新列记录雨雪雾
df3 = pd.read_csv('./data/qx1819.csv')
df3['沙暴']=df3['天气'].str.contains('沙').astype(int)
df3['有雾']=df3['天气'].str.contains('雾').astype(int)
df3['有雨']=df3['天气'].str.contains('雨').astype(int)
df3['有雪']=df3['天气'].str.contains('雪').astype(int)
df3
2.match+$
对于晴天不能用contains,因为这样会把阴转晴等也算在晴天
我妈可以使用match的方法,不过记得要匹配结尾,否则晴转多云等也会被匹配进去:
df3.loc[df3['天气'].str.match('晴$')]
注意这里endwith(‘晴’)也不行,会匹配多云转晴
df3['晴']=df3['天气'].str.match('晴$').astype(int)
df3
问题4:
选择一种合适的方法度量雨量/下雪量的大小(构造两个序列分别表示二者大小)
解决思路:
1.cat+contains获取所有含雨的天气类型
weather_type=df3['天气'].astype('category').cat.categories
rain_type=weather_type[rian_type.str.contains('雨')].tolist()
rain_type
一共42种,这里展示部分:
2.zip组成雨类型的字典
index1=[i for i in range(len(rain_type)) ]
rain_dict=dict(zip(rain_type, index1))
rain_dict
3.天气匹配下雨等级字典表
匹配不到的这里我用了异常捕获,填入变成缺失值
weather=df3['天气'].tolist()
rain=[]
for wea in weather:
try:
rain.append(rain_dict[wea])
except:
rain.append(np.NaN)
df3['下雨等级']=rain
df3
看下下雨等级非缺失值的那些:
df3.loc[df3['下雨等级'].notna()]
下雪等级情况完全一致,这里不再赘述
问题5:
限制只用4列,对风向进行0-1编码(只考虑风向,不考虑大小)
解决思路:
1.contains
这里题意也没完全弄懂,我按照自己的理解及出题人的回复就使用了最简单的做法,即当前风向中出现对应方向的风就将该列置为1,完成01编码,类似于one-hot向量,比如东北风转南风,出现了东、北、南,即东南西北四列分别为1101。
df3 = pd.read_csv('./data/qx1819.csv')
# pat_wind_dire='([东南西北]{1,2})风.([东南西北]{1,2})风|([东南西北]{1,2})风'
df3['东风']=df3['风向'].str.contains('东').astype(int)
df3['西风']=df3['风向'].str.contains('西').astype(int)
df3['南风']=df3['风向'].str.contains('南').astype(int)
df3['北风']=df3['风向'].str.contains('北').astype(int)
df3
其他思路:
群里小伙伴提供了另一种思路,不过由于时间原因无法继续实验:
就是先识别风向,然后对风向进行编码,最后对状态进行数据表示。 我的理解是,
识别风向:只有东西南北,以及东北、东南、西北、西南8种风向,先用extract提取 风向编码:可以用000-111编码
状态表示:感觉最后只需要两列,state1,state2,比如北风,应为000 NAN;东北风转北风 应为 101 000
剩余练习
对df的水压一列构造如下时序特征:
- 当前时刻该站点水压与本月的相同整点时间该站点水压均值的差,例如当前时刻为2018-05-20 17:00:00,那么对应需要减去的值为当前月所有17:00:00时间点水压值的均值
- 当前时刻所在周的周末该站点水压均值与工作日水压均值之差
- 当前时刻向前7日内,该站点水压的均值、标准差、0.95分位数、下雨天数与下雪天数的总和
- 当前时刻向前7日内,该站点同一整点时间水压的均值、标准差、0.95分位数
- 当前时刻所在日的该站点水压最高值与最低值出现时刻的时间差