【Task Final】Pandas之综合练习2

前言

Mission04 显卡日志

下面给出了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用相应模型名称填充,按照字母顺序排序,数值保留三位小数:

【Task Final】Pandas之综合练习2_第1张图片

数据查看

#略去前10行和后2行 不设置第一行数据为col值 引擎使用python
df = pd.read_table('./data/mission04/benchmark.txt',skiprows=10,skipfooter=2,header=None,engine='python')
df

【Task Final】Pandas之综合练习2_第2张图片

完整解题代码

def my_func(x):
    list1 = x.iloc[1].split(' ')
    list2 = x.iloc[-1].split(' ')
    return pd.Series([list2[0],list1[1],float(list2[-2]),list1[2]],index=['model_name','data_type','time','state'])
#把df的每两行合并到一起,并用my_func方法提取4个参数并将time小数点后保留三位
df_demo = pd.concat([df[0::2].reset_index(),df[1::2].reset_index()],axis=1).apply(my_func,axis=1).round({
     'time': 3})
#进行长宽表转换
res = df_demo.pivot(index='model_name',columns=['data_type','state'],values='time')
#进行多级列索引合并
res.columns = res.columns.map(lambda x:(x[0]+'_'+x[1]))
#按要求排列列索引顺序
res = res[['Training_half','Training_float','Training_double','Inference_half','Inference_float','Inference_double']]
res.shape
(32, 6)
res

【Task Final】Pandas之综合练习2_第3张图片

Mission05 水压站点的特征工程

  • df1和df2中分别给出了18年和19年各个站点的数据,其中列中的H0至H23分别代表当天0点至23点

  • df3中记录了18-19年的每日该地区的天气情况

请完成如下的任务:

1.通过df1和df2构造df,把时间设为索引,第一列为站点编号,第二列为对应时刻的压力大小,排列方式如下(压力数值请用正确的值替换):

def process_df(my_df):
    df_demo = my_df.melt(id_vars=['Time','MeasName'],value_vars=df1.columns[2:],var_name='小时',value_name='压力')
    df_demo.Time = pd.to_datetime(df_demo.Time) + pd.to_timedelta(df_demo['小时'].apply(lambda x:x[1:]+'H'))
    df_demo.MeasName = df_demo.MeasName.apply(lambda x:int(x[2:]))
    df_demo.drop('小时',axis=1,inplace=True)
    return df_demo.sort_values(['Time','MeasName'])
df1 = pd.read_csv('./data/mission05/yali18.csv')
df2 = pd.read_csv('./data/mission05/yali19.csv')
df = pd.concat([process_df(df1),process_df(df2)])
df.reset_index(drop=True,inplace=True)
df.rename(columns = {
     'MeasName':'站点'},inplace=True)
df.set_index('Time',inplace=True)
df

【Task Final】Pandas之综合练习2_第4张图片

2.在上一问构造的df基础上,构造下面的特征序列或DataFrame,并把它们逐个拼接到df的右侧

df3 = pd.read_csv('./data/mission05/qx1819.csv')
df3

【Task Final】Pandas之综合练习2_第5张图片

1)当天最高温、最低温和它们的温差

def my_func(x):
    list2 = x[2].replace(' ','').split('~')
    a1 = int(list2[0][:-1]) if list2[0] not in '℃C' else 0
    a2 = int(list2[1][:-1]) if list2[1] not in '℃C' else 0
    a1 = a2 if a1 < a2 else a1
    return pd.Series([x[0],a1,a2,a1-a2],index=['日期','最高温','最低温','温差'])
df3.apply(my_func,axis=1)

【Task Final】Pandas之综合练习2_第6张图片

2)当天是否有沙暴、是否有雾、是否有雨、是否有雪、是否为晴天

def my_func(x):
    return pd.Series(['沙' in x[1],'雾' in x[1],'雨' in x[1],'雪' in x[1],'晴天' in x[1]],index=['是否有沙暴','是否有雾','是否有雨','是否有雪','是否为晴天'])
df3.apply(my_func,axis=1)

【Task Final】Pandas之综合练习2_第7张图片

3) 选择一种合适的方法度量雨量/下雪量的大小(构造两个序列分别表示二者大小)

对不同的雨雪情况进行观察:

def my_func(x):
    if '雪' in x:
        return x
snow_list = list(df_weather.apply(my_func).drop_duplicates())[1:]
snow_list
['阴转小雪',
 '多云转小到中雪',
 '雨夹雪转阴',
 '多云转小雪',
 '阴转雨夹雪',
 '雨夹雪转多云',
 '大雪转多云',
 '阴转中到大雪',
 '小雪转晴',
 '扬沙转雨夹雪',
 '雨夹雪转大雪',
 '雾转雨夹雪']
def my_func(x):
    if '雨' in x:
        return x
rain_list = list(df_weather.apply(my_func).drop_duplicates())[1:]
rain_list
['雨夹雪转阴',
 '阴转雨夹雪',
 '小雨转阴',
 '多云转小雨',
 '阴转小雨',
 '中雨转小雨',
 '多云转雷阵雨',
 '雨夹雪转多云',
 '小雨',
 '多云转中到大雨',
 '阴转阵雨',
 '小雨转中雨',
 '阴转雷阵雨',
 '多云转小到中雨',
 '阴转小到中雨',
 '大雨转小雨',
 '阴转中雨',
 '雷阵雨',
 '小雨转雷阵雨',
 '雷阵雨转阴',
 '雷阵雨转多云',
 '阴转中到大雨',
 '中雨转暴雨',
 '小雨转多云',
 '阴转大雨',
 '中雨转多云',
 '多云转阵雨',
 '扬沙转雨夹雪',
 '雨夹雪转大雪',
 '多云转中雨',
 '雨转阴',
 '小雨转阵雨',
 '大雨转多云',
 '暴雨转雷阵雨',
 '晴转阵雨',
 '中雨转阴',
 '中雨转雷阵雨',
 '暴雨',
 '中雨转小到中雨',
 '雨转多云',
 '晴转小雨',
 '雾转小雨',
 '雾转雨夹雪']

观察后,将雨雪按照不同类别进行离散分类:

雨的种类 等级
小雨 1
中雨 2
大雨 3
阵雨 4
暴雨 5
雨夹雪 6
雪的种类 等级
小雪 1
中雪 2
大雪 3
雨夹雪 4

做一个说明,这里考虑到有不同的“转”的情况,比如“小雨转阵雨”,“阴转大雨”等,这里统一以强度最高的类别为主体:

def my_func(x):
    def judge(s,type):
        dict = snow_dict if type else rain_dict
        for x in dict:
            if x in s:
                return dict[x]
        return 0
    snow_dict = dict(zip(['小雪','中雪','大雪','雨夹雪'],range(1,5)))
    rain_dict = dict(zip(['小雨','中雨','大雨','阵雨','暴雨','雨夹雪'],range(1,7)))
    return pd.Series([judge(x[1],1),judge(x[1],0)],index=['雨量等级','雪量等级'])
df_weather_descibe = df3.apply(my_func,axis=1)
df_weather_descibe

【Task Final】Pandas之综合练习2_第8张图片

4)限制只用4列,对风向进行0-1编码(只考虑风向,不考虑大小)

def my_func(x):
    def returnWindCode(s):
        res = [pd.NA,pd.NA]
        if '东' in s:
            res[0] = 1
        if '西' in s:
            res[0] = 0
        if '南' in s:
            res[1] = 1
        if '北' in s:
            res[1] = 0
        return res
    #list代表风向
    list = x[-1].split(' ')
    #提前补全
    if '转' not in list[0]:
        list[0] += '转'
    #list1为风向列表,可能为空
    list1 = list[0].split('转')
    res = []
    for x in list1:
        res += returnWindCode(x)
    return pd.Series(res,index=['前风 东1西0','前风 南1北0','后风 东1西0','后风 南1北0'])
df3.apply(my_func,axis=1).head(10)

验证:
【Task Final】Pandas之综合练习2_第9张图片

5)统一连接表操作:

由于df与df3合并相当于是多对一合并,所以这里首选merge方法将上面4类额外数据进行统一合并操作:

先进行汇总:

def my_func(x):
    def getWeather():
        typeList = ['沙','雾','雨','雪','晴天']
        return [1 if item in x[1] else 0 for item in typeList]
    def getTemp():
        list2 = x[2].replace(' ','').split('~')
        a1 = int(list2[0][:-1]) if list2[0] not in '℃C' else 0
        a2 = int(list2[1][:-1]) if list2[1] not in '℃C' else 0
        a1 = a2 if a1 < a2 else a1
        return [a1,a2,a1-a2]
    def getWeatherDes():
        def judge(s,type):
            dict = snow_dict if type else rain_dict
            for x in dict:
                if x in s:
                    return dict[x]
            return 0
        snow_dict = dict(zip(['小雪','中雪','大雪','雨夹雪'],range(1,5)))
        rain_dict = dict(zip(['小雨','中雨','大雨','阵雨','暴雨','雨夹雪'],range(1,7)))
        return [judge(x[1],1),judge(x[1],0)]
    def getWindType():
        def returnWindCode(s):
            res = [pd.NA,pd.NA]
            if '东' in s:
                res[0] = 1
            elif '西' in s:
                res[0] = 0
            if '南' in s:
                res[1] = 1
            elif '北' in s:
                res[1] = 0
            return res
        #list代表风向
        list = x[-1].split(' ')
        #提前补全
        if '转' not in list[0]:
            list[0] += '转'
        #list1为风向列表,可能为空
        list1 = list[0].split('转')
        res = []
        for item in list1:
            res += returnWindCode(item)
        return res
    index = ['日期','最高温','最低温','温差','是否有沙暴','是否有雾','是否有雨','是否有雪','是否为晴天','雪量等级','雨量等级','前 东1西0','前 南1北0','后 东1西0','后 南1北0']
    return pd.Series([pd.to_datetime(x[0])]+getTemp()+getWeather()+getWeatherDes()+getWindType(),index=index)
df_total = df3.apply(my_func,axis=1)
df_total

【Task Final】Pandas之综合练习2_第10张图片

然后进行merge:

df_demo = df
df_demo['日期'] = pd.to_datetime(df.index.date)
df_demo = df_demo.reset_index().merge(df_total,on='日期',how='left',validate='m:1').set_index('Time').drop('日期',axis=1)
df_demo

注意这里需要对日期列转成时序类型,并且要将merge方法中的validate参数设置为‘m:1’,否则右边会产生很多空值。而且因为合并后不保留行索引,所以在合并之前要把df_demo的行索引重置,在合并后删掉‘日期’列,效果如下:

【Task Final】Pandas之综合练习2_第11张图片

3.对df的水压一列构造如下时序特征:

1)当前时刻该站点水压与本月的相同整点时间该站点水压均值的差,例如当前时刻为2018-05-20 17:00:00,那么对应需要减去的值为当前月所有17:00:00时间点水压值的均值

首先建立一个根据年、月、小时、站点分组的分组对象,然后求得压力均值,最后将行索引进行合并,存入df_table中:

def concatFourNum(a,b,c,d):
    return str(a)+'-'+str(b)+'-'+str(c)+'-'+str(d)
df_table = df.groupby([df.index.year,df.index.month,df.index.hour,'站点'])['压力'].mean()
df_table.index = df_table.index.map(lambda x:concatFourNum(x[0],x[1],x[2],x[3]))
df_table = df_table.to_frame().reset_index()
df_table

【Task Final】Pandas之综合练习2_第12张图片
然后新建一个df的copy:df_demo,遍历每行建立与df_table的index列保持一致的列:

df_demo = df.copy()
df_demo['index'] = pd.to_datetime(df_demo.index)
df_demo['index'] = df_demo.apply(lambda x:concatFourNum(x[-1].year,x[-1].month,x[-1].hour,x[0]),axis=1)
df_demo

【Task Final】Pandas之综合练习2_第13张图片

最后将两张表进行合并,合并后的效果为:

df_res = df_demo.merge(df_table,on='index',validate='m:1',how='left')
df_res

【Task Final】Pandas之综合练习2_第14张图片

此时压力_x代表当前的压力,压力_y代表题目要求的当月相同整点的压力均值,相减即可得到结果:

res = df_res['压力_x'] - df_res['压力_y']
res
0         0.014988
1         0.000835
2         0.000738
3        -0.015472
4         0.001440
            ...   
525595   -0.004948
525596   -0.021786
525597   -0.009992
525598   -0.012544
525599   -0.011625
Length: 525600, dtype: float64

2)当前时刻所在周的周末该站点水压均值与工作日水压均值之差

首先增加额外信息列辅助判断,分别为站点+当前年份+周数,以及是否为周内:

df_demo = df.copy().reset_index()
# df_demo['weekInfo'] =
df_demo['weekInfo'] = df_demo.apply(lambda x:str(x[1])+'-'+str(x[0].year)+'-'+str(x[0].weekofyear),axis=1)
df_demo['isWeekdays'] =  df_demo.apply(lambda x:x[0].dayofweek < 5,axis=1)
df_demo

【Task Final】Pandas之综合练习2_第15张图片

然后按weekInfo进行分组,利用isWeekdays列分别求均值:

s_wdays = df_demo[df_demo.isWeekdays].groupby('weekInfo')['压力'].mean()
s_wdays
weekInfo
1-2018-1     0.247120
1-2018-10    0.250056
1-2018-11    0.246278
1-2018-12    0.240869
1-2018-13    0.243756
               ...   
9-2019-52    0.210806
9-2019-6     0.265816
9-2019-7     0.239919
9-2019-8     0.250313
9-2019-9     0.254747
Name: 压力, Length: 3120, dtype: float64
s_wends = df_demo[~df_demo.isWeekdays].groupby('weekInfo')['压力'].mean()
s_wends
weekInfo
1-2018-1     0.251711
1-2018-10    0.251602
1-2018-11    0.237789
1-2018-12    0.242266
1-2018-13    0.241422
               ...   
9-2019-52    0.204203
9-2019-6     0.245734
9-2019-7     0.237219
9-2019-8     0.243523
9-2019-9     0.245055
Name: 压力, Length: 3120, dtype: float64

然后相减后转换成df类型准备拼接:

res = (s_wdays - s_wends).to_frame().reset_index()
res

【Task Final】Pandas之综合练习2_第16张图片

最后利用df_demo进行拼接:

df_demo.merge(res,on='weekInfo',validate='m:1',how='left').set_index('Time')

【Task Final】Pandas之综合练习2_第17张图片

压力_y即为所求。

这块也有一点点小问题,不是所有的日期所属的周都是按所在年计算:

pd.Timestamp('2021-01-01').weekofyear
53

【Task Final】Pandas之综合练习2_第18张图片

pd.Timestamp('2019-12-31').weekofyear
1

【Task Final】Pandas之综合练习2_第19张图片
解决思路:研究一下日历中不同日子所属周相对于年的关系,然后在上面生成weekIndex的代码中进行额外的逻辑判断。

3)当前时刻向前7日内,该站点水压的均值、标准差、0.95分位数、下雨天数与下雪天数的总和

df_demoda代表2问中求得的df

gb = df_demo.groupby('站点')
gb.rolling('7D')['压力'].mean()
站点  Time               
1   2018-01-01 00:00:00    0.288625
    2018-01-01 01:00:00    0.290313
    2018-01-01 02:00:00    0.290375
    2018-01-01 03:00:00    0.292656
    2018-01-01 04:00:00    0.294175
                             ...   
30  2019-12-31 19:00:00    0.276701
    2019-12-31 20:00:00    0.276730
    2019-12-31 21:00:00    0.276777
    2019-12-31 22:00:00    0.276824
    2019-12-31 23:00:00    0.276750
Name: 压力, Length: 525600, dtype: float64

gb.rolling('7D')['压力'].std()
站点  Time               
1   2018-01-01 00:00:00         NaN
    2018-01-01 01:00:00    0.002386
    2018-01-01 02:00:00    0.001691
    2018-01-01 03:00:00    0.004767
    2018-01-01 04:00:00    0.005346
                             ...   
30  2019-12-31 19:00:00    0.027159
    2019-12-31 20:00:00    0.027153
    2019-12-31 21:00:00    0.027120
    2019-12-31 22:00:00    0.027075
    2019-12-31 23:00:00    0.027063
Name: 压力, Length: 525600, dtype: float64

gb.rolling('7D')['压力'].quantile(0.95)
站点  Time               
1   2018-01-01 00:00:00    0.288625
    2018-01-01 01:00:00    0.291831
    2018-01-01 02:00:00    0.291850
    2018-01-01 03:00:00    0.298375
    2018-01-01 04:00:00    0.300100
                             ...   
30  2019-12-31 19:00:00    0.319988
    2019-12-31 20:00:00    0.319988
    2019-12-31 21:00:00    0.319988
    2019-12-31 22:00:00    0.319988
    2019-12-31 23:00:00    0.319988
Name: 压力, Length: 525600, dtype: float64

求7天内下雨,下雪天数:

df_res = df_demo.copy()
df_res['Date'] = pd.to_datetime(pd.to_datetime(df_res.index).date)
df_res = df_res[['站点','是否有雨','是否有雪','Date']]
df_res = df_res.groupby(['站点','Date']).agg(lambda x:1 if sum(x) > 0 else 0)
df_res.reset_index('站点').groupby('站点')[['是否有雨','是否有雪']].rolling('7D').sum().rename(columns={
     '是否有雨':'7天内有雨天数','是否有雪':'7天内有雪天数'})

【Task Final】Pandas之综合练习2_第20张图片
这块已经求出了结果,但是有个细节要修改一下:

用主数据表进行merge合并。

4)当前时刻向前7日内,该站点同一整点时间水压的均值、标准差、0.95分位数

先求同一整点的水压的三个系数,然后再进行滑动窗口。

gb = df.groupby([df.index.year,df.index.month,df.index.hour,'站点']).rolling('7D')['压力']
gb.mean()
Time  Time  Time  站点
2018  1     0     1     0.288625
                  1     0.287688
                  1     0.289125
                  1     0.289563
                  1     0.288550
                          ...   
2019  12    23    30    0.286714
                  30    0.283821
                  30    0.284839
                  30    0.284679
                  30    0.282911
Name: 压力, Length: 525600, dtype: float64

gb.std()
Time  Time  Time  站点
2018  1     0     1          NaN
                  1     0.001326
                  1     0.002660
                  1     0.002342
                  1     0.003040
                          ...   
2019  12    23    30    0.006524
                  30    0.007718
                  30    0.007381
                  30    0.007127
                  30    0.007878
Name: 压力, Length: 525600, dtype: float64

gb.quantile(0.95)
Time  Time  Time  站点
2018  1     0     1     0.288625
                  1     0.288531
                  1     0.291663
                  1     0.291831
                  1     0.291775
                          ...   
2019  12    23    30    0.294450
                  30    0.293550
                  30    0.293550
                  30    0.292763
                  30    0.292763
Name: 压力, Length: 525600, dtype: float64

待修改的地方,虽然长度保持一致,但是行索引已经不同,需要修改。

5)当前时刻所在日的该站点水压最高值与最低值出现时刻的时间差

新增主键列index:

def concatFourNum(a,b,c,d):
    return str(a)+'-'+str(b)+'-'+str(c)+'-'+str(d)
df_demo = df.copy()
df_demo['index'] = pd.to_datetime(df_demo.index)
df_demo['index'] = df_demo.apply(lambda x:concatFourNum(x[-1].year,x[-1].month,x[-1].day,x[0]),axis=1)
df_demo = df_demo.reset_index()
df_demo

【Task Final】Pandas之综合练习2_第21张图片

计算每个站点每日的最大压力和最小压力之间的时间差:

res = df.groupby([pd.to_datetime(df.index.date),'站点']).idxmax() - df.groupby([pd.to_datetime(df.index.date),'站点']).idxmin()
res.index = res.index.map(lambda x:concatFourNum(x[0].year,x[0].month,x[0].day,x[1]))
res = res.reset_index()
res

【Task Final】Pandas之综合练习2_第22张图片
左连接两张表,并且更改列名:

res = df_demo.merge(res,how='left',on='index',validate='m:1')
res = res.set_index('Time')[['站点','压力_y']].rename(columns={
     '压力_y':'最高值与最低值出现时刻的时间差'})
res

【Task Final】Pandas之综合练习2_第23张图片

参考文献

1.风向都有哪几种啊

https://zhidao.baidu.com/question/1732599155287606027.html

你可能感兴趣的:(#,pandas数据分析)