一、時間格式轉(zhuǎn)換
有時候,我們獲得的原始數(shù)據(jù)并不是按照時間類型索引進(jìn)行排列的,需要先進(jìn)行時間格式的轉(zhuǎn)換,為后續(xù)的操作和分析做準(zhǔn)備。
這里介紹兩種方法。第一種方法是用pandas.read_csv導(dǎo)入文件的時候,通過設(shè)置參數(shù)parse_dates和index_col,直接對日期列進(jìn)行轉(zhuǎn)換,并將其設(shè)置為索引。關(guān)于參數(shù)的詳細(xì)解釋。
如下示例中,在沒有設(shè)置參數(shù)之前,可以觀察到數(shù)據(jù)集中的索引是數(shù)字0-208,'date'列的數(shù)據(jù)類型也不是日期。
In [8]: data = pd.read_csv('unemployment.csv')
In [9]: data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 209 entries, 0 to 208
Data columns (total 2 columns):
date 209 non-null object
UNRATE 209 non-null float64
dtypes: float64(1), object(1)
memory usage: 3.3+ KB
設(shè)置參數(shù)parse_dates = ['date'] ,將數(shù)據(jù)類型轉(zhuǎn)換成日期,再設(shè)置 index_col = 'date',將這一列用作索引,結(jié)果如下。
**
In [11]: data = pd.read_csv('unemployment.csv', parse_dates=['date'], index_col='date')
In [12]: data.info()
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 209 entries, 2000-01-01 to 2017-05-01
Data columns (total 1 columns):
UNRATE 209 non-null float64
dtypes: float64(1)
memory usage: 13.3 KB
這時,索引變成了日期'20000101'-'2017-05-01',數(shù)據(jù)類型是datetime。
第二種方法是在已經(jīng)導(dǎo)入數(shù)據(jù)的情況下,用pd.to_datetime()【2】將列轉(zhuǎn)換成日期類型,再用 df.set_index()【3】將其設(shè)置為索引,完成轉(zhuǎn)換。
以tushare.pro上面的日線行情數(shù)據(jù)為例,我們把'trade_date'列轉(zhuǎn)換成日期類型,并設(shè)置成索引。
import tushare as ts
import pandas as pd
pd.set_option('expand_frame_repr', False) # 列太多時不換行
pro = ts.pro_api()
df = pro.daily(ts_code='000001.SZ', start_date='20180701', end_date='20180718')
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 13 entries, 0 to 12
Data columns (total 11 columns):
ts_code 13 non-null object
trade_date 13 non-null object
open 13 non-null float64
high 13 non-null float64
low 13 non-null float64
close 13 non-null float64
pre_close 13 non-null float64
change 13 non-null float64
pct_chg 13 non-null float64
vol 13 non-null float64
amount 13 non-null float64
dtypes: float64(9), object(2)
memory usage: 1.2+ KB
None
df['trade_date'] = pd.to_datetime(df['trade_date'])
df.set_index('trade_date', inplace=True)
df.sort_values('trade_date', ascending=True, inplace=True) # 升序排列
df.info()
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 13 entries, 2018-07-02 to 2018-07-18
Data columns (total 10 columns):
ts_code 13 non-null object
open 13 non-null float64
high 13 non-null float64
low 13 non-null float64
close 13 non-null float64
pre_close 13 non-null float64
change 13 non-null float64
pct_chg 13 non-null float64
vol 13 non-null float64
amount 13 non-null float64
dtypes: float64(9), object(1)
memory usage: 1.1+ KB
打印出前5行,效果如下。
df.head()
Out[15]:
ts_code open high low close pre_close change pct_chg vol amount
trade_date
2018-07-02 000001.SZ 9.05 9.05 8.55 8.61 9.09 -0.48 -5.28 1315520.13 1158545.868
2018-07-03 000001.SZ 8.69 8.70 8.45 8.67 8.61 0.06 0.70 1274838.57 1096657.033
2018-07-04 000001.SZ 8.63 8.75 8.61 8.61 8.67 -0.06 -0.69 711153.37 617278.559
2018-07-05 000001.SZ 8.62 8.73 8.55 8.60 8.61 -0.01 -0.12 835768.77 722169.579
2018-07-06 000001.SZ 8.61 8.78 8.45 8.66 8.60 0.06 0.70 988282.69 852071.526
02
時間周期轉(zhuǎn)換
在完成時間格式轉(zhuǎn)換之后,我們就可以進(jìn)行后續(xù)的日期操作了。下面介紹一下如何對時間序列數(shù)據(jù)進(jìn)行重采樣resampling。
重采樣指的是將時間序列從?個頻率轉(zhuǎn)換到另?個頻率的處理過程。將?頻率數(shù)據(jù)聚合到低頻率稱為降采樣downsampling,如將股票的日線數(shù)據(jù)轉(zhuǎn)換成周線數(shù)據(jù),?將低頻率數(shù)據(jù)轉(zhuǎn)換到?頻率則稱為升采樣upsampling,如將股票的周線數(shù)據(jù)轉(zhuǎn)換成日線數(shù)據(jù)。
降采樣:以日線數(shù)據(jù)轉(zhuǎn)換周線數(shù)據(jù)為例。繼續(xù)使用上面的tushare.pro日線行情數(shù)據(jù),選出特定的幾列。
df = df[['ts_code', 'open', 'high', 'low', 'close', 'vol']] # 單位:成交量 (手)
ts_code open high low close vol
trade_date
2018-07-02 000001.SZ 9.05 9.05 8.55 8.61 1315520.13
2018-07-03 000001.SZ 8.69 8.70 8.45 8.67 1274838.57
2018-07-04 000001.SZ 8.63 8.75 8.61 8.61 711153.37
2018-07-05 000001.SZ 8.62 8.73 8.55 8.60 835768.77
2018-07-06 000001.SZ 8.61 8.78 8.45 8.66 988282.69
2018-07-09 000001.SZ 8.69 9.03 8.68 9.03 1409954.60
2018-07-10 000001.SZ 9.02 9.02 8.89 8.98 896862.02
2018-07-11 000001.SZ 8.76 8.83 8.68 8.78 851296.70
2018-07-12 000001.SZ 8.60 8.97 8.58 8.88 1140492.31
2018-07-13 000001.SZ 8.92 8.94 8.82 8.88 603378.21
2018-07-16 000001.SZ 8.85 8.90 8.69 8.73 689845.58
2018-07-17 000001.SZ 8.74 8.75 8.66 8.72 375356.33
2018-07-18 000001.SZ 8.75 8.85 8.69 8.70 525152.77
為了方便大家觀察,把這段時間的日歷附在下面,'2018-07-02'正好是星期一。

轉(zhuǎn)換的思路是這樣的,以日歷中的周進(jìn)行聚合,如'20180702'-'20180708',取該周期內(nèi),日線開盤價的第一個值作為周開盤價,日線最高價的最大值作為周最高價,日線最低價的最小值作為周最低價,日線收盤價的最后一個值作為周最收盤價,日線最高價的最大值作為周最高價,日線成交量的求和作為周成交量(手),如下圖黃色方框所示。

我們可以通過.resample()【4】方法實現(xiàn)上述操作,對DataFrame和Series都適用。其中,參數(shù)rule設(shè)置需要轉(zhuǎn)換成的頻率,'1W'是一周。
具體轉(zhuǎn)換的代碼如下,日期默認(rèn)為本周的星期日,如果周期內(nèi)數(shù)據(jù)不全,如'20180722'這周只有3行數(shù)據(jù),也會按照上述方法進(jìn)行轉(zhuǎn)換。
freq = '1W'
df_weekly = df[['open']].resample(rule=freq).first()
df_weekly['high'] = df['high'].resample(rule=freq).max()
df_weekly['low'] = df['low'].resample(rule=freq).min()
df_weekly['close'] = df['close'].resample(rule=freq).last()
df_weekly['vol'] = df['vol'].resample(rule=freq).sum()
df_weekly
Out[33]:
open high low close vol
trade_date
2018-07-08 9.05 9.05 8.45 8.66 5125563.53
2018-07-15 8.69 9.03 8.58 8.88 4901983.84
2018-07-22 8.85 8.90 8.66 8.70 1590354.68
升采樣:以周線數(shù)據(jù)轉(zhuǎn)換日線數(shù)據(jù)為例。繼續(xù)使用上面剛剛轉(zhuǎn)換好的周線數(shù)據(jù),我們再試著把它轉(zhuǎn)換成日線數(shù)據(jù)。先通過.resample('D').asfreq()【5】方法,將周線數(shù)據(jù)的頻率轉(zhuǎn)換成日線,效果如下。
df_daily = df_weekly.resample('D').asfreq()
print(df_daily)
Out[52]:
open high low close vol
trade_date
2018-07-08 9.05 9.05 8.45 8.66 5125563.53
2018-07-09 NaN NaN NaN NaN NaN
2018-07-10 NaN NaN NaN NaN NaN
2018-07-11 NaN NaN NaN NaN NaN
2018-07-12 NaN NaN NaN NaN NaN
2018-07-13 NaN NaN NaN NaN NaN
2018-07-14 NaN NaN NaN NaN NaN
2018-07-15 8.69 9.03 8.58 8.88 4901983.84
2018-07-16 NaN NaN NaN NaN NaN
2018-07-17 NaN NaN NaN NaN NaN
2018-07-18 NaN NaN NaN NaN NaN
2018-07-19 NaN NaN NaN NaN NaN
2018-07-20 NaN NaN NaN NaN NaN
2018-07-21 NaN NaN NaN NaN NaN
2018-07-22 8.85 8.90 8.66 8.70 1590354.68
結(jié)果中出現(xiàn)了很多空值,需要我們按照一定的方法進(jìn)行填充,可以通過添加.ffill()或者.bfill()實現(xiàn)。
其中,.ffill()代表用前值進(jìn)行填充,也就是用前面的非空值對后面的NaN值進(jìn)行填充,如'20180709'-20180714' 的NaN值都等于'20180708'這一行的非空值,效果如下。
df_daily = df_weekly.resample('D').ffill()
df_daily
Out[54]:
open high low close vol
trade_date
2018-07-08 9.05 9.05 8.45 8.66 5125563.53
2018-07-09 9.05 9.05 8.45 8.66 5125563.53
2018-07-10 9.05 9.05 8.45 8.66 5125563.53
2018-07-11 9.05 9.05 8.45 8.66 5125563.53
2018-07-12 9.05 9.05 8.45 8.66 5125563.53
2018-07-13 9.05 9.05 8.45 8.66 5125563.53
2018-07-14 9.05 9.05 8.45 8.66 5125563.53
2018-07-15 8.69 9.03 8.58 8.88 4901983.84
2018-07-16 8.69 9.03 8.58 8.88 4901983.84
2018-07-17 8.69 9.03 8.58 8.88 4901983.84
2018-07-18 8.69 9.03 8.58 8.88 4901983.84
2018-07-19 8.69 9.03 8.58 8.88 4901983.84
2018-07-20 8.69 9.03 8.58 8.88 4901983.84
2018-07-21 8.69 9.03 8.58 8.88 4901983.84
2018-07-22 8.85 8.90 8.66 8.70 1590354.68
同理,.bfill()代表用后值對空值進(jìn)行填充,效果如下。
df_daily = df_weekly.resample('D').bfill()
df_daily
Out[55]:
open high low close vol
trade_date
2018-07-08 9.05 9.05 8.45 8.66 5125563.53
2018-07-09 8.69 9.03 8.58 8.88 4901983.84
2018-07-10 8.69 9.03 8.58 8.88 4901983.84
2018-07-11 8.69 9.03 8.58 8.88 4901983.84
2018-07-12 8.69 9.03 8.58 8.88 4901983.84
2018-07-13 8.69 9.03 8.58 8.88 4901983.84
2018-07-14 8.69 9.03 8.58 8.88 4901983.84
2018-07-15 8.69 9.03 8.58 8.88 4901983.84
2018-07-16 8.85 8.90 8.66 8.70 1590354.68
2018-07-17 8.85 8.90 8.66 8.70 1590354.68
2018-07-18 8.85 8.90 8.66 8.70 1590354.68
2018-07-19 8.85 8.90 8.66 8.70 1590354.68
2018-07-20 8.85 8.90 8.66 8.70 1590354.68
2018-07-21 8.85 8.90 8.66 8.70 1590354.68
2018-07-22 8.85 8.90 8.66 8.70 1590354.68
03
時間窗口函數(shù)
當(dāng)我們想要比較數(shù)據(jù)在相同時間窗口的不同特征和變化時,可以借助窗口函數(shù)rolling【6】進(jìn)行計算。
看一個實例:計算股票收盤價的移動平均值。
df = df[['ts_code', 'close']]
df
Out[58]:
ts_code close
trade_date
2018-07-02 000001.SZ 8.61
2018-07-03 000001.SZ 8.67
2018-07-04 000001.SZ 8.61
2018-07-05 000001.SZ 8.60
2018-07-06 000001.SZ 8.66
2018-07-09 000001.SZ 9.03
2018-07-10 000001.SZ 8.98
2018-07-11 000001.SZ 8.78
2018-07-12 000001.SZ 8.88
2018-07-13 000001.SZ 8.88
2018-07-16 000001.SZ 8.73
2018-07-17 000001.SZ 8.72
2018-07-18 000001.SZ 8.70
調(diào)用rolling函數(shù),通過設(shè)置參數(shù)window的值規(guī)定窗口大小,這里設(shè)置為3,并且調(diào)用.mean()方法計算窗口期為3天的均值,結(jié)果如下。
其中,'20180704'當(dāng)天的平均值等于'20180702'-'20180704'三天的收盤價取平均的結(jié)果,'20180705'當(dāng)天的平均值等于'20180703'-'20180705'三天的收盤價取平均的結(jié)果,以此類推。
df['MA3'] = df['close'].rolling(3).mean()
df
Out[76]:
ts_code close MA3
trade_date
2018-07-02 000001.SZ 8.61 NaN
2018-07-03 000001.SZ 8.67 NaN
2018-07-04 000001.SZ 8.61 8.630000
2018-07-05 000001.SZ 8.60 8.626667
2018-07-06 000001.SZ 8.66 8.623333
2018-07-09 000001.SZ 9.03 8.763333
2018-07-10 000001.SZ 8.98 8.890000
2018-07-11 000001.SZ 8.78 8.930000
2018-07-12 000001.SZ 8.88 8.880000
2018-07-13 000001.SZ 8.88 8.846667
2018-07-16 000001.SZ 8.73 8.830000
2018-07-17 000001.SZ 8.72 8.776667
2018-07-18 000001.SZ 8.70 8.716667
還有一個常用的窗口函數(shù)是expanding,每增加一行數(shù)據(jù),窗口會相應(yīng)的增大。比如,我們想計算某只股票每天的累計漲跌幅,就可以調(diào)用此函數(shù)。
df = df[['ts_code', 'pct_chg']] # 列pct_chg單位是(%)
Out[71]:
ts_code pct_chg
trade_date
2018-07-02 000001.SZ -5.28
2018-07-03 000001.SZ 0.70
2018-07-04 000001.SZ -0.69
2018-07-05 000001.SZ -0.12
2018-07-06 000001.SZ 0.70
2018-07-09 000001.SZ 4.27
2018-07-10 000001.SZ -0.55
2018-07-11 000001.SZ -2.23
2018-07-12 000001.SZ 2.78
2018-07-13 000001.SZ 0.00
2018-07-16 000001.SZ -1.69
2018-07-17 000001.SZ -0.11
2018-07-18 000001.SZ -0.23
對列'pct_chg'調(diào)用窗口函數(shù)expanding,再調(diào)用.sum()方法求累計值。
df['cum_pct_chg'] = df['pct_chg'].expanding().sum()
df
Out[78]:
ts_code pct_chg cum_pct_chg
trade_date
2018-07-02 000001.SZ -5.28 -5.28
2018-07-03 000001.SZ 0.70 -4.58
2018-07-04 000001.SZ -0.69 -5.27
2018-07-05 000001.SZ -0.12 -5.39
2018-07-06 000001.SZ 0.70 -4.69
2018-07-09 000001.SZ 4.27 -0.42
2018-07-10 000001.SZ -0.55 -0.97
2018-07-11 000001.SZ -2.23 -3.20
2018-07-12 000001.SZ 2.78 -0.42
2018-07-13 000001.SZ 0.00 -0.42
2018-07-16 000001.SZ -1.69 -2.11
2018-07-17 000001.SZ -0.11 -2.22
2018-07-18 000001.SZ -0.23 -2.45
總結(jié)
本文介紹了Pandas庫中處理時間序列數(shù)據(jù)的幾種常用方法。
在時間格式轉(zhuǎn)換部分,介紹了兩種將時間轉(zhuǎn)化成日期類型的方法,分別是通過設(shè)置參數(shù)parse_dates和調(diào)用方法pd.to_datetime()。
接著,介紹了時間周期的轉(zhuǎn)換,通過調(diào)用.resample()方法實現(xiàn),包括降采樣和升采樣。
最后,介紹兩個常用的窗口函數(shù)rolling和expanding。
希望大家能靈活掌握本文中提到的方法,并應(yīng)用到實際工作和學(xué)習(xí)中去!