<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python數據分析實戰(zhàn):用Pandas 處理時間序列

          共 7732字,需瀏覽 16分鐘

           ·

          2020-09-07 22:58



          low profile,no profile























          前言


          時間序列的處理是傳統經濟學里面的一個重要篇章,在數據科學和機器學習的背景下,時間序列分析所包含的內容更加復雜。
          計量經濟學里的時間序列特指一元時間序列,也就是數據包含兩列,第一列是時間戳,第二列是觀察對象。這屬于比較經典的時間序列。有時候你會注意到一些時間序列的模型或者算法,比如ARIMA,prophet等,都是針對這類時間序列
          商業(yè)里面的交易歷史信息也是一元時間序列。工業(yè)領域中,一些監(jiān)測數據,比如天氣溫度,也是一元時間序列。但是時間序列不止有一元時間序列當同一個時間戳對應的觀測對象不只一個時,我們就有了多元時間序列。比如某個城市的空氣PM2.5的預測,我們可以通過PM2.5的歷史時間觀測值來預測。我們也可以通過當天(或者近期)的其他觀測對象來預測,比如風速,溫度,濕度等。
          多元時間序列在表現形式上就是數據包含多列(大于兩列),第一列是時間戳,后面的列都是觀察對象。當時間序列是多元時,很多經典的機器學習模型可以施展拳腳,比如回歸模型,分類模型,這些模型都依賴于多元的特征。對于我們本文以及后續(xù)的分析中,我們不會將時間序列特指為一元時間序列。
          無論是一元時間序列的分析還是多元時間序列的分析,對于時間相關的預處理格外重要。今天我們就討論pandas在時間序列處理中應用。






          導入數據


          這里我們采用美國能源消耗數據集進行分析和討論,數據集可以在kaggle上下載,如果有問題,可以留言討論。該數據集包含了美國一家能源公司的長達數十年的能源消耗數據,數據分辨率為小時。這里我們下載了兩個數據集進行對比分析,PJME_hourly 和PJMW_hourly (分別對應東區(qū)和西區(qū))。數據集默認放在同目錄的data文件夾下。
          import seaborn as sns
          import pandas as pd
          import matplotlib.pyplot as plt
          pjme_file = 'data/PJME_hourly.csv'
          pjmw_file = 'data/PJMW_hourly.csv'

          通過pandas 的read_csv 來讀取數據。
          df_1 = pd.read_csv(pjme_file)
          df_2 = pd.read_csv(pjmw_file)

          print(df_1.info())
          print(df_2.info())
          數據集并不大,只有2.2MB左右。df_1 包含了145366 行數據,df_2 包含了143206 行數據,這里可以看到兩個數據集的樣本個數不同,如果我們需要對比兩個數據或者進行比較分析,需要對數據進行處理。

          RangeIndex: 145366 entries, 0 to 145365
          Data columns (total 2 columns):
          # Column Non-Null Count Dtype
          --- ------ -------------- -----
          0 Datetime 145366 non-null object
          1 PJME_MW 145366 non-null float64
          dtypes: float64(1), object(1)
          memory usage: 2.2+ MB
          None


          RangeIndex: 143206 entries, 0 to 143205
          Data columns (total 2 columns):
          # Column Non-Null Count Dtype
          --- ------ -------------- -----
          0 Datetime 143206 non-null object
          1 PJMW_MW 143206 non-null float64
          dtypes: float64(1), object(1)
          memory usage: 2.2+ MB
          None






          時間列(時間戳)的處理


          默認讀取的時間列為字符形式,我們可以通過pandas的describe函數來進行統計,首先我們對原始時間列進行統計。
          print(df_1['Datetime'].describe())
          結果如下表,我們可以看到unique 數值不同于count數值,這說明有重復的時間戳。更重要是,由于當前的時間戳是字符串格式,無法進行時間相關的統計
          count 145366
          unique 145362
          top 2015-11-01 02:00:00
          freq 2
          我們通過to_datetime 將字符串轉換為pandas 的Timestamp 格式。這里需要指定字符串的格式。需要注意的是指定的時間格式需要完全匹配樣本的格式,而且要確保所有樣本的時間戳格式是一致的。
          df_1['Datetime'] = pd.to_datetime(df_1['Datetime'],format='%Y-%m-%d %H:%M:%S')
          print(df_1['Datetime'].describe())
          轉換后的時間列重新進行統計,結果如下:
          count 145366
          unique 145362
          top 2014-11-02 02:00:00
          freq 2
          first 2002-01-01 01:00:00
          last 2018-08-03 00:00:00
          Name: Datetime, dtype: object
          這里可以看到和時間相關的統計信息,比如開始的時間是2002-01-01 01:00:00,結束的時間是2018-08-03 00:00:00。
          如果我們顯示數據集的前5行(如下圖),就會發(fā)現第一行的時間并不等于上面的開始時間,這說明樣本并不是按照時間順序嚴格排序的,這對于時間序列分析來說是很大的坑:千萬不要輕信時間系列是默認排序正確的!!!
          Datetime PJME_MW
          0 2002-12-31 01:00:00 26498.0
          1 2002-12-31 02:00:00 25147.0
          2 2002-12-31 03:00:00 24574.0
          3 2002-12-31 04:00:00 24393.0
          4 2002-12-31 05:00:00 24860.0






          時間序列數據清理


          對于這個數據集來說,目前有兩處需要清理:
          1. 出現重復的時間戳及樣本,需要我們移除

          2. 樣本排序混亂

          對于一般的時間序列去重,我們可以通過保留第一個或者最后一個來進行清理,這里我們采用求均值的方法,也就是對重復時間戳的樣本進行求均值。理由如下:
          1. 其實該數據集是單純的重復類型,保留第一個,最后一個,或者求均值,結果是一致的

          2. 重要的是想展示一個pivot_table的用法

          我們采用pivot_table,將時間列設為index,將觀察對象列設為value,aggfuc采用mean。這樣我們就消除了重復項,確保時間列的每個值是唯一的。
          之后我們用sort_values進行重新排序,并且設置時間列為index(索引)。
          df_1 = pd.pivot_table(data=df_1,values='PJME_MW',index='Datetime',aggfunc='mean').reset_index()
          df_1.sort_values(by='Datetime',inplace=True)
          df_1.set_index('Datetime',inplace=True)
          這樣我們就得到清理后的數據,并且索引為時間戳。我們對df_2 進行同樣的操作,然后進行對比。






          時間序列可視化


          對于時間序列,最常用的plot就是趨勢圖。直接用pandas的plot函數即可,也可以用seaborn的lineplot。這里我們采用兩種方式分別畫出df_1和df_2的趨勢,通過對比我們也可以看到兩種plot方式的細微差別,尤其是對于y軸標簽和圖例默認值的處理上
          # plot data
          fig,ax = plt.subplots(2,1)
          df_1.plot(ax =ax[0])
          sns.lineplot(data=df_1,x=df_1.index,y='PJME_MW',ax=ax[1])

          兩個時間序列的都呈現明顯的周期性,這是可以理解的。因為能源消耗(耗電量)本來就是很人類活動息息相關,自然會和日歷的周期性有一定的吻合。
          當我們把兩個df合并在一起時,就會得到一個多元的時間序列,對于多元的時間序列,相關分析也是最常用的分析方式
          df = pd.concat([df_1,df_2],axis=1)
          sns.scatterplot(x='PJME_MW',y='PJMW_MW',data=df)

          從上圖來看,兩者還是存在明顯的正相關,也就是東區(qū)耗電量增加時,西區(qū)耗電量也增加。






          時間序列重采樣


          對于原始數據來說,時間分辨率是小時。有時候我們需要對數據的分辨率進行調整,比如為了查看每月的耗電量的的情況。因此resample (重采樣)必不可少。
          # resample data
          day_df = df_1.resample(rule='D').mean()
          week_df = df_1.resample(rule='W').mean()
          month_df = df_1.resample(rule='M').mean()
          quarter_df = df_1.resample(rule='Q').mean()
          year_df = df_1.resample(rule='Y').mean()

          print(month_df.info())
          fig,ax = plt.subplots(2,1)
          sns.lineplot(data=df_1,x=df_1.index,y='PJME_MW',ax=ax[0])
          sns.lineplot(data=month_df,x=month_df.index,y='PJME_MW',ax=ax[1])
          常用的周期D,W,M,Q,Y分別代表每天,每周,每月,每季度和每年。我們對比每月重采樣的數據和原始數據。可以看到按月重采樣的曲線更加光滑,這是因為每周和每天的周期信息已經被過濾了

          其實重采樣就是時間序列分解的”思想原型“,通過重采樣我們可以看到每個時間周期的”信號分量“。
          num_ax = 5
          fig,ax = plt.subplots(num_ax,1)
          #[ax[i].set_ylim(10000,22000) for i in range(num_ax)]
          day_df.plot(ax=ax[0])
          week_df.plot(ax=ax[1])
          month_df.plot(ax=ax[2])
          quarter_df.plot(ax=ax[3])
          year_df.plot(ax=ax[4])

          當然了,對于每一種重采樣,后續(xù)采用的統計方式不一定是均值(mean),也可以選擇其他,比如sum(求和)來獲取每月耗電量之和。
          month_sum_df = df_1.resample(rule='M').sum()






          時間切片與索引

          DataFrame數據用時間戳作為索引,最大的好處是可以快速對樣本進行索引和切片。進行索引和切片時,不一定需要完全匹配時間戳的格式,比如,你可以快速索引某個年度的所有樣本。

          print(day_df.loc['2014-02-12']) #獲得某一天的樣本
          print(day_df['2015']) #獲得某一年的額樣本
          print(day_df['2014-02-12':'2014-02-19']) #獲取某個時間段
          #print(day_df['2014-02-12']) !!!這是錯誤示例
          print(month_df.asof('2014-02')) #獲取某一月
          這里需要注意的是:當返回結果只有一個時,無法采用[]進行索引,比如

          #print(day_df['2014-02-12']) !!!這是錯誤示例。因為day_df的每一天只有一個樣本,此時只有iloc可以進行索引。詳細的解釋參考如下。







          時間序列特征工程


          一元時間序列如果需要進行回歸分析或者分類預測,必然需要通過特征工程擴展特征數量,常用的特征工程有三類:
          1. 時間信息的提取

          2. 基于時間窗口的時域統計

          3. 基于時間窗口的頻域統計

          時間信息的提取指的是對時間列進行特征工程,提取時間戳中和人類活動日歷相關的時間信息,比如是否是月末,是否是周末,這是幾月等等。這里列出常用的時間信息的提取。
          # get more datetime attributes
          df_1['day']= df_1.index.day # means which day in this month
          df_1['dayofweek']= df_1.index.dayofweek
          df_1['dayofyear']= df_1.index.dayofyear
          df_1['days_in_month']= df_1.index.days_in_month # how many days in this month
          df_1['daysinmonth']= df_1.index.daysinmonth # same as days_in_month
          df_1['is_month_end']= df_1.index.is_month_end
          df_1['is_month_start']= df_1.index.is_month_start
          df_1['is_quarter_start']= df_1.index.is_quarter_start
          df_1['is_quarter_end']= df_1.index.is_quarter_end
          df_1['month']= df_1.index.month
          df_1['week']= df_1.index.week
          df_1['weekofyear']= df_1.index.weekofyear # same as week
          df_1['year']= df_1.index.year
          df_1['date']= df_1.index.date
          df_1['time']= df_1.index.time
          基于時間窗口的統計分析,可以分析時域分析和頻域分析。頻域分析主要用于高頻時間序列(信號)的分析,比如聲音也算是時間序列。我們先不做講解,這里主要說一下時域分析。
          時域分析很簡單,當一個時間窗口確定后,意味著我們有一段有限長度的時間序列(有限的數據樣本),我們可以進行統計分析,比如求均值,方差,眾數,中位數等等。
          df_1['window_mean']= df_1['PJME_MW'].rolling(window=24,center=True).mean() # it will generate null
          print(df_1.head(24))
          這里采用rolling 函數進行”滾動窗口“,然后對每個滾動窗口內的所有樣本進行求統計均值等操作。需要注意的是,采用滾動窗口的方式,會出現某些樣本的窗口樣本不足指定數量,從而結果為NaN,實踐中需要進行缺失值處理。
          PJME_MW window_mean
          Datetime
          2002-01-01 01:00:00 30393.0 NaN
          2002-01-01 02:00:00 29265.0 NaN
          2002-01-01 03:00:00 28357.0 NaN
          2002-01-01 04:00:00 27899.0 NaN
          2002-01-01 05:00:00 28057.0 NaN
          2002-01-01 06:00:00 28654.0 NaN
          2002-01-01 07:00:00 29308.0 NaN
          2002-01-01 08:00:00 29595.0 NaN
          2002-01-01 09:00:00 29943.0 NaN
          2002-01-01 10:00:00 30692.0 NaN
          2002-01-01 11:00:00 31395.0 NaN
          2002-01-01 12:00:00 31496.0 NaN
          2002-01-01 13:00:00 31031.0 31017.500000
          2002-01-01 14:00:00 30360.0 30922.833333
          2002-01-01 15:00:00 29798.0 30846.666667
          2002-01-01 16:00:00 29720.0 30802.666667
          2002-01-01 17:00:00 31271.0 30787.416667
          2002-01-01 18:00:00 35103.0 30801.916667
          2002-01-01 19:00:00 35732.0 30889.166667
          2002-01-01 20:00:00 35639.0 31114.875000
          2002-01-01 21:00:00 35285.0 31436.458333
          2002-01-01 22:00:00 34007.0 31743.916667
          2002-01-01 23:00:00 31857.0 32008.208333
          2002-01-02 00:00:00 29563.0 32231.666667






          總結


          本文涵蓋了時間序列分析的基本處理操作,包括時間戳的處理,排序,去重,索引與切片等。對于時間序列,可以進行重采樣來滿足特定的分辨率需求,也可以以此查看基本的周期趨勢。一元時間序列可以通過滾動窗口時域分析,時間列信息提取等方法進行特征工程,為最終的機器學習模型做好準備。
          掃描二維碼添加好友↓

          推薦閱讀

          (點擊標題可跳轉閱讀)

          大數據面前,統計學的價值在哪里?

          【AI行業(yè)鄙視鏈大曝光】

          機器學習基礎:可視化方式理解決策樹剪枝

          推薦一款科研必備的Python數據可視化神器

          三連支持,混臉熟,進福利群↓↓

          瀏覽 439
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  草逼小视频 | 蜜桃亚洲无码电影 | 麻豆福利视频 | 特级西西444WWW高清大视频 | www,av手机在线 |