YOLO813

Pandas学习-时间序列

    pandas中对于时间的解析使用to_datetime函数,非常智能

pd.to_datetime('20210804')
pd.to_datetime('04/08/2021')
>Timestamp('2021-04-08 00:00:00')

    当我们传入一个列表时,转化出来的就会是一个DatetimeIndex时间索引

pd.to_datetime(['04/08/2021'])
>DatetimeIndex(['2021-04-08'], dtype='datetime64[ns]', freq=None)


    我们可以使用date_range函数生成一个固定频率的DatetimeIndex,看下官方介绍

Signature:
pd.date_range(
    start=None,
    end=None,
    periods=None,
    freq=None,
    tz=None,
    normalize=False,
    name=None,
    closed=None,
    **kwargs,
)
pd.date_range(start='20210601',periods=200,freq='5H')

    

    当我们的数据存在时间索引时,我们就可以定义它为时间序列

data = pd.Series(np.random.randn(100),
                 index=pd.date_range(end='20210804',
                                     periods=100))
data


    取时间序列非常方便,可以用具体的时间取值,也可以切片取值

data['2021-05-01']
data['20210501':'20210511']

    pandas甚至可以了解我们想要用月份来切片,例如

data['2021-05':'2021-06']


    时间序列中的运算会根据对齐的时间索引来进行运算,而未对齐的值会返回一个NA,测试如下

data_test = data[::2]
data_test

data_test + data

 


时间序列重采样

    照例,来看下官网对重采样resample的定义以及参数。

    定义:Resample time-series data,重新采样时间序列数据。从一个频率到另一个频率:降采样,升采样,采样时间点变化。降采样就是比如之前是每天的频率到每月的频率,升采样例如每月的频率到每天,采样时间点变化例如之前是每周五采样,现在需要改成每周三。

Signature:
data.resample(
    rule,
    axis=0,
    closed: 'str | None' = None,
    label: 'str | None' = None,
    convention: 'str' = 'start',
    kind: 'str | None' = None,
    loffset=None,
    base: 'int | None' = None,
    on=None,
    level=None,
    origin: 'str | TimestampConvertibleTypes' = 'start_day',
    offset: 'TimedeltaConvertibleTypes | None' = None,
) -> 'Resampler'
Docstring:
Resample time-series data.


    还是上面的例子:

data


    现在我想要对其进行降采样,由每天的频率变成每月的频率,并取平均值

data.resample(rule='M').mean()

可能你会看到这data数据明明只生成到了2021年8月4号,为何在下面重采样的数据显示到了2021年8月31号,这只是展示形式,实际上算的平均数还是8月1号到8月4号(我已经核算了一遍)。


    例如,现在有一份文件如下:

df.head()

    这里面读取的日期默认是一个普通列对象,现在我想把这份数据变为时间序列,那么首先应该将日期这一列指定为索引!pandas怎么读取csv文件

df = pd.read_csv('./air1908.csv', index_col='Date')
df

    后面的参数还应该增加一个parse_dates参数

df = pd.read_csv('./air1908.csv',
                 index_col=['Date'],
                 parse_dates=True)
df

    此时df.index返回的是一个DatetimeIndex。

    此时我们想计算出每年的着陆人数就很好计算了

df['Ground'].resample('A').sum()

 

股票分析实例

    股票数据来源于开源库tushare,选定的股票代码为洁柔002511,刚好笔者有个表弟最近沉迷于洁柔股票,正好拿来当实例学习下。

import tushare as ts
jr = ts.get_k_data('002511', autype='hfq', ktype='D', start='2018-12-17', end='2021-08-04')
jr

    首先将日期一列转为索引,我们来看下目前的索引和列名

jr.columns
jr.index


    转换索引,我们可以采用两种方法,一种是直接命名法,这种直接就在源数据上修改了

jr.index=jr.date

    另外一种是使用set_index函数,生成一个新的副本,关于set_index函数介绍如下:

Set the DataFrame index using existing columns.
Signature:
jr.set_index(
    keys,
    drop: 'bool' = True,
    append: 'bool' = False,
    inplace: 'bool' = False,
    verify_integrity: 'bool' = False,
)
Docstring:
Set the DataFrame index using existing columns.
jr.set_index('date')

    此时,可以看到,date一列已经作为了索引,看着挺像时间索引,但是绝对不是,我们可以打印出来看下

jr.index

    

    也就是说我们还需要把这一列转换为时间索引,这里可以使用to_datetime函数,本文的第一部分介绍过,可以试一下

pd.to_datetime(jr.index)
jr.index = pd.to_datetime(jr.index)


    此时再按照切片语法取值就很方便了

jr["2019":"2020"]


    假如我现在想要看下它的这几年收盘价,嗯,看着还行

jr.close.plot(figsize=(10,8))


    利用采样看下每一年收盘价的平均值,可以看到我并没有使用groupby等函数聚合年份,仅仅是传入了一个A参数,数据就自动聚合了

jr.close.resample('A').mean()


    单独的选取年份,也很方便

jr.loc['2021'].close.plot(figsize=(14,8))
# 或者直接利用时间序列
# jr.close本身就是一个时间索引
jr.close['2021'].plot(figsize=(14,8))


    如果计算第一天买入,到今天抛出,赚取的利润

(jr.close[-1]-jr.close[0])/jr.close[0]
>1.2971751412429378


    我们也可以利用to_period函数将Series从DatetimeIndex 转换为 PeriodIndex。先来看下原始数据

jr

jr.close.to_period('M')

    可以看到,数据的内容本身不会有任何改变,只是将时间索引作了修改,方便聚合。现在我想得到每个月初的收盘价,

jr.close.to_period('M').groupby(level=0).first()
#等价于
jr.close.to_period('M').groupby('date').first()


    比如想要算出股票的波动率,首先需要知道对数收益率:所有价格取对数后两两之间的差值。

(log(30) - log(20) = log(30/20))
log(a) - log(b) = log(a/b)
jr.close

往后推移一位

jr.close.shift(1)

jr['ds']=np.log(jr.close/jr.close.shift(1))
jr


    绘图如下

jr[['close','ds']].plot(subplots=True, figsize=(14,8))

 

 

参考

https://zhuanlan.zhihu.com/p/35943334