Numpy&pandas(六)--datetime

import pandas as pd
import numpy as np

时间日期

  • 时间戳 tiimestamp:固定的时刻 -> pd.Timestamp
  • 固定时期 period:比如 2016年3月份,再如2015年销售额 -> pd.Period
  • 时间间隔 interval:由起始时间和结束时间来表示,固定时期是时间间隔的一个特殊

时间日期在 Pandas 里的作用

  • 分析金融数据,如股票交易数据
  • 分析服务器日志

Python datetime

python 标准库里提供了时间日期的处理。这个是时间日期的基础。

from datetime import datetime
from datetime import timedelta
now = datetime.now()
#输出当前年月日时分秒,还有秒的下一个计量单位

now.year, now.month, now.day
#输出当前年月日

时间差

date1 = datetime(2016, 3, 20)
date2 = datetime(2016, 3, 16)
delta = date1 - date2
#输出timedelta是4,默认为day

delta.days
#输出4

delta.total_seconds()
#转换成秒

date2 + delta
#输出一个datetime2016 3 20 0 0

date2 + timedelta(4.5)
#输出一个datetime2016 3 20 12 0

字符串和 datetime 转换

关于 datetime 格式定义,可以参阅 python 官方文档

date = datetime(2016, 3, 20, 8, 30)
str(date)
#变成字符串'2016-03-20 08:30:00'

date.strftime('%Y-%m-%d %H:%M:%S')
#可以自定义格式'2016-03-20 08:30:00'

datetime.strptime('2016-03-20 09:30', '%Y-%m-%d %H:%M')
#字符串转换为时间类型

Pandas 里的时间序列

Pandas 里使用 Timestamp 来表达时间

dates = [datetime(2016, 3, 1), datetime(2016, 3, 2), datetime(2016, 3, 3), datetime(2016, 3, 4)]
s = pd.Series(np.random.randn(4), index=dates)
type(s.index)
#输出pandas.tseries.index.DatetimeIndex

type(s.index[0])
#输出的是timestamp

日期范围

生成日期范围

pd.date_range('20160320', '20160331')
#生成DatetimeIndex(['2016-03-20', '2016-03-21', '2016-03-22', '2016-03-23',
#               '2016-03-24', '2016-03-25', '2016-03-26', '2016-03-27',
#              '2016-03-28', '2016-03-29', '2016-03-30', '2016-03-31'],
#             dtype='datetime64[ns]', freq='D')
#freq = D表示天,可以自己改动

pd.date_range(start='20160320', periods=10)
#和上面差不多,但是数量为十天

## 规则化时间戳
pd.date_range(start='2016-03-20 16:23:32', periods=10, normalize=True)

时间频率

## 星期
pd.date_range(start='20160320', periods=10, freq='W')

# 月
pd.date_range(start='20160320', periods=10, freq='M')

## 每个月最后一个工作日组成的索引
pd.date_range(start='20160320', periods=10, freq='BM')

# 小时
pd.date_range(start='20160320', periods=10, freq='4H')

时期及算术运算

pd.Period 表示时期,比如几日,月或几个月等。比如用来统计每个月的销售额,就可以用时期作为单位。

p1 = pd.Period(2010)
p2 = p1 + 2
#输出2012年


p2 - p1
#输出2L

p1 = pd.Period(2016, freq='M')
#输出2016-01

p1 + 3
#输出Period('2016-04', 'M')

时期序列

pd.period_range(start='2016-01', periods=12, freq='M')
'''输出结果为
    PeriodIndex(['2016-01', '2016-02', '2016-03', '2016-04', '2016-05', '2016-06',
             '2016-07', '2016-08', '2016-09', '2016-10', '2016-11', '2016-12'],
            dtype='int64', freq='M')
'''

pd.period_range(start='2016-01', end='2016-10', freq='M')
#输出1~10月

# 直接用字符串,输出季度
index = pd.PeriodIndex(['2016Q1', '2016Q2', '2016Q3'], freq='Q-DEC')

时期的频率转换

asfreq

  • A-DEC: 以 12 月份作为结束的年时期
  • A-NOV: 以 11 月份作为结束的年时期
  • Q-DEC: 以 12 月份作为结束的季度时期

p = pd.Period('2016', freq='A-DEC')
#输出以12月为一年结束的时间,2016

p.asfreq('M', how='start')
#重新取freq,变成月份

p.asfreq('M', how='end')
#同上输出为12月

p = pd.Period('2016-04', freq='M')
#时间序列

p.asfreq('A-DEC')
#变换为年,以十二月为结束,所以是2016

# 以年为周期,以一年中的 3 月份作为年的结束(财年)输出为2017年
p.asfreq('A-MAR')

季度时间频率

Pandas 支持 12 种季度型频率,从 Q-JAN 到 Q-DEC

p = pd.Period('2016Q4', 'Q-JAN')
#2016年一月份为第四季度

# 以 1 月份结束的财年中,2016Q4 的时期是指 2015-11-1 到 2016-1-31
p.asfreq('D', how='start'), p.asfreq('D', how='end')

# 获取该季度倒数第二个工作日下午4点的时间戳
p4pm = (p.asfreq('B', how='end') - 1).asfreq('T', 'start') + 16 * 60

# 转换为 timestamp
p4pm.to_timestamp()
#Timestamp('2016-01-28 16:00:00')

Timestamp 和 Period 相互转换

ts = pd.Series(np.random.randn(5), index = pd.date_range('2016-01-01', periods=5, freq='M'))
ts.to_period()
#由timestamp转换成period

ts = pd.Series(np.random.randn(5), index = pd.date_range('2016-12-29', periods=5, freq='D'))
pts = ts.to_period(freq='M')
#由天转换成月

pts.groupby(level=0).sum()

# 转换为时间戳时,细部时间会丢失
pts.to_timestamp(how='end')

重采样

  • 高频率 -> 低频率 -> 降采样:5 分钟股票交易数据转换为日交易数据
  • 低频率 -> 高频率 -> 升采样
  • 其他重采样:每周三 (W-WED) 转换为每周五 (W-FRI)
ts = pd.Series(np.random.randint(0, 50, 60), index=pd.date_range('2016-04-25 09:30', periods=60, freq='T'))

# 0-4 分钟为第一组,显示的是从9:30开始
ts.resample('5min', how='sum')

# 0-4 分钟为第一组,显示的是从9:35开始
ts.resample('5min', how='sum', label='right')

OHLC 重采样

金融数据专用:Open/High/Low/Close

ts.resample('5min', how='ohlc')
#五分钟为间隔重采样,有ohlc四列

### 通过 groupby 重采样
ts = pd.Series(np.random.randint(0, 50, 100), index=pd.date_range('2016-03-01', periods=100, freq='D'))

ts.groupby(lambda x: x.month).sum()
#以月份为单位求总和

ts.groupby(ts.index.to_period('M')).sum()
#也是以月份为单位求和

升采样和插值

# 以周为单位,每周五采样
df = pd.DataFrame(np.random.randint(1, 50, 2), index=pd.date_range('2016-04-22', periods=2, freq='W-FRI'))

df.resample('D')
#输出22-29所有天数

df.resample('D', fill_method='ffill', limit=3)
#向前填充,限制三个

# 以周为单位,每周一采样
df.resample('W-MON', fill_method='ffill')

时期重采样

df = pd.DataFrame(np.random.randint(2, 30, (24, 4)), 
                  index=pd.period_range('2015-01', '2016-12', freq='M'),
                  columns=list('ABCD'))
adf = df.resample('A-DEC', how='mean')
#以十二月为一年的结尾,取每年的平均值

df.resample('A-MAY', how='mean')
#以五月份为一年的结尾,去每年的平均值

# 升采样
adf.resample('Q-DEC')
#以十二月为季度的结尾,升采样过后行数会变多,会出现很多空值

adf.resample('Q-DEC', fill_method='ffill')
#和上一个一样,空值变成了向前填充

性能

n = 1000000
ts = pd.Series(np.random.randn(n), 
               index=pd.date_range('2000-01-01', periods=n, freq='10ms'))
len(ts)
%timeit ts.resample('10min', how='ohlc')
#测试性能 10 loops, best of 3: 21.9 ms per loop

ts.resample('D', how='ohlc')
#以天为单位重采样

从文件中读取日期序列

df = pd.read_csv('data/002001.csv', index_col='Date')
df.index
#发现index并不是时间日期类型

df = pd.read_csv('data/002001.csv', index_col='Date', parse_dates=True)
df.index
#转换成时间日期类型

wdf = df['Adj Close'].resample('W-FRI', how='ohlc')
#以每周五为单位重采样,ohlc


wdf['Volume'] = df['Volume'].resample('W-FRI', how='sum')
#以每周五为单位,取总和

自定义时间日期解析函数

def date_parser(s):
    s = '2016/' + s
    d = datetime.strptime(s, '%Y/%m/%d')
    return d

df = pd.read_csv('data/custom_date.csv', parse_dates=True, index_col='Date', date_parser=date_parser)
#指定函数

df.index
#确定index是时间日期类型

猜你喜欢

转载自blog.csdn.net/qq_42007339/article/details/104510840
今日推荐