基礎概述
下面列出了 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訪問屬性
我們可以通過 Timestamp 或 DateTimeIndex 訪問一些時間/日期的屬性。這里列舉一些常見的,想要查看所有的屬性見官方鏈接: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