Day12-Python綜合練習2(DataWhale)
一、顯示卡日誌
下面給出了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 2(Inference) 4(float) precision type 1(resnet50)
1(resnet50) model average 2(inference) time : 3(13.426570892333984) ms
問題:整理為如下樣式
請把日誌結果進行整理,變換成如下狀態model_i用相應模型名稱填充,按照字母順序排序,數值保留三位小數:
思路
1.觀察給定的資料,首先需要做的是將資料匯入進來
2.將1,2,3,4的資料提取出來
3.將2和4組合為列,1為行,3作為值
import pandas as pd
import numpy as np
import re
【START】
1. 讀取資料
使用re模組讀取兩個值之間的資料,此處可以直接將開始和結尾的多餘資料直接刪除,然後讀取txt檔案,但是考慮到日常的使用,選擇使用這種方式
file = open('benchmark.txt')
keyStart = 'memory_available: 129118310400'
keyEnd = 'benchmark end : 2020/12/24 12:56:47'
buff = file.read()
pat = re.compile(keyStart+'(.*?)'+keyEnd, re.S)
result = pat.findall(buff) #得到我們實際想要的資料
file.close()
2.調整資料格式
上面獲取的資料讀取出來是一個列表,存成了一列,觀察資料發現可以通過/n拆分,但是拆分出來的列表的並沒有按照一條完整的日誌資料來儲存,接著將列表資料拆分為奇數列和偶數列,得到我們想要的一條完整的日誌記錄存在在一行
A = result
#將資料依據\n拆分
A = A[0].split('\n')
#去除多餘資料
A = A[1:len(A)-1]
# 獲取奇數列和偶數列
J = [i for i in A if A.index(i)%2 == 0]
Q = [i for i in A if A.index(i)%2 == 1]
#將奇數列和偶數列拼成DataFrame
df = pd.DataFrame({'A':J,
'B': Q})
df.head(2)
A | B | |
---|---|---|
0 | Benchmarking Training float precision type mna... | mnasnet0_5 model average train time : 28.527... |
1 | Benchmarking Training float precision type mna... | mnasnet0_75 model average train time : 34.10... |
3.提取值
A列:提取2,4 ;B列提取1,3
#通過正則提取到2和4
s1 = df['A']
p = 'Benchmarking( \w+)( \w+)'
ext1 = s1.str.extract(p)
s2 = df['B']
#提取到1,2,3。注意獲取浮點型資料的方法
p2 = '(\w+) model average (\w+) time : (\d+.\d+)'
ext2 = s2.str.extract(p2)
#拼接1,2,3,4
data = pd.DataFrame({'name': ext2[0],
'type': ext1[0]+'_'+ext1[1],
'time': round(ext2[2].astype('float'),3)})#擷取為小數點後三位,注意需要轉換為float型
data.head(3)
name | type | time | |
---|---|---|---|
0 | mnasnet0_5 | Training_ float | 28.528 |
1 | mnasnet0_75 | Training_ float | 34.105 |
2 | mnasnet1_0 | Training_ float | 34.314 |
4. 長表變寬表
data = data.pivot(index='name',columns='type',values='time')
data = data.reset_index()
data.head()
type | name | Inference_ double | Inference_ float | Inference_ half | Training_ double | Training_ float | Training_ half |
---|---|---|---|---|---|---|---|
0 | densenet121 | 144.111 | 15.637 | 19.772 | 417.207 | 93.357 | 88.976 |
1 | densenet161 | 511.177 | 31.750 | 27.555 | 1290.287 | 136.624 | 144.319 |
2 | densenet169 | 175.808 | 21.598 | 26.371 | 511.404 | 104.840 | 121.556 |
3 | densenet201 | 223.960 | 26.169 | 33.394 | 654.365 | 129.334 | 118.940 |
4 | mnasnet0_5 | 11.870 | 8.039 | 6.929 | 48.232 | 28.528 | 27.198 |
【END】
總結
這道題的總體思路是比較好找到的,但是遇到了幾個問題:
1.首先就是讀取資料,需要排除我們不要的資料,這裡是在網上查找了一個獲取開始和結束值之間資料的方法
2.資料獲取了之後發現存的是一個長字串,觀察之後選擇將資料拆分,需要注意的是要先轉換為字串之後再拆分,拆分完以後,發現我們需要的資料存成了兩行,這裡又將兩行轉換為兩列
上面兩個問題解決後終於將我們的資料整理成了可以進行各種操作的資料集,之後就是通過正則表示式將我們需要的資料提取,然後再進行長寬表變換,最後就得到了我們的最終資料
二、水壓站點的特徵工程
df1和df2中分別給出了18年和19年各個站點的資料,其中列中的H0至H23分別代表當天0點至23點;df3中記錄了18-19年的每日該地區的天氣情況,請完成如下的任務:
df1 = pd.read_csv('yali18.csv')
df2 = pd.read_csv('yali19.csv')
df3 = pd.read_csv('qx1819.csv')
df1.tail(2)
Time | MeasName | H0 | H1 | H2 | H3 | H4 | H5 | H6 | H7 | ... | H14 | H15 | H16 | H17 | H18 | H19 | H20 | H21 | H22 | H23 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
10948 | 2018-12-31 | 站點9 | 0.287250 | 0.301875 | 0.30600 | 0.30525 | 0.313500 | 0.301500 | 0.279750 | 0.253875 | ... | 0.241500 | 0.237750 | 0.233625 | 0.227625 | 0.209625 | 0.226500 | 0.21975 | 0.211500 | 0.241125 | 0.246375 |
10949 | 2018-12-31 | 站點6 | 0.313125 | 0.330375 | 0.33375 | 0.33450 | 0.337125 | 0.326625 | 0.310875 | 0.277875 | ... | 0.261375 | 0.259125 | 0.262125 | 0.252750 | 0.241500 | 0.252375 | 0.24675 | 0.239625 | 0.269250 | 0.269625 |
2 rows × 26 columns
df2.head(2)
Time | MeasName | H0 | H1 | H2 | H3 | H4 | H5 | H6 | H7 | ... | H14 | H15 | H16 | H17 | H18 | H19 | H20 | H21 | H22 | H23 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2019-01-01 | 站點4 | 0.342000 | 0.429375 | 0.4290 | 0.44025 | 0.445875 | 0.444750 | 0.417750 | 0.387000 | ... | 0.319875 | 0.32625 | 0.323625 | 0.322500 | 0.309000 | 0.307125 | 0.307125 | 0.307125 | 0.307125 | 0.307125 |
1 | 2019-01-01 | 站點7 | 0.215125 | 0.239500 | 0.2575 | 0.24625 | 0.275125 | 0.264625 | 0.229375 | 0.205375 | ... | 0.180625 | 0.17650 | 0.181375 | 0.155125 | 0.159625 | 0.146125 | 0.144625 | 0.135250 | 0.158875 | 0.184750 |
2 rows × 26 columns
1. 通過df1和df2構造df,把時間設為索引,第一列為站點編號,第二列為對應時刻的壓力大小
思路
使用縱向拼接將df1和df2資料集合並,然後需要將H0-H23轉換為對應的時間點,之後通過寬表變長表將日期和時間匹配
【START】
1. 拼接資料
df = pd.concat([df1,df2],axis=0,join='outer')
df.head(2)
Time | MeasName | H0 | H1 | H2 | H3 | H4 | H5 | H6 | H7 | ... | H14 | H15 | H16 | H17 | H18 | H19 | H20 | H21 | H22 | H23 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2018-01-01 | 站點4 | 0.402750 | 0.407625 | 0.418125 | 0.425250 | 0.426 | 0.42525 | 0.417375 | 0.426375 | ... | 0.348750 | 0.35925 | 0.35550 | 0.34425 | 0.352125 | 0.35625 | 0.34725 | 0.343875 | 0.356625 | 0.418875 |
1 | 2018-01-01 | 站點7 | 0.214375 | 0.226750 | 0.232375 | 0.233125 | 0.235 | 0.23275 | 0.230875 | 0.220000 | ... | 0.187375 | 0.19675 | 0.19975 | 0.19225 | 0.186250 | 0.18325 | 0.17725 | 0.163375 | 0.165250 | 0.199375 |
2 rows × 26 columns
2. 將H0-H23替換為時間值
#1.使用正則將H去除
timet = pd.Series(df.columns[2:])
p = 'H(\d+)'
timet = timet.str.extract(p)[0].to_list()
#2.在前面填充0,否則在後面拼接的時候0:00:00不顯示
timet = [' '+i.zfill(2)+':00:00' for i in timet]
#3.替換原來的列名,這裡將列名補全,可以直接替換
timet1 = ['Date','站點']+timet
df.columns = timet1
df.head(2)
Date | 站點 | 00:00:00 | 01:00:00 | 02:00:00 | 03:00:00 | 04:00:00 | 05:00:00 | 06:00:00 | 07:00:00 | ... | 14:00:00 | 15:00:00 | 16:00:00 | 17:00:00 | 18:00:00 | 19:00:00 | 20:00:00 | 21:00:00 | 22:00:00 | 23:00:00 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2018-01-01 | 站點4 | 0.402750 | 0.407625 | 0.418125 | 0.425250 | 0.426 | 0.42525 | 0.417375 | 0.426375 | ... | 0.348750 | 0.35925 | 0.35550 | 0.34425 | 0.352125 | 0.35625 | 0.34725 | 0.343875 | 0.356625 | 0.418875 |
1 | 2018-01-01 | 站點7 | 0.214375 | 0.226750 | 0.232375 | 0.233125 | 0.235 | 0.23275 | 0.230875 | 0.220000 | ... | 0.187375 | 0.19675 | 0.19975 | 0.19225 | 0.186250 | 0.18325 | 0.17725 | 0.163375 | 0.165250 | 0.199375 |
2 rows × 26 columns
3.將寬表變為長表
#轉換為長表,然後將日期和時間拼接為一個欄位
df_melted = df.melt(id_vars=['Date','站點'],
value_vars=timet,
var_name='Time2',
value_name='壓力')
df_melted['Time'] = pd.to_datetime(df_melted['Date']+df_melted['Time2'])
df_new = df_melted[['Time','站點','壓力']]
#將Time作為索引
df_new = df_new.set_index('Time')
df_new.tail(3)
站點 | 壓力 | |
---|---|---|
Time | ||
2019-12-31 23:00:00 | 站點2 | 0.332000 |
2019-12-31 23:00:00 | 站點9 | 0.201375 |
2019-12-31 23:00:00 | 站點6 | 0.000000 |
【END】
2. 在上一問構造的df基礎上,構造下面的特徵序列或DataFrame,並把它們逐個拼接到df的右側
2.1 當天最高溫、最低溫和它們的溫差
df3.head(3)
日期 | 天氣 | 氣溫 | 風向 | |
---|---|---|---|---|
0 | 2018-01-01 | 多雲 | 1C~-4C | 東南風 微風 |
1 | 2018-01-02 | 陰轉多雲 | 8C~0C | 東北風 3-4級 |
2 | 2018-01-03 | 陰轉小雪 | 1C~-1C | 東北風 4-5級轉4-5級 |
【START】
思路
首先我們需要將df3的氣溫拆成最低氣溫和最高氣溫,並存成數值型,計算出溫差使用join拼入df中
#刪除氣溫為空的值
df_t = df3.dropna(how='any',subset=['氣溫'])
s = df_t['氣溫']
#將空格和℃替換為統一值,方便正則取值
s = s.str.replace(' ','')
s = s.str.replace('℃','C')
#正則表示式取出溫度
p = '(\d+)C~(\S\d+|\d+)'
ext = s.str.extract(p)
#由於存在沒有最低溫度的值,這裡選擇不為na的值
ext = ext[ext[0].isna()==False]
#將型別轉換為int型,方便計算差值
ext[0] = ext[0].astype(int)
ext[1] = ext[1].astype(int)
ext[2] = ext[0] - ext[1]
ext.head(2)
0 | 1 | 2 | |
---|---|---|---|
0 | 1 | -4 | 5 |
1 | 8 | 0 | 8 |
上面一步出現了問題:首先是會有存在空格的現象,採用替代的Day3-Index.ipynb將空格刪除出;另一個會有沒有最低溫度的值,因為只有兩條,這裡選擇將其刪除
#使用索引拼接的方式,上面刪除na值不會影響到索引號
df_t = df_t.join(ext,how='outer')
#對列名重新命名
df_t = df_t.rename(columns = {0:'最高氣溫',1:'最低氣溫',2:'溫差'})
df_t = df_t[['日期','最高氣溫','最低氣溫','溫差']]
df_t['日期'] = pd.to_datetime(df_t['日期'])
df_te = df_new.copy()
#對第1小問生成的df_new進行改造,建立拼接欄位date
df_m = df_te.reset_index(drop=False)
#注意使用merge的時候,兩個日期的型別要一致
df_m['date'] = pd.to_datetime(df_m['Time'].dt.date)
df_l = df_m.merge(df_t, left_on = 'date', right_on='日期', how='left')
df_l.head(2)
Time | 站點 | 壓力 | date | 日期 | 最高氣溫 | 最低氣溫 | 溫差 | |
---|---|---|---|---|---|---|---|---|
0 | 2018-01-01 | 站點4 | 0.402750 | 2018-01-01 | 2018-01-01 | 1.0 | -4.0 | 5.0 |
1 | 2018-01-01 | 站點7 | 0.214375 | 2018-01-01 | 2018-01-01 | 1.0 | -4.0 | 5.0 |
【END】
2.2 當天是否有沙暴、是否有霧、是否有雨、是否有雪、是否為晴天
思路
我們想要返回布林型別,因此可以直接使用str.contains,然後再拼接資料
【START】
df_w = df3.copy()
#日期型別轉換
df_w['日期'] = pd.to_datetime(df_w['日期'])
s = df_w['天氣']
s1 = s.str.contains('沙|暴')
#此處注意一定要重新命名,預設名稱為天氣,在join的時候會報錯
s1 = s1.rename('是否沙暴')
s2 = s.str.contains('霧')
s2 = s2.rename('是否有霧')
s3 = s.str.contains('雨')
s3 = s3.rename('是否有雨')
s4 = s.str.contains('雪')
s4 = s4.rename('是否有雪')
s5 = s.str.contains('晴')
s5 = s5.rename('是否晴天')
#將上面的結果拼接到df_w中
df_w = df_w.join(s1,how='left')
df_w = df_w.join(s2,how='left')
df_w = df_w.join(s3,how='left')
df_w = df_w.join(s4,how='left')
df_w = df_w.join(s5,how='left')
df_w.tail(2)
日期 | 天氣 | 氣溫 | 風向 | 是否沙暴 | 是否有霧 | 是否有雨 | 是否有雪 | 是否晴天 | |
---|---|---|---|---|---|---|---|---|---|
727 | 2019-12-30 | 陰轉晴 | 4℃~-6℃ | 東北風轉北風 4-5級轉4-5級 | False | False | False | False | True |
728 | 2019-12-31 | 晴轉多雲 | 0℃~-5℃ | 西風轉南風 <3級 | False | False | False | False | True |
#將df_w資料拼接到df_l
df_l = df_l.merge(df_w, left_on = 'date', right_on='日期', how='left')
df_e = df_l[['Time','站點','壓力','date','天氣','氣溫','風向','最高氣溫','最低氣溫','溫差','是否沙暴','是否有霧','是否有雨','是否有雪','是否晴天']]
df_e.tail(2)
Time | 站點 | 壓力 | date | 天氣 | 氣溫 | 風向 | 最高氣溫 | 最低氣溫 | 溫差 | 是否沙暴 | 是否有霧 | 是否有雨 | 是否有雪 | 是否晴天 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
525598 | 2019-12-31 23:00:00 | 站點9 | 0.201375 | 2019-12-31 | 晴轉多雲 | 0℃~-5℃ | 西風轉南風 <3級 | 0.0 | -5.0 | 5.0 | False | False | False | False | True |
525599 | 2019-12-31 23:00:00 | 站點6 | 0.000000 | 2019-12-31 | 晴轉多雲 | 0℃~-5℃ | 西風轉南風 <3級 | 0.0 | -5.0 | 5.0 | False | False | False | False | True |
【END】
2.3 選擇一種合適的方法度量雨量/下雪量的大小(構造兩個序列分別表示二者大小)
思路
雨量使用水壓站點當天的最大壓力來度量,下雪量的大小通過天氣中的雪的型別來區分,設定為分類資料型別
【START】
雨量的分類
#篩選出有雨的資料
df_y = df_e[df_e['是否有雨']==True]
gb = df_y.groupby('date')['壓力'].max()
#依據gb的最大值和最小值來進行分組,分為小、中、大、特大四類
print(gb.min())
print(gb.max())
0.40424999594688416
1.4006251096725464
#對雨量進行分類
s = pd.cut(gb, bins=4, labels=['小','中','大','特大'])
雪量的分類
#篩選出有雪的資料
df_x = df_e[df_e['是否有雪']==True]
pat = '(\w雪)'
typ = df_x['天氣'].str.extract(pat)
typ[0].unique()
#我們發現提取後,雪的分類可以設定為四類,現在需要將四類作為有序分類
array(['小雪', '中雪', '夾雪', '大雪'], dtype=object)
#設定為有序分類
typ = typ[0].astype('category')
typ = typ.cat.reorder_categories(['夾雪','小雪', '中雪', '大雪'],ordered=True)
將雨和雪的分類拼接
#修改為DataFrame,s使用值連線
s = pd.DataFrame(s)
s = s.reset_index()
df_f = df_e.merge(s,on ='date',how='left')
#typ使用索引連線
typ = pd.DataFrame(typ)
df_f = df_f.join(typ,how='outer')
df_f = df_f.rename(columns={'壓力_x':'壓力','壓力_y':'雨量大小',0:'雪量大小'})
df_f[df_f['是否有雨']==True].head(2)
Time | 站點 | 壓力 | date | 天氣 | 氣溫 | 風向 | 最高氣溫 | 最低氣溫 | 溫差 | 是否沙暴 | 是否有霧 | 是否有雨 | 是否有雪 | 是否晴天 | 雨量大小 | 雪量大小 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
450 | 2018-01-16 | 站點4 | 0.396375 | 2018-01-16 | 雨夾雪轉陰 | 4C~-1C | 東北風轉南風 3-4級轉3-4級 | 4.0 | -1.0 | 5.0 | False | False | True | True | False | 小 | 夾雪 |
451 | 2018-01-16 | 站點7 | 0.209500 | 2018-01-16 | 雨夾雪轉陰 | 4C~-1C | 東北風轉南風 3-4級轉3-4級 | 4.0 | -1.0 | 5.0 | False | False | True | True | False | 小 | 夾雪 |
【END】
2.4 限制只用4列,對風向進行0-1編碼(只考慮風向,不考慮大小)
思路
首先檢視一下風向的種類,發現有很多類別,這裡選取後兩位作為它的主要風向(這裡我認為並不是最優的)
【START】
#獲取風向的資料,並以後兩位作為主要風向
p ='(轉\w+風|\w+風)'
df_d = df_f['風向'].str.extract(p)
df_d = pd.DataFrame([str(i)[-2:] for i in df_d[0].to_list()])
#轉換為4列0-1編碼
df_d = pd.get_dummies(df_d[0])
df_d = df_d[['東風','西風','南風','北風']]
#將風向資料拼入df_f,索引連線
df_h = df_f.join(df_d,how='outer')
df_h.tail(2)
Time | 站點 | 壓力 | date | 天氣 | 氣溫 | 風向 | 最高氣溫 | 最低氣溫 | 溫差 | ... | 是否有霧 | 是否有雨 | 是否有雪 | 是否晴天 | 雨量大小 | 雪量大小 | 東風 | 西風 | 南風 | 北風 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
525598 | 2019-12-31 23:00:00 | 站點9 | 0.201375 | 2019-12-31 | 晴轉多雲 | 0℃~-5℃ | 西風轉南風 <3級 | 0.0 | -5.0 | 5.0 | ... | False | False | False | True | NaN | NaN | 0 | 0 | 1 | 0 |
525599 | 2019-12-31 23:00:00 | 站點6 | 0.000000 | 2019-12-31 | 晴轉多雲 | 0℃~-5℃ | 西風轉南風 <3級 | 0.0 | -5.0 | 5.0 | ... | False | False | False | True | NaN | NaN | 0 | 0 | 1 | 0 |
2 rows × 21 columns
【END】
3. 對df的水壓一列構造如下時序特徵
3.1 當前時刻該站點水壓與本月的相同整點時間該站點水壓均值的差,例如當前時刻為2018-05-20 17:00:00,那麼對應需要減去的值為當前月所有17:00:00時間點水壓值的均值
思路
首先計算按月到時刻、站點的均值,然後拼接到主表,最後進行計算
【START】
#對df進行改造,新增月和時刻的列值
df = pd.DataFrame(df_h[['Time','date','站點','壓力','是否有雨','是否有雪']])
df['month'] = df['Time'].dt.month
df['hour'] = df['Time'].dt.hour
df.head()
Time | date | 站點 | 壓力 | 是否有雨 | 是否有雪 | month | hour | |
---|---|---|---|---|---|---|---|---|
0 | 2018-01-01 | 2018-01-01 | 站點4 | 0.402750 | False | False | 1 | 0 |
1 | 2018-01-01 | 2018-01-01 | 站點7 | 0.214375 | False | False | 1 | 0 |
2 | 2018-01-01 | 2018-01-01 | 站點22 | 0.247000 | False | False | 1 | 0 |
3 | 2018-01-01 | 2018-01-01 | 站點21 | 0.284250 | False | False | 1 | 0 |
4 | 2018-01-01 | 2018-01-01 | 站點20 | 0.292875 | False | False | 1 | 0 |
#到月到時段的均值計算
df_month = df.groupby(['month','hour','站點'])['壓力'].mean()
df_month = df_month.reset_index()
df_month.head()
month | hour | 站點 | 壓力 | |
---|---|---|---|---|
0 | 1 | 0 | 站點1 | 0.260095 |
1 | 1 | 0 | 站點10 | 0.259512 |
2 | 1 | 0 | 站點11 | 0.244476 |
3 | 1 | 0 | 站點12 | 0.252960 |
4 | 1 | 0 | 站點13 | 0.259923 |
#將到月的資料拼接到df,使用值拼接
df = df.merge(df_month, on=['month','hour','站點'],how='left')
df = df.sort_values(by=['站點','hour'],axis=0,ascending=True)
df = df.rename(columns={'壓力_x':'壓力','壓力_y':'平均壓力'})
df[(df['站點']=='站點1')&df['hour']==1].head(3)
Time | date | 站點 | 壓力 | 是否有雨 | 是否有雪 | month | hour | 平均壓力 | |
---|---|---|---|---|---|---|---|---|---|
21909 | 2018-01-01 01:00:00 | 2018-01-01 | 站點1 | 0.292000 | False | False | 1 | 1 | 0.266966 |
21939 | 2018-01-02 01:00:00 | 2018-01-02 | 站點1 | 0.291625 | False | False | 1 | 1 | 0.266966 |
21969 | 2018-01-03 01:00:00 | 2018-01-03 | 站點1 | 0.296500 | False | True | 1 | 1 | 0.266966 |
【END】
3.2 當前時刻所在周的週末該站點水壓均值與工作日水壓均值之差
思路
首先找到站點的週末和工作日,然受計算週末和工作日的均值,最後再按照站點、年、月、周進行彙總
【START】
#增加年、周、工作日維度
df['year'] = df['Time'].dt.year
df['week'] = df['Time'].dt.isocalendar().week
df['day_week'] = df['Time'].dt.dayofweek
df.head(2)
Time | date | 站點 | 壓力 | 是否有雨 | 是否有雪 | month | hour | 平均壓力 | year | week | day_week | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
9 | 2018-01-01 | 2018-01-01 | 站點1 | 0.288625 | False | False | 1 | 0 | 0.260095 | 2018 | 1 | 0 |
39 | 2018-01-02 | 2018-01-02 | 站點1 | 0.286750 | False | False | 1 | 0 | 0.260095 | 2018 | 1 | 1 |
#週末的水壓均值
df_m = df[df['day_week'].isin([5,6])]
df_m2 = df_m.groupby(['站點','year','month','week'])['壓力'].mean()
df_m2 = df_m2.reset_index()
df_m2 = df_m2.rename(columns={'壓力':'週末平均壓力'})
df_m2.head(2)
站點 | year | month | week | 週末平均壓力 | |
---|---|---|---|---|---|
0 | 站點1 | 2018 | 1 | 1 | 0.251711 |
1 | 站點1 | 2018 | 1 | 2 | 0.248945 |
#工作日的水壓均值
df_w = df[df['day_week'].isin([0,1,2,3,4])]
df_w2 = df_w.groupby(['站點','year','month','week'])['壓力'].mean()
df_w2 = df_w2.reset_index()
df_w2 = df_w2.rename(columns={'壓力':'工作日平均壓力'})
df_w2.head(2)
站點 | year | month | week | 工作日平均壓力 | |
---|---|---|---|---|---|
0 | 站點1 | 2018 | 1 | 1 | 0.253222 |
1 | 站點1 | 2018 | 1 | 2 | 0.252750 |
#拼接資料
df = df.merge(df_m2, on=['站點','year','month','week'],how='left')
df = df.merge(df_w2, on=['站點','year','month','week'],how='left')
#做差值
df['週末與工作日壓力差值'] = df['週末平均壓力'] - df['工作日平均壓力']
df.tail(2)
Time | date | 站點 | 壓力 | 是否有雨 | 是否有雪 | month | hour | 平均壓力 | year | week | day_week | 週末平均壓力 | 工作日平均壓力 | 週末與工作日壓力差值 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
525598 | 2019-12-30 23:00:00 | 2019-12-30 | 站點9 | 0.225375 | False | False | 12 | 23 | 0.247349 | 2019 | 1 | 0 | NaN | 0.218828 | NaN |
525599 | 2019-12-31 23:00:00 | 2019-12-31 | 站點9 | 0.201375 | False | False | 12 | 23 | 0.247349 | 2019 | 1 | 1 | NaN | 0.218828 | NaN |
【END】
3.3 當前時刻向前7日內,該站點水壓的均值、標準差、0.95分位數、下雨天數與下雪天數的總和
思路
我理解這一問求得是到日的結果,不到時刻對應的結果,按照每個不同的站點,使用rolling移動求出相對應的值,這裡僅實現了均值,其他的可以參照這個方法實現,但是使用rolling會將當天也算在7天內,這是一個bug點
【START】
s = df.copy()
#得到到單日的均值
f = pd.DataFrame(s.groupby(['date','站點'])['壓力'].mean())
f = f.reset_index()
#建立站點的序列,以便下面的迴圈
z = pd.Series(s['站點'].unique())
for i in z:
#給定到站點
s = f[f['站點']==i]
#要使用rolling,所以欄位僅為日期和壓力
s = s[['date','壓力']]
#對date進行一個排序
s = s.sort_values(by='date')
#設定索引
s1 = s.set_index('date')
#rolling取7天均值
r = s1.rolling(window=7)
r1 = r.mean()
#將站點的值拼入r1中
m = pd.DataFrame([i]*r1.shape[0],index=s['date'].to_list(),columns=['站點'])
n = pd.concat([r1,m],1)
#得到最終結果
result = pd.concat([result,n])
result[result['站點']=='站點2']
壓力 | 站點 | |
---|---|---|
2018-01-01 | NaN | 站點2 |
2018-01-02 | NaN | 站點2 |
2018-01-03 | NaN | 站點2 |
2018-01-04 | NaN | 站點2 |
2018-01-05 | NaN | 站點2 |
... | ... | ... |
2019-12-27 | 0.335159 | 站點2 |
2019-12-28 | 0.335098 | 站點2 |
2019-12-29 | 0.334743 | 站點2 |
2019-12-30 | 0.335152 | 站點2 |
2019-12-31 | 0.335009 | 站點2 |
2920 rows × 2 columns
【END】
3.4 當前時刻向前7日內,該站點同一整點時間水壓的均值、標準差、0.95分位數
思路
依照上面的方法,我們多加一個時刻的引數即可
【START】
s = df.copy()
#得到到單日的均值
f = s[['Time','hour','站點','壓力']]
#建立站點的序列,以便下面的迴圈
z = pd.Series(s['站點'].unique())
t = pd.Series(s['hour'].unique())
for i in z:
for j in t:
#給定到站點
s = f[f['站點']==i]
#要使用rolling,所以欄位僅為日期和壓力
s = s[s['hour']==j]
s = s[['Time','壓力']]
#對date進行一個排序
s = s.sort_values(by='Time')
#設定索引
s1 = s.set_index('Time')
#rolling取7天均值
r = s1.rolling(window=7)
r1 = r.mean()
#將站點的值拼入r1中
m = pd.DataFrame([i]*r1.shape[0],index=s['Time'].to_list(),columns=['站點'])
n = pd.concat([r1,m],1)
#得到最終結果
result = pd.concat([result,n])
result[result['站點']=='站點2']
壓力 | 站點 | |
---|---|---|
2018-01-01 00:00:00 | NaN | 站點2 |
2018-01-02 00:00:00 | NaN | 站點2 |
2018-01-03 00:00:00 | NaN | 站點2 |
2018-01-04 00:00:00 | NaN | 站點2 |
2018-01-05 00:00:00 | NaN | 站點2 |
... | ... | ... |
2019-12-27 23:00:00 | 0.338964 | 站點2 |
2019-12-28 23:00:00 | 0.339286 | 站點2 |
2019-12-29 23:00:00 | 0.339982 | 站點2 |
2019-12-30 23:00:00 | 0.341054 | 站點2 |
2019-12-31 23:00:00 | 0.339714 | 站點2 |
20440 rows × 2 columns
3.5 當前時刻所在日的該站點水壓最高值與最低值出現時刻的時間差
思路
先求出當前日的水壓最高點和最低點時刻,然後再算時間差
【START】
#找到水壓的最高點,先通過groupby找到最高點的值,然後再通過merge的inner找到最高點的時段
df5 = df_e.copy()
df1 = df5.groupby(['站點','date'])['壓力'].max()
#這裡出現了一個問題,最大值和最小值存在多條記錄的情況,所以選擇在對Time取最大值
df_n = df5.merge(df1,on=['站點','date','壓力'],how='inner')
df_n = pd.DataFrame(df_n.groupby(['站點','date'])['Time'].max())
df_max = df_n.reset_index()
df_max = df_max.rename(columns={'Time':'max_time'})
#找到水壓的最高點,先通過groupby找到最高點的值,然後再通過merge的inner找到最高點的時段
df2 = df5.groupby(['站點','date'])['壓力'].min()
df_n = df5.merge(df2,on=['站點','date','壓力'],how='inner')
#這裡最小值存在多值的問題選擇最小值
df_n = pd.DataFrame(df_n.groupby(['站點','date'])['Time'].min())
df_min = df_n.reset_index()
df_min = df_min.rename(columns={'Time':'min_time'})
#通過date和站點將最大值和最小值拼接
df_f = df_max.merge(df_min, on=['date','站點'],how='outer')
df_f['time_diff'] = df_f['max_time'] -df_f['min_time']
df_f.sort_values(by=['date'])
df_f = df_f[['date','站點','time_diff']]
df_f.head(2)
date | 站點 | time_diff | |
---|---|---|---|
0 | 2018-01-01 | 站點1 | -1 days +18:00:00 |
1 | 2018-01-02 | 站點1 | -1 days +18:00:00 |
【END】
總結
在題目2中遇到的最大的問題是,當寫了很多條賦值語句的時候,命名如果不具有代表性,很難清晰的知道之前的含義,在之後的學習中一定要規避這個問題,儘量將名稱認真的取名。
整個做題的過程中,大部分的思維方式都是基於表格運算的思維方式,這個方式可以解決問題,但是可能並不是最優的方案,之後還需要更多的去了解python內的知識,轉變自己的思維方式。
最後,要養成寫備註的習慣!!!