【Python数据分析】Pandas_日期与时间

时间序列

时间序列(time series),就是由时间构成的序列,它指的是在一定时间内按照时间顺序测量的某个变量的取值序列,比如一天内的温度会随时间而发生变化,或者股票的价格会随着时间不断的波动,这里用到的一系列时间,就可以看做时间序列。时间序列包含三种应用场景,分别是:

  • 特定的时刻(timestamp),也就是时间戳;
  • 固定的日期(period),比如某年某月某日;
  • 时间间隔(interval),每隔一段时间具有规律性;

在处理时间序列的过程中,我们一般会遇到两个问题,第一,如何创建时间序列;第二,如何更改已生成时间序列的频率。 Pandas 为解决上述问题提供了一套简单、易用的方法。

下面用 Python 内置的 datetime 模块来获取当前时间,通过该模块提供的now()方法即可实现。

from datetime import datetime
#数据类型为datetime
print(datetime.now())

创建时间戳

TimeStamp(时间戳) 是时间序列中的最基本的数据类型,它将数值与时间点完美结合在一起。Pandas 使用下列方法创建时间戳:

import pandas as pd
print (pd.Timestamp('2017-03-01'))

同样,可以将整型或浮点型表示的时间转换为时间戳。默认的单位是纳秒(时间戳单位),示例如下:

import pandas as pd
print(pd.Timestamp(1587687255,unit='s'))

创建时间范围

通过 date_range() 方法可以创建某段连续的时间或者固定间隔的时间时间段。该函数提供了三个参数,分别是:

  • start:开始时间
  • end:结束时间
  • freq:时间频率,默认为 “D”(天)

示例如下:

import pandas as pd
#freq表示时间频率,每30min变化一次
print(pd.date_range("9:00", "18:10", freq="30min").time)

运行结果:

[datetime.time(9, 0) datetime.time(9, 30) datetime.time(10, 0)
 datetime.time(10, 30) datetime.time(11, 0) datetime.time(11, 30)
 datetime.time(12, 0) datetime.time(12, 30) datetime.time(13, 0)
 datetime.time(13, 30) datetime.time(14, 0) datetime.time(14, 30)
 datetime.time(15, 0) datetime.time(15, 30) datetime.time(16, 0)
 datetime.time(16, 30) datetime.time(17, 0) datetime.time(17, 30)
 datetime.time(18, 0)]

更改时间频率

import pandas as pd
#修改为按小时
print(pd.date_range("6:10", "11:45", freq="H").time)

运行结果:

[datetime.time(6, 10) datetime.time(7, 10) datetime.time(8, 10)
 datetime.time(9, 10) datetime.time(10, 10) datetime.time(11, 10)]

转化为时间戳

您可以使用 to_datetime() 函数将 series 或 list 转换为日期对象,其中 list 会转换为DatetimeIndex。示例如下:

import pandas as pd
print(pd.to_datetime(pd.Series(['Jun 3, 2020','2020-12-10', None]),errors='ignore'))

运行结果:

0    Jun 3, 2020
1     2020-12-10
2           None
dtype: object

再来看一个示例:

import pandas as pd
#传入list,生成Datetimeindex
print(pd.to_datetime(['Jun 31, 2020','2020-12-10', None],errors='ignore'))

运行结果:

Index(['Jun 31, 2020', '2020-12-10', None], dtype='object')

频率和周期转换

Time Periods 表示时间跨度,一段时间周期,它被定义在 Pandas Periods 类中,通过该类提供的方法可以实现将频率转换为周期。比如 Periods() 方法,可以将频率 “M”(月)转换为 Period(时间段)。

下面示例,使用 asfreq() 和 start 参数,打印 “01” ,若使用 end 参数,则打印 “31”。示例如下:

import pandas as pd
x = pd.Period('2014', freq='M')
#start参数
print(x.asfreq('D', 'start'))
#end参数
print(x.asfreq('D', 'end'))

运行结果:

2014-01-01
2014-01-31

对于常用的时间序列频率,Pandas 为其规定了一些字符串别名,我们将这些别名称为“offset(偏移量)”。如下表所示:

别名描述别名描述
B工作日频率BQS工作季度开始频率
D日历日频率A年终频率
W每周频率BA工作年度结束频率
M月末频率BAS工作年度开始频率
SM半月结束频率BH营业时间频率
BM工作月结束频率H小时频率
MS月开始频率T,min每分钟频率
SMS半月开始频率S每秒钟频率
BMS工作月开始频率L,ms毫秒
Q季末频率U,us微妙
BQ工作季度结束频率N纳秒
QS季度开始频率

时间周期计算

周期计算,指的是对时间周期进行算术运算,所有的操作将在“频率”的基础上执行。

import pandas as pd
#S表示秒
x = pd.Period('2014', freq='S')  
print(x)

运行结果:

2014-01-01 00:00:00
2014-01-01 00:00:01

再看一组完整的示例:

import pandas as pd
#定义时期period,默认freq="Y"年份
p1=pd.Period('2020')
p2=pd.Period('2019')
#使用f''格式化输出
print(f'p1={p1}年')
print(f'p2={p2}年')
print(f'p1和p2间隔{p1-p2}年')
#f''表示字符串格式化输出
print(f'五年前是{p1-5}年')

运行结果:

p1=2020年
p2=2019年
p1和p2间隔<YearEnd: month=12>年
五年前是2015年

创建时间周期

我们可以使用 period_range() 方法来创建时间周期范围。示例如下:

import pandas as pd
#Y表示年
p = pd.period_range('2016','2018', freq='Y')
print(p)

运行结果:

PeriodIndex(['2016', '2017', '2018'], dtype='period[Y-DEC]')

时间序列转换

如果想要把字符串日期转换为 Period,首先需要将字符串转换为日期格式,然后再将日期转换为 Period。示例如下:

import pandas as pd
import numpy as np
# 创建时间序列
index=pd.date_range("2020-03-17","2020-03-30",freq="1.5h")
#随机选取4个互不相同的数
loc=np.random.choice(np.arange(len(index)),size=4,replace=False)
loc.sort()
ts_index=index[loc]
print(ts_index)
pd_index=ts_index.to_period('D')
print(pd_index)

运行结果(随机):

DatetimeIndex(['2020-03-24 21:00:00', '2020-03-25 18:00:00',
               '2020-03-27 03:00:00', '2020-03-29 04:30:00'],
              dtype='datetime64[ns]', freq=None)
PeriodIndex(['2020-03-24', '2020-03-25', '2020-03-27', '2020-03-29'], dtype='period[D]')

使用 to_timestamp() 能够将 Period 时期转换为时间戳(timestamp),示例如下:

import pandas as pd
p1=pd.Period("2020-2-3")
print(p1.to_timestamp())

运行结果:

2020-02-03 00:00:00

创建日期范围

Pandas 提供了用来创建日期序列的函数 date_range(),该函数的默认频率为 “D”, 也就是“天”。日期序列只包含年、月、日,不包含时、分、秒。

下面是一组简单的示例,如下所示:

import pandas as pd
print(pd.date_range('12/15/2020', periods=10))

运行结果:

DatetimeIndex(['2020-12-15', '2020-12-16', '2020-12-17', '2020-12-18',
               '2020-12-19', '2020-12-20', '2020-12-21', '2020-12-22',
               '2020-12-23', '2020-12-24'],
              dtype='datetime64[ns]', freq='D')

当我们使用 date_range() 来创建日期范围时,该函数包含结束的日期,用数学术语来说就是区间左闭右闭,即包含起始值,也包含结束值。示例如下:

from datetime import datetime
import pandas as pd
#建议使用Python的datetime模块创建时间
start = datetime(2019, 1, 1)
end = datetime(2019, 1, 5)
print(pd.date_range(start,end))

运行结果:

DatetimeIndex(['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04',
               '2019-01-05'],
              dtype='datetime64[ns]', freq='D')

更改日频率

使用下列方法可以修改频率,比如按“天”为按“月”,示例如下:

import pandas as pd
print(pd.date_range('12/15/2011', periods=5,freq='M'))

运行结果:

DatetimeIndex(['2011-12-31', '2012-01-31', '2012-02-29', '2012-03-31',
               '2012-04-30'],
              dtype='datetime64[ns]', freq='ME')

工作日时间

bdate_range() 表示创建工作日的日期范围,它与 date_range() 不同,它不包括周六、周日。

import pandas as pd
print(pd.date_range('11/25/2020', periods=8))

运行结果:

DatetimeIndex(['2020-11-25', '2020-11-26', '2020-11-27', '2020-11-28',
               '2020-11-29', '2020-11-30', '2020-12-01', '2020-12-02'],
              dtype='datetime64[ns]', freq='D')

上述方法中,date_range() 默认频率是日历日,而 bdate_range() 的默认频率是工作日。

import pandas as pd
print(pd.bdate_range('11/25/2020', periods=8))

运行结果:

DatetimeIndex(['2020-11-25', '2020-11-26', '2020-11-27', '2020-11-30',
               '2020-12-01', '2020-12-02', '2020-12-03', '2020-12-04'],
              dtype='datetime64[ns]', freq='B')

日期时间格式化

当进行数据分析时,我们会遇到很多带有日期、时间格式的数据集,在处理这些数据集时,可能会遇到日期格式不统一的问题,此时就需要对日期时间做统一的格式化处理。比如“Wednesday, June 6, 2020”可以写成“6/6/20”,或者写成“06-06-2020。

日期格式化符号

在对时间进行格式化处理时,它们都有固定的表示格式,比如小时的格式化符号为%H ,分钟简写为%M ,秒简写为%S。下表对常用的日期格式化符号做了总结:

符号说明
%y两位数的年份表示(00-99)
%Y四位数的年份表示(000-9999)
%m月份(01-12)
%d月内中的一天(0-31)
%H24小时制小时数(0-23)
%I12小时制小时数(01-12)
%M分钟数(00=59)
%S秒(00-59)
%a本地英文缩写星期名称
%A本地英文完整星期名称
%b本地缩写英文的月份名称
%B本地完整英文的月份名称
%w星期(0-6),星期天为星期的开始
%W一年中的星期数(00-53)星期一为星期的开始
%x本地相应的日期表示
%X本地相应的时间表示
%Z当前时区的名称
%U一年中的星期数(00-53)星期天为星期的开始
%j年内的一天(001-366)
%c本地相应的日期表示和时间表示

Python 内置的 strptime() 方法能够将字符串日期转换为 datetime 类型,下面看一组示例:

from datetime import datetime
#将日期定义为字符串
date_str1 = 'Wednesday,July 18,2020'
date_str2 = '18/7/20'
date_str3 = '18-07-2020'
#将日期转化为datetime对象
dmy_dt1 = datetime.strptime(date_str1, '%A,%B %d,%Y')
dmy_dt2 = datetime.strptime(date_str2, '%d/%m/%y')
dmy_dt3 = datetime.strptime(date_str3, '%d-%m-%Y')
#处理为相同格式,并打印输出
print(dmy_dt1)
print(dmy_dt2)
print(dmy_dt3)

运行结果:

2020-07-18 00:00:00
2020-07-18 00:00:00
2020-07-18 00:00:00

注意:strftime() 可以将 datetime 类型转换为字符串类型,恰好与 strptime() 相反。

除了使用 Python 内置的 strptime() 方法外,你还可以使用 Pandas 模块的 pd.to_datetime() 和 pd.DatetimeIndex() 进行转换。

1) to_datetime()

通过 to_datetime() 直接转换为 datetime 类型

import pandas as pd
import numpy as np
date = ['2012-05-06 11:00:00','2012-05-16 11:00:00']
pd_date=pd.to_datetime(date)
df=pd.Series(np.random.randn(2),index=pd_date)
print(df)

运行结果:

2012-05-06 11:00:00   -0.197195
2012-05-16 11:00:00   -0.860734
dtype: float64
2) DatetimeIndex()

使用 Datetimeindex() 函数设置时间序,示例如下:

import pandas as pd
import numpy as np
date = pd.DatetimeIndex(['1/1/2008', '1/2/2008', '1/3/2008', '1/4/2008', '1/5/2008'])
dt = pd.Series(np.random.randn(5),index = date)
print(dt)

运行结果:

2008-01-01    1.219920
2008-01-02    0.754776
2008-01-03   -2.124087
2008-01-04    0.292846
2008-01-05   -0.778030
dtype: float64

Timedelta时间差

Timedelta 表示时间差(或者时间增量),我们可以使用不同的时间单位来表示它,比如天、小时、分、秒。时间差的最终的结果可以是正时间差,也可以是负时间差。

字符串

通过传递字符串可以创建 Timedelta 对象,示例如下:

import pandas as pd
print(pd.Timedelta('5 days 8 hours 6 minutes 59 seconds'))

运行结果:

5 days 08:06:59

整数

通过传递整数值和unit参数也可以创建一个 Timedelta 对象。

import pandas as pd
print(pd.Timedelta(19,unit='h'))

运行结果:

0 days 19:00:00

数据偏移量

数据偏移量, 比如,周(weeks)、天(days)、小时(hours)、分钟(minutes)、秒(milliseconds)、毫秒、微秒、纳秒都可以使用。

import pandas as pd
print (pd.Timedelta(days=2,hours=6))

运行结果:

2 days 06:00:00

to_timedelta()

您可以使用pd.to_timedelta()方法,将具有 timedelta 格式的值 (标量、数组、列表或 Series)转换为 Timedelta 类型。如果输入是 Series,则返回 Series;如果输入是标量,则返回值也为标量,其他情况输出 TimedeltaIndex。示例如下:

import pandas as pd
import numpy as np
print(pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan']))
print(pd.to_timedelta(np.arange(5), unit='s'))

运行结果:

TimedeltaIndex(['1 days 06:05:01.000030', '0 days 00:00:00.000015500', NaT], dtype='timedelta64[ns]', freq=None)
TimedeltaIndex(['0 days 00:00:00', '0 days 00:00:01', '0 days 00:00:02',
                '0 days 00:00:03', '0 days 00:00:04'],
               dtype='timedelta64[ns]', freq=None)

算术操作

通过对datetime64[ns]类型的时间序列或时间戳做算术运算,其运算结果依然是datetime64[ns]数据类型。接下来,我们创建一个带有 Timedelta 与 datetime 的 DataFrame 对象,并对其做一些算术运算。

import pandas as pd
s = pd.Series(pd.date_range('2020-1-1', periods=5, freq='D'))
#推导式用法
td = pd.Series([ pd.Timedelta(days=i) for i in range(5)])
df = pd.DataFrame(dict(A = s, B = td))
print(df)

运行结果:

          A      B
0 2020-01-01 0 days
1 2020-01-02 1 days
2 2020-01-03 2 days
3 2020-01-04 3 days
4 2020-01-05 4 days
加法运算
import pandas as pd
s = pd.Series(pd.date_range('2012-1-1', periods=3, freq='D'))
td = pd.Series([ pd.Timedelta(days=i) for i in range(3) ])
df = pd.DataFrame(dict(A = s, B = td))
#加法运算
df['C']=df['A']+df['B']
print(df)

运行结果:

           A      B          C
0 2012-01-01 0 days 2012-01-01
1 2012-01-02 1 days 2012-01-03
2 2012-01-03 2 days 2012-01-05
减法运算
import pandas as pd
s = pd.Series(pd.date_range('2012-1-1', periods=3, freq='D'))
td = pd.Series([ pd.Timedelta(days=i) for i in range(3) ])
df = pd.DataFrame(dict(A = s, B = td))
df['C']=df['A']+df['B']
df['D']=df['C']-df['B']
print(df)

运行结果:

           A      B          C          D
0 2012-01-01 0 days 2012-01-01 2012-01-01
1 2012-01-02 1 days 2012-01-03 2012-01-02
2 2012-01-03 2 days 2012-01-05 2012-01-03

参考:C语言中文网

  • 31
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值