2020-08-06--Pandas-06--時間序列詳解

基礎概述

下面列出了 Pandas中 和時間日期相關常用的類以及創(chuàng)建方法。

備注 創(chuàng)建方法
Timestamp 時刻數(shù)據 to_datetime,Timestamp
DatetimeIndex Timestamp的索引 to_datetime,date_range,DatetimeIndex
Period 時期數(shù)據 Period
PeriodIndex Period period_range,PeriodIndex

Pandas 中關于時間序列最常見的類型就是時間戳(Timestamp)了,創(chuàng)建時間戳的方法有很多種,我們分別來看一看。

time = pd.Timestamp(2018, 5, 21)
print(time)
# 2018-05-21 00:00:00
time = pd.Timestamp("2018-5-21")
print(time)
# 2018-05-21 00:00:00

除了時間戳之外,另一個常見的結構是時間跨度(Period)。

periods = pd.Period("2018-01")
print(periods)
# 2018-01
periods = pd.Period("2018-05", freq="D")
print(periods)
# 2018-05-01

Timestamp 和 Period 可以是索引。將Timestamp 和 Period 作為 Series 或 DataFrame的索引后會自動強制轉為為 DatetimeIndex 和 PeriodIndex。

dates = [pd.Timestamp("2018-05-01"), pd.Timestamp("2018-05-02"), pd.Timestamp("2018-05-03"), pd.Timestamp("2018-05-04")]
ts = pd.Series(data=["Tom", "Bob", "Mary", "James"], index=dates)
print(ts)
# 2018-05-01      Tom
# 2018-05-02      Bob
# 2018-05-03     Mary
# 2018-05-04    James
# dtype: object
print(ts.index)
# DatetimeIndex(['2018-05-01', '2018-05-02', '2018-05-03', '2018-05-04'], dtype='datetime64[ns]', freq=None)

periods = [pd.Period("2018-01"), pd.Period("2018-02"), pd.Period("2018-03"), pd.Period("2018-4")]
ts = pd.Series(data=["Tom", "Bob", "Mary", "James"], index=periods)
print(ts)
# 2018-01      Tom
# 2018-02      Bob
# 2018-03     Mary
# 2018-04    James
# Freq: M, dtype: object
print(ts.index)
# PeriodIndex(['2018-01', '2018-02', '2018-03', '2018-04'], dtype='period[M]', freq='M')

轉換時間戳

你可能會想到,我們經常要和文本數(shù)據(字符串)打交道,能否快速將文本數(shù)據轉為時間戳呢?

答案是可以的,通過 to_datetime 能快速將字符串轉換為時間戳。當傳遞一個Series時,它會返回一個Series(具有相同的索引)。

timeSeries = pd.to_datetime(pd.Series(["Jul 31, 2018", "2018-05-10", None]))
print(timeSeries)
# 0   2018-07-31
# 1   2018-05-10
# 2          NaT
# dtype: datetime64[ns]

而傳遞一個list列表的則轉換為DatetimeIndex。

timeList = pd.to_datetime(["2005/11/23", "2010.12.31"])
print(timeList)
# DatetimeIndex(['2005-11-23', '2010-12-31'], dtype='datetime64[ns]', freq=None)

unix轉換時間戳

除了可以將文本數(shù)據轉為時間戳外,還可以將 unix 時間轉為時間戳。

sunixTime = pd.to_datetime([1349720105, 1349806505, 1349892905], unit="s")
print(sunixTime)
# DatetimeIndex(['2012-10-08 18:15:05', '2012-10-09 18:15:05',
#                '2012-10-10 18:15:05'],
#               dtype='datetime64[ns]', freq=None)

msunixTime = pd.to_datetime([1349720105100, 1349720105200, 1349720105300], unit="ms")
print(msunixTime)
# DatetimeIndex(['2012-10-08 18:15:05.100000', '2012-10-08 18:15:05.200000',
#                '2012-10-08 18:15:05.300000'],
#               dtype='datetime64[ns]', freq=None)

unix的單位可以是s,也可以是ms。該數(shù)值是從1970-1-1日開始計算的,通常獲取時間最先獲取的數(shù)值就是unix值,所以用的還是比較多的。

生成時間戳范圍

有時候,我們可能想要生成某個范圍內的時間戳。例如,我想要生成 "2018-6-26" 這一天之后的8天時間戳,如何完成呢?我們可以使用 date_range 和 bdate_range 來完成時間戳范圍的生成。

  • date_range 默認使用的頻率是 日歷日
  • bdate_range 默認使用的頻率是 營業(yè)日
data_range = pd.date_range("2018-6-26", periods=8)
print(data_range)
# DatetimeIndex(['2018-06-26', '2018-06-27', '2018-06-28', '2018-06-29',
#                '2018-06-30', '2018-07-01', '2018-07-02', '2018-07-03'],
#               dtype='datetime64[ns]', freq='D')

bdate_range = pd.bdate_range("2018-6-26", periods=8)
print(bdate_range)
# DatetimeIndex(['2018-06-26', '2018-06-27', '2018-06-28', '2018-06-29',
#                '2018-07-02', '2018-07-03', '2018-07-04', '2018-07-05'],
#               dtype='datetime64[ns]', freq='B')

當然了,我們可以自己指定頻率.

比如,我們可以按周來生成時間戳范圍。

week = pd.date_range("2018-6-26", periods=8, freq="W")
print(week)
# DatetimeIndex(['2018-07-01', '2018-07-08', '2018-07-15', '2018-07-22',
#                '2018-07-29', '2018-08-05', '2018-08-12', '2018-08-19'],
#               dtype='datetime64[ns]', freq='W-SUN')

顯示的是7-01后的每周的周日。

DataTimeIndex---時間索引

在上邊,當Timestamp 和 Period 作為 Series 或 DataFrame的索引后會自動強制轉為為 DatetimeIndex 和 PeriodIndex。

所以DatetimeIndex 的主要作用是之一是用作 Pandas 對象的索引,使用它作為索引除了擁有普通索引對象的所有基本功能外,還擁有簡化頻率處理的高級時間序列方法。

首先創(chuàng)建一個時間戳作為索引的Series對象

# 創(chuàng)建時間戳作為索引的Series對象
rng = pd.date_range("2018-6-24", periods=4, freq="W")
ts = pd.Series(range(len(rng)), index=rng)
print(ts)
# 2018-06-24    0
# 2018-07-01    1
# 2018-07-08    2
# 2018-07-15    3
# Freq: W-SUN, dtype: int64

訪問數(shù)據

通過日期訪問數(shù)據

data  =ts['2018-06-24']
print(data)      # 0
切片訪問

切片操作時前開后開的。

data1 = ts["2018-07-08": "2018-07-22"]
print(data1)
# 2018-07-08    2
# 2018-07-15    3
# Freq: W-SUN, dtype: int64
print(type(data1))
# <class 'pandas.core.series.Series'>

返回的是Series對象類型。

年份訪問

data2 = ts['2018']
print(data2)
# 2018-06-24    0
# 2018-07-01    1
# 2018-07-08    2
# 2018-07-15    3
# Freq: W-SUN, dtype: int64

會把該年份中的所有數(shù)據全部查出來。

使用datetime類型進行 數(shù)據訪問

除了可以使用字符串對 DateTimeIndex 進行索引外,還可以使用 datetime(日期時間)對象來進行索引。

from datetime import datetime

c = ts[datetime(2018, 7, 8) : datetime(2018, 7, 22)]
print(c)
# 2018-07-08    2
# 2018-07-15    3
# Freq: W-SUN, dtype: int64

根據DateTimeIndex或Timestamp訪問屬性

我們可以通過 TimestampDateTimeIndex 訪問一些時間/日期的屬性。這里列舉一些常見的,想要查看所有的屬性見官方鏈接:Time/Date Components(http://pandas.pydata.org/pandas-docs/stable/timeseries.html#time-date-components)

獲取所有數(shù)據的年份:

year = ts.index.year
print(year)
# Int64Index([2018, 2018, 2018, 2018], dtype='int64')

獲取索引是星期幾

week = ts.index.dayofweek
print(week)
# Int64Index([6, 6, 6, 6], dtype='int64')

獲取一年中的第幾周

weeknum = ts.index.isocalendar()
print(weeknum)
#             year  week  day
# 2018-06-24  2018    25    7
# 2018-07-01  2018    26    7
# 2018-07-08  2018    27    7
# 2018-07-15  2018    28    7

DateOffset對象

DateOffset 從名稱中就可以看出來是要做日期偏移的,
工作方式如下:

from pandas.tseries.offsets import *
d = pd.Timestamp("2018-06-25")
d = d + DateOffset(weeks=2, days=5)
print(d)
# 2018-07-14 00:00:00

除了可以使用 DateOffset 完成上面的功能外,還可以使用偏移量實例來完成。

print(d)
# 2018-07-14 00:00:00

d = d + Week(2) + Day(5)
print(d)
# 2018-08-02 00:00:00

與時間序列相關的方法

在做時間序列相關的工作時,經常要對時間做一些移動/滯后、頻率轉換、采樣等相關操作,我們來看下這些操作如何使用吧。

1.移動

如果你想移動或滯后時間序列的數(shù)據部分,你可以使用 shift 方法。

ts = ts.shift(2)
print(ts)
# 2018-06-24    NaN
# 2018-07-01    NaN
# 2018-07-08    0.0
# 2018-07-15    1.0
# Freq: W-SUN, dtype: float64

可以看到,Series 所有的值都都移動了 2 個距離。如果不想移動值,而是移動日期索引,可以使用 freq 參數(shù)

c = ts.shift(2,freq=Day())
print(c)
# 2018-06-26    0
# 2018-07-03    1
# 2018-07-10    2
# 2018-07-17    3
# dtype: int64

可以看到,現(xiàn)在日期索引移動了 2 天的間隔。通過 tshift 同樣可以達到相同的效果。

c = ts.tshift(2,freq=Day())
print(c)
# 2018-06-26    0
# 2018-07-03    1
# 2018-07-10    2
# 2018-07-17    3
# dtype: int64

但是建議使用shift()進行移動。

2.頻率轉換

asfrea()

頻率轉換可以使用 asfreq 函數(shù)來實現(xiàn)。下面演示了將頻率由周轉為了天。

print(ts)
# 2018-06-24    0
# 2018-07-01    1
# 2018-07-08    2
# 2018-07-15    3
# Freq: W-SUN, dtype: int64
ts = ts.asfreq(Day())
print(ts)
# 2018-06-24    0.0
# 2018-06-25    NaN
# 2018-06-26    NaN
# 2018-06-27    NaN
# 2018-06-28    NaN
# 2018-06-29    NaN
# 2018-06-30    NaN
# 2018-07-01    1.0
# 2018-07-02    NaN
# 2018-07-03    NaN
# 2018-07-04    NaN
# 2018-07-05    NaN
# 2018-07-06    NaN
# 2018-07-07    NaN
# 2018-07-08    2.0
# 2018-07-09    NaN
# 2018-07-10    NaN
# 2018-07-11    NaN
# 2018-07-12    NaN
# 2018-07-13    NaN
# 2018-07-14    NaN
# 2018-07-15    3.0
# Freq: D, dtype: float64

聰明的你會發(fā)現(xiàn)出現(xiàn)了缺失值,因此 Pandas 為你提供了 method 參數(shù)來填充缺失值。幾種不同的填充方法參考 Pandas 缺失值處理)) 中 fillna 介紹。

print(ts)
# 2018-06-24    0
# 2018-07-01    1
# 2018-07-08    2
# 2018-07-15    3
# Freq: W-SUN, dtype: int64
ts = ts.asfreq(Day(),method='ffill')
print(ts)
# 2018-06-24    0
# 2018-06-25    0
# 2018-06-26    0
# 2018-06-27    0
# 2018-06-28    0
# 2018-06-29    0
# 2018-06-30    0
# 2018-07-01    1
# 2018-07-02    1
# 2018-07-03    1
# 2018-07-04    1
# 2018-07-05    1
# 2018-07-06    1
# 2018-07-07    1
# 2018-07-08    2
# 2018-07-09    2
# 2018-07-10    2
# 2018-07-11    2
# 2018-07-12    2
# 2018-07-13    2
# 2018-07-14    2
# 2018-07-15    3
# Freq: D, dtype: int64

重采樣

resample 表示根據日期維度進行數(shù)據聚合,可以按照分鐘、小時、工作日、周、月、年等來作為日期維度,更多的日期維度見 Offset Aliases(http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases)。

這里我們先以月來作為時間維度來進行聚合。

求出每個月和每周數(shù)據的總和:

print(c)
# 2018-06-24    0
# 2018-06-25    0
# 2018-06-26    0
# 2018-06-27    0
# 2018-06-28    0
# 2018-06-29    0
# 2018-06-30    0
# 2018-07-01    1
# 2018-07-02    1
# 2018-07-03    1
# 2018-07-04    1
# 2018-07-05    1
# 2018-07-06    1
# 2018-07-07    1
# 2018-07-08    2
# 2018-07-09    2
# 2018-07-10    2
# 2018-07-11    2
# 2018-07-12    2
# 2018-07-13    2
# 2018-07-14    2
# 2018-07-15    3
# Freq: D, dtype: int64

re = c.resample('1M').sum()
print(re)
# 2018-06-30     0
# 2018-07-31    24
# Freq: M, dtype: int64

re = c.resample('1W').sum()
print(re)
# 2018-06-24     0
# 2018-07-01     1
# 2018-07-08     8
# 2018-07-15    15
# Freq: W-SUN, dtype: int64

求出每個月和每周數(shù)據的平均值:

re = c.resample("1M").mean()
print(re)
# 2018-06-30    0.0
# 2018-07-31    1.6
# Freq: M, dtype: float64

re = c.resample("1W").mean()
print(re)
# 2018-06-24    0.000000
# 2018-07-01    0.142857
# 2018-07-08    1.142857
# 2018-07-15    2.142857
# Freq: W-SUN, dtype: float64
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容