pandas處理時間序列(2):DatetimeIndex、索引和選擇、含有重復索引的時間序列、日期范圍與頻率和移位、時間區間和區間算術


 

一、時間序列基礎

1. 時間戳索引DatetimeIndex

生成20個DatetimeIndex

from datetime import datetime
dates = pd.date_range(start='2019-04-01',periods=20)
dates

 用這20個索引作為ts的索引

ts = pd.Series(np.random.randn(20),index=dates)
ts

不同索引的時間序列之間的算術運算在日期上自動對齊

ts + ts[::2]

pandas使用numpy的datetime64數據類型在納秒級的分辨率下存儲時間戳

ts.index.dtype 

DatetimeIndex中的標量值是pandas的Timestamp對象

stamp =ts.index[0]
stamp

 

2. 索引、選擇

(1) 索引 

ts是一個series;stamp是索引為2的時間戳,Timestamp('2019-04-03 00:00:00', freq='D')

stamp =ts.index[2]

ts[stamp]

 

為了方便,可以傳遞一個能解釋為日期的字符串

(2) 選擇

[1]對於長的時間序列,可以傳遞一個年份或一個年份和月份來選擇數據的切片

longer_ts = pd.Series(np.random.randn(10),index=pd.date_range('4/1/2019',periods=10))
longer_ts

選擇2019年4月份的所有數據

longer_ts.loc['2019-4']#可以寫成'2019/04',不能寫成'201904'

 選擇2019年的所有數據

longer_ts['2019'] 

[2]選擇一段時間內的數據

ts[datetime(2019,1,1):]

ts['1/4/2019':'4/10/2019']

truncate也可以實現在兩個日期間對Series進行切片

ts.truncate(after='4/3/2019')

以上操作也都適用於DataFrame

  

3. 含有重復索引的時間序列

 在某些應用中,可能會有多個數據觀察值落在特定的時間戳中。

dates = pd.DatetimeIndex(['4/1/2019','4/2/2019','4/2/2019','4/2/2019','4/3/2019'])

dup_ts = pd.Series(np.arange(5),index=dates)
dup_ts

通過檢查索引的is_unique屬性,我們可以看出索引並不是唯一的。

dup_ts.index.is_unique

對上面的Series進行索引,結果是標量值還是Series切片取決於是否有時間戳是重復的。

假設你想要聚合含有非唯一時間戳的數據,一種方式就是使用groupby並傳遞level=0

 

二、日期范圍、頻率和移位

  有些應用中經常需要處理固定頻率的場景,例如每日的、每月的或每10分鍾,這意味着我們甚至需要在必要的時候向時間序列中引入缺失值。pandas可以幫助我們重新采樣、推斷頻率以及生成固定頻率的數據范圍。

1. 生成日期范圍pd.date_range()、pd.period_range()

常用函數:

  • pd.date_range()生成的是DatetimeIndex格式的日期序列;
  • pd.period_range(),生成PeriodIndex的時期日期序列。

(1)pd.date_range()

參數:起始時間,結束時間,freq,periods  (四選三)

  開始日期和結束日期嚴格定義了生成日期索引的邊界, 周時間序列,默認以sunday周日作為一周最后一日;若要改成周一作為第一天,freq='W-SAT'

  freq='M'月,'D'天,'W',周,'Y'年。默認情況下,date_range生成的是每日的時間戳,如果只傳遞一個起始或結尾日期,就必須要傳遞一個用於生成范圍的數字,如 “BM” 代表 bussiness end of month

#使用date_range生成日期序列
#如要詳細了解該函數,可以使用help(pd.date_range)
#參數四選三:起始時間,結束時間,freq,periods
#freq='M'月,'D'天,'W',周,'Y'年
#生成月時間序列
dm = pd.date_range('2018/01/01', freq='M', periods=12)
print(f'生成月時間序列:\n{dm}')
#算頭不算尾
#生成年時間序列,默認是以12月結尾,freq='Y-DEC'
dy=pd.date_range('2008-01-01','2019-01-10',freq='Y')
print(f'生成年時間序列:\n{dy}')
#生成日時間序列
dd=pd.date_range('2018-01-01',freq='D',periods=10)
print(f'生成日時間序列:\n{dd}')
#生成周時間序列,默認以sunday周日作為一周最后一日
#如要改成周一作為第一天,freq='W-SAT'
dw=pd.date_range('2018-01-01',freq='W',periods=10)
print(f'生成周時間序列:\n{dw}')

畫以時間為x軸的圖,pandas的DataFrame自動將index列作為x軸
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
#畫以時間為x軸的圖,pandas的DataFrame自動將index列作為x軸
np.random.seed(2)
#生成日期序列
x=pd.date_range('2018/01/01','2019/12/31', freq='d')
#x=pd.period_range('2018/01/01','2019/12/31', freq='d')
#標准正態分布時間序列
y=np.random.standard_normal(len(x))
#將二者轉換為pandas的數據格式
df=pd.DataFrame(y,columns=['標准正態分布'],index=x)
df.plot(figsize=(12,6))
plt.title('模擬標准正態分布隨機數')

ax = plt.gca()  
ax.spines['right'].set_color('none') 
ax.spines['top'].set_color('none')  
plt.show()

  

(2)pd.period_range()

具體period見第五節

#使用period_range生成日期序列
#參數四選三:起始時間,結束時間,freq,periods
#freq='M'月,'D'天,'W',周,'Y'年
#生成月時期序列
dpm = pd.period_range('2019/01/01', freq='M', periods=12)
print(f'生成月時間序列:\n{dpm}')
#生成年時期序列,默認是以12月結尾,freq='Y-DEC'
dpy=pd.period_range('2008-01-01','2019-01-10',freq='Y')
print(f'生成年時間序列:\n{dpy}')
#生成日時期序列
dpd=pd.period_range('2018-01-01',freq='D',periods=10)
print(f'生成日時間序列:\n{dpd}')
#生成周時期序列,默認以sunday周日作為一周最后一日
#如要改成周一作為第一天,freq='W-SAT'
dpw=pd.period_range('2018-01-01',freq='W-SUN',periods=10)
print(f'生成周時間序列:\n{dpw}')

其他的一些freq頻率值,見下圖

有時候會獲得包含時間信息的開始日期或結束日期,但是想要生成的是標准化為零點的時間戳。用normalize=True就可以解決

pd.date_range(start='2019-4-1 12:45:23',periods=5) #不加normalize

pd.date_range(start='2019-4-1 12:45:23',periods=5,normalize=True)

2. 頻率和日期偏置

 pandas中的頻率是由基礎頻率和倍數組成的。基礎頻率通常會有字符串別名,例如'M'代表每月,'H'代表每小時。對於每個基礎頻率,都有一個對象可以被用於定義日期偏置。例如,每小時的頻率可以使用Hour類來表示。

from pandas.tseries.offsets import Hour,Minute
hour = Hour()
hour

four_hours = Hour(4)
four_hours

pd.date_range(start='2019-4-1',periods=5,freq='4h')

pd.date_range(start='2019-4-1',periods=5,freq='1h30min')

月中某星期的日期week of month  

例子:每月第三個星期五  

rng = pd.date_range('2019-4-1','2019-7-5',freq='WOM-3FRI')
list(rng)

3. 移位(前向和后向)日期

   “移位”是指將日期按時間向前移動或向后移動。Series和DataFrame都有一個shift方法用於進行簡單的前向或后向移位,而不改變索引

(1)shift

ts = pd.Series(np.random.randn(4),
              index=pd.date_range('4/1/2019',periods=4,freq='M'))
ts

ts.shift(2)

ts.shift(-2)

由於簡單移位並不改變索引,一些數據會被丟棄。因此,如果頻率是已知的,則可以將頻率傳遞給shift來推移時間戳而不是簡單的數據:

ts.shift(2,freq='D')

ts.shift(2,freq='M') #'M'日歷月末

ts.shift(2,freq='BM') #'BM'月內最后工作日

(2)使用偏置進行移位日期

from pandas.tseries.offsets import Day,MonthEnd
now = datetime.now()
now

now + 3 * Day()

如果添加錨定偏置量,比如MonthEnd,根據頻率規則,第一個增量會將日期“前滾”到下一個日期:

now + MonthEnd()

now + MonthEnd(2)

錨定偏置可以使用rollforwardrollback分別顯示地將日期向前或向后“滾動”;

offset = MonthEnd()
offset.rollforward(now)

offset.rollback(now)

將移位方法與groupby一起使用是日期偏置的一種創造性用法:

ts = pd.Series(np.random.randn(20),index=pd.date_range('4/1/2019',periods=20,freq='4d'))
ts

ts.groupby(offset.rollforward).mean()

resample可以得到同樣的結果

ts.resample('M').mean()

三、時區處理

待用到時候再添加  

  

四、時間區間和區間算術

1. Period、period_range

(1)Period

時間區間Period表示的是時間范圍,比如數日、數月、數季、數年等。

定義一個時間區間Period

p = pd.Period(2019,freq='A-DEC')
p

通過加減整數可以實現對Period的移動

如果兩個Period對象擁有相同頻率,則它們的差就是它們之間的單位數量

pd.Period('2018',freq='A-DEC') - p

(2)period_range

功能:用來生成日期序列
參數:起始時間,結束時間,freq,periods(四選三)
   freq='M'月,'D'天,'W',周,'Y'年
#生成月時期序列
dpm = pd.period_range('2019/01/01', freq='M', periods=12)
print(f'生成時間序列:\n{dpm}')
#生成年時期序列,默認是以12月結尾,freq='Y-DEC'
dpy=pd.period_range('2008-01-01','2019-01-10',freq='Y')
print(f'生成時間序列:\n{dpy}')
#生成日時期序列
dpd=pd.period_range('2018-01-01',freq='D',periods=10)
print(f'生成時間序列:\n{dpd}')
#生成周時期序列,默認以sunday周日作為一周最后一日
#如要改成周一作為第一天,freq='W-SAT'
dpw=pd.period_range('2018-01-01',freq='W-SUN',periods=10)
print(f'生成時間序列:\n{dpw}')

(3)PeriodIndex

PeriodIndex類的構造函數允許直接使用一組字符串表示一段時期

values = ['2001Q3','2002Q2','2003Q1']
index = pd.PeriodIndex(values,freq='Q-DEC')
index

2. 區間頻率轉換

時間序列樣本轉換主要分兩種:即
  • 高頻數據向低頻數據轉換;
  • 低頻數據向高頻數據轉換
應用場景:行情交易數據一般是高頻,基本面一般是月度、季度、年度等低頻數據,量化分析的時候,常常要將基本面數據和行情交易數據結合起來進行統計回歸分析,這時候就要用到樣本數據頻率的轉換了。
主要函數:df.resample(),df代表pandas的DataFrame格式數據,resample方法的參數參數中,freq表示重采樣頻率,例如‘M’、‘5min’,Second(15),用於產生聚合值的函數名或數組函數,例如‘mean’、‘ohlc’、np.max等,默認是‘mean’,其他常用的有:‘first’、‘last’、‘median’、‘max’、‘min’axis=0默認是縱軸,橫軸設置axis=1

(1)asfreq轉換頻率

PeriodPeriodIndex對象可以通過asfreq方法被轉換成別的頻率。

假設有一個年度時期,希望將其轉換為當年年初或年末的一個月度時期:

頻率為‘A-DEC’表示一年的開始到結尾的每一條,'start'表示年初,'end'表示年末

【1】Period

對於一個不以12月結束的財政年度,月度子時期的歸屬情況就不一樣了:

【2】PeriodIndex或TimeSeries的頻率轉換

 

 舉例:頻率轉換

#frq='W'代表周
df=pd.DataFrame(np.random.randn(5,4),
            index=pd.date_range('1/4/2019',periods=5,freq='W'),
            columns=['GZ','BJ','SH','SZ'])
df

低頻數據向高頻數據轉換【周-日】

#將上述樣本轉換為日序列,缺失值使用前值補上
#如使用后值則用bfill()
df_daily=df.resample('D').ffill()
df_daily.head(10)

高頻數據向低頻數據轉化【日-月】

df_daily1=df.resample('M').ffill()
df_daily1.head(10)

根據period來重采樣

#根據period來重采樣
df1=pd.DataFrame(np.random.randn(5,4),
            index=pd.period_range('1/1/2017',periods=5,freq='W'),
            columns=['GZ','BJ','SH','SZ'])
df1.head()

df2=pd.DataFrame(np.random.randn(2,4),
            index=pd.period_range('1-2017','12-2018',freq='A'),
            columns=['GZ','BJ','SH','SZ'])
df2.head()

3. 季度區間頻率

  季度型數據在會計、金融等領域中很常見,許多季度型數據都會涉及“財年末”的概念,通常是一年12個月中某月的最后一個日歷日或工作日。就這一點來說,時期“2012Q4”根據財年末的不同會有不同的含義。pandas支持12種可能的季度型頻率,即Q-JAN到Q-DEC:

  2012Q4指的是2011年第四個季度,也就是2011.11.01-2012-01.31

  在以1月結束的財年中,2012Q4是從11月到1月(將其轉換為日型頻率就明白了)

例如:要獲取該季度倒數第二個工作日下午4點的時間戳:

period_range可以生成季度型范圍。季度型范圍的算術運算也跟上面是一樣的:

 

4. 時間戳Timestamp與Period區間的轉換

(1)to_period()

由於時期指的是非重疊時間區間,因此對於給定的頻率,一個給定的時間戳只能屬於一個時期。新PeriodIndex的頻率默認是從時間戳推斷而來的,你也可以指定任何別的頻率。結果中語序存在重復時期:

(2)to_timestamp()

5. 通過數組創建PeriodIndex

   固定頻率的數據集通常會將時間信息分開存放在多個列中。例如:年度和季度就分布存放在不同的列中:

將這兩個數組以及一個頻率傳入PeriodIndex,就可以將它們合並成DataFrame的一個索引:

 

 

參考文獻:

【1】【手把手教你】Python處理金融數據

【2】Pandas時間序列:時期(period)及其算術運算

【3】pandas 快速處理 date_time 日期格式


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM