数据分析之时间序列
### 引入
DataFrame处理的数据中经常会看到某一列的数据类型是时间类型或者是字符串但是需要转成时间类型。什么是时间类型?与Python中使用的模块time、datetime等有什么联系?
首先看看下面这张图,如果看到数据的如果类型是**datetime64[ns]**说明就是DataFrame中的日期时间类型。
但是有时候我们看到的数据明明都是日期格式,怎么就偏偏不是**datetime64[ns]**类型呢?而显示的是object类型,比如下面你看到的数据
上面看到都是object类型,object类型在获取日期时间的年月日时分秒的时候就不方便,比获取
### 简单回顾Python日期时间模块
python标准库包含用于日期(date)和时间(time)数据的数据类型,而且还有日历方面的功能。我们主要会用到datetime、time以及calendar模块。
#### datetime模块
datetime模块常用的类如下:
| 类型 | 说明 |
| --------- | ------------------------------------------ |
| date | 日期对象,以公历形式存储日期(年、月、日) |
| time | 时间对象,将时间存储为:时、分、秒、毫秒 |
| datetime | 存储日期和时间 |
| timedelta | 时间间隔,表示两个datetime之间的差 |
附录(日期和时间的格式化符号表)
| 符号 | 说明 |
| :--- | :---------------------------------------- |
| `%y` | 两位数的年份表示(00-99) |
| `%Y` | 四位数的年份表示(000-9999) |
| `%m` | 月份(01-12) |
| `%d` | 月内中的一天(0-31) |
| `%H` | 24小时制小时数(0-23) |
| `%I` | 12小时制小时数(01-12) |
| `%M` | 分钟数(00=59) |
| `%S` | 秒(00-59) |
| `%a` | 本地简化星期名称 |
| `%A` | 本地完整星期名称 |
| `%b` | 本地简化的月份名称 |
| `%B` | 本地完整的月份名称 |
| `%c` | 本地相应的日期表示和时间表示 |
| `%j` | 年内的一天(001-366) |
| `%p` | 本地A.M.或P.M.的等价符 |
| `%U` | 一年中的星期数(00-53)星期天为星期的开始 |
| `%w` | 星期(0-6),星期天为星期的开始 |
| `%W` | 一年中的星期数(00-53)星期一为星期的开始 |
| `%x` | 本地相应的日期表示 |
| `%X` | 本地相应的时间表示 |
| `%Z` | 当前时区的名称 |
| `%%` | %号本身 |
date类代码演示:
> datetime.date(year, month, day)
```python
from datetime import date
# 获取当前的日期
today = date.today()
print(today) # 2021-08-10
print(today.day) # 10
# 也可以创建一个指定的日期对象
tomorrow = date(2021,8,11)
print(tomorrow) # 2021-08-11
print(tomorrow.day) # 11
print(today.strftime('%Y年%m月%d日')) # 相当于格式化输出
```
time类代码演示:
> datetime.time(hour[ , minute[ , second[ , microsecond[ , tzinfo] ] ] ] )
```python
from datetime import time
# 创建一个time对象
t = time(14,20,59,83999)
print(t) # 14:20:59.083999
print(t.strftime('%H:%M:%S')) # 相当于格式化输出
```
datetime代码演示:
> datetime相当于date和time结合起来
> datetime.datetime (year, month, day[ , hour[ , minute[ , second[ , microsecond[ , tzinfo] ] ] ] ] )
```python
from datetime import datetime
now = datetime.now()
print(now) # datetime.datetime(2021, 8, 10, 15, 21, 6, 581886)
print(now.year) # 2021
print(now.month) # 8
print(now.day) # 21
print(now.date())
print(now.time())
print(now.strftime('%Y年%m月%d日 %H:%M:%S')) # 格式化输出
```
timedelta代码演示:
> 使用timedelta可以很方便的在日期上做天days,小时hours,分钟,秒,毫秒,微妙的时间计算,如果要计算月份则需要另外的办法。
```python
from datetime import *
dt = datetime.now()
#日期减一天,dt1和dt2都表示昨天,两种不同的操作方式
dt1 = dt + timedelta(days=-1) # 昨天
dt2 = dt - timedelta(days=1) # 昨天
dt3 = dt + timedelta(days=1) # 明天
print(dt1)
print(dt2)
print(dt3)
# 也可以小时的加减
t1 = dt + timedelta(hours=1)
print(t1)
```
**案例**:获取指定日期月份的**最后一天的日期和本月天数**
```
from datetime import datetime,date,timedelta
date1 = datetime.now()
def eomonth(date_object):
if date_object.month == 12:
next_month_first_date = date(date_object.year+1,1,1)
else:
next_month_first_date = date(date_object.year, date_object.month+1, 1)
return next_month_first_date - timedelta(1)
print(eomonth(date1))
print(eomonth(date1).day)
```
#### time模块
time模块中时间表现的格式主要有三种:
> a、timestamp时间戳,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量
>
> b、struct_time时间元组,共有九个元素组。
>
> c、format time 格式化时间,已格式化的结构使时间更具可读性。包括自定义格式和固定格式
```python
import time
# 生成timestamp
print(time.time()) # 时间戳时间
print(time.localtime()) # 生成struct_time
print(time.strptime('2021-08-10 16:37:06', '%Y-%m-%d %X')) # 格式化时间转struct_time
print(time.strftime("%Y-%m-%d %X",time.localtime())) # struct_time转格式化时间
```
当然还有大家常用的time.sleep(seconds)休眠。
### panads日期时间操作
我们在数据分析的时候时间日期的操作无非下面几种:
#### object转日期时间类型
| 原有数据类型(object)和展示形式 | 想得到的格式 | 代码 |
| -------------------------------- | ------------------- | ----------------------------------------------------- |
| 2021-08-10 | 2021-08-10 | pd.to_datetime(data['time_object']) |
| 08/10/21 | 2021-08-10 | pd.to_datetime(data['time_object'],format='%m/%d/%y') |
| 2021-08-10 14:20:59 | 2021-08-10 14:20:59 | pd.to_datetime(data['time_object']) |
| 2021年08月 | 2021-08-01 | pd.to_datetime(data['time_object'],format='%Y年%m月') |
#### 日期转固定格式的
| 原有数据类型(datetime64)和展示形式 | 想得到的格式 | 代码 |
| ------------------------------------ | ------------------- | ------------------------------------------------------------ |
| 2021-08-10 14:20:59 | 2021-08-10 | data['datetime_col'].dt.date 或者pd.to_datetime(data['datetime_col'].dt.strftime('%Y-%m-%d')) |
| 2021-08-10 14:20:59 | 2021-08-10 00:00:00 | data['datetime_col'].dt.strftime('%Y-%m-%d 00:00:00') |
#### 提取日期类型的年月日
| 原有数据类型(datetime64)和展示形式 | 想得到的格式 | 代码 |
| ------------------------------------ | ------------ | ------------------------------ |
| 2021-08-10 14:20:59 | 2021 | data['datetime_col'].dt.year |
| 2021-08-10 14:20:59 | 8 | data['datetime_col'].dt.month |
| 2021-08-10 14:20:59 | 10 | data['datetime_col'].dt.day |
| 2021-08-10 14:20:59 | 14 | data['datetime_col'].dt.hour |
| 2021-08-10 14:20:59 | 20 | data['datetime_col'].dt.minute |
| 2021-08-10 14:20:59 | 59 | data['datetime_col'].dt.second |
#### 时间差的计算
| startdate | enddate | difference | 代码 |
| ------------------- | ------------------- | ---------- | ------------------------------------------------------------ |
| 2018-02-14 12:20:36 | 2019-02-28 13:38:41 | 379.054225 | (data['datetime_col']-data['datetime_col'])/np.timedelta64(1,'D') |
np.timedelta64具体内容可以参看文档:https://numpy.org/doc/stable/reference/arrays.datetime.html文档中给出的案例非常详细。