0
点赞
收藏
分享

微信扫一扫

【Python】数据分析.pandas.时间序列


文章目录

  • ​​数据分析.pandas.时间序列​​
  • ​​一、简单的了解生成一段时间范围​​
  • ​​二、转换与处理时间序列数据​​
  • ​​二、实际案例处理​​
  • ​​2.1 案例一​​
  • ​​2.2 案例一解析​​
  • ​​2.3 案例二​​
  • ​​2.4 案例二解析​​

数据分析.pandas.时间序列

关于时间序列的一些基本知识点,本人了解不是太深入,介绍一篇文章:​​pandas–处理时间序列数据​​ 数据分析的对象不仅仅限于数值型和类别型两种,常用的数据分析类型还包括时间类型。但时间类型数据在读入Python后常常以字符串的形式出现,无法实现大部分与时间相关的分析,多以pandas库提供了额外的模块来快速的实现时间字符串的转换、信息提取和时间运算。

【Python】数据分析.pandas.时间序列_时间序列

一、简单的了解生成一段时间范围

【Python】数据分析.pandas.时间序列_时间序列_02

【Python】数据分析.pandas.时间序列_数据_03

import pandas as pd
import numpy as np

df = pd.date_range(start="20000101",end="20010101",freq="D")
print(df)
# DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04',
# '2000-01-05', '2000-01-06', '2000-01-07', '2000-01-08',
# '2000-01-09', '2000-01-10',
# ...
# '2000-12-23', '2000-12-24', '2000-12-25', '2000-12-26',
# '2000-12-27', '2000-12-28', '2000-12-29', '2000-12-30',
# '2000-12-31', '2001-01-01'],
# dtype='datetime64[ns]', length=367, freq='D')

df = pd.date_range(start="2000-01-01",end="2001/01/01",freq="D")
print(df)
# DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04',
# '2000-01-05', '2000-01-06', '2000-01-07', '2000-01-08',
# '2000-01-09', '2000-01-10',
# ...
# '2000-12-23', '2000-12-24', '2000-12-25', '2000-12-26',
# '2000-12-27', '2000-12-28', '2000-12-29', '2000-12-30',
# '2000-12-31', '2001-01-01'],
# dtype='datetime64[ns]', length=367, freq='D')


df = pd.date_range(start="20000101",end="20010101",freq="10D")
print(df)
# DatetimeIndex(['2000-01-01', '2000-01-11', '2000-01-21', '2000-01-31',
# '2000-02-10', '2000-02-20', '2000-03-01', '2000-03-11',
# '2000-03-21', '2000-03-31', '2000-04-10', '2000-04-20',
# '2000-04-30', '2000-05-10', '2000-05-20', '2000-05-30',
# '2000-06-09', '2000-06-19', '2000-06-29', '2000-07-09',
# '2000-07-19', '2000-07-29', '2000-08-08', '2000-08-18',
# '2000-08-28', '2000-09-07', '2000-09-17', '2000-09-27',
# '2000-10-07', '2000-10-17', '2000-10-27', '2000-11-06',
# '2000-11-16', '2000-11-26', '2000-12-06', '2000-12-16',
# '2000-12-26'],
# dtype='datetime64[ns]', freq='10D')

df = pd.date_range(start="20000101",periods=12,freq="M")
print(df)
# DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31', '2000-04-30',
# '2000-05-31', '2000-06-30', '2000-07-31', '2000-08-31',
# '2000-09-30', '2000-10-31', '2000-11-30', '2000-12-31'],
# dtype='datetime64[ns]', freq='M')

df = pd.date_range(start="20000101",periods=12,freq="H")
print(df)
# DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 01:00:00',
# '2000-01-01 02:00:00', '2000-01-01 03:00:00',
# '2000-01-01 04:00:00', '2000-01-01 05:00:00',
# '2000-01-01 06:00:00', '2000-01-01 07:00:00',
# '2000-01-01 08:00:00', '2000-01-01 09:00:00',
# '2000-01-01 10:00:00', '2000-01-01 11:00:00'],
# dtype='datetime64[ns]', freq='H')

​​返回顶部​​

二、转换与处理时间序列数据

在多数情况下,对时间类型数据进行分析的前提就是将原本为字符串的时间转换为标准时间。以下是pandas继承的相关时间类。

【Python】数据分析.pandas.时间序列_pandas_04

1.Timestamp是时间类中最基础的类,也是最为常用的。通常情况下,会将与时间有关的字符串转换成Timestamp。使用的方法为 to_datetime()

【Python】数据分析.pandas.时间序列_pandas_05


2.Timestamp类型的时间是有限的,计算机中目前的范围是1677.9.21-2262.4.11.

【Python】数据分析.pandas.时间序列_数据分析_06


3.除了可以将数据直接转化为Timestamp类型外,还可以将数据单独提取出来转换为DatetimeIndex或者PeriodIndex.(这两种方法使用中并无太大区别,只是前者是指代一系列时间点的数据结构,后者是指代一系列时间段的数据结构。)

在用PeriodIndex转化数据类型时,需要添加freq参数来指定时间间隔。(常用的时间间隔有年-Y、月-M、日-D、小时-H、分钟-T、秒-S)

参数名称

说明

data

接受array,表示DatetimeIndex的值

freq

接受string ,表示时间的间隔频率

start

接受string,表示生成规则时间数据的起始点

periods

表示需要生成的周期数

end

接受string,表示生成规则时间数据的终结点

tz

接受timezone,表示数据的时区

name

接受int、string,默认为空,指定DatetimeIndex的名字

【Python】数据分析.pandas.时间序列_数据分析_07


4.提取时间序列数据信息

在涉及处理分析与时间相关的数据的时候,需要利用Timestamp的属性来实现对时间中的年份、月份的提取。

【Python】数据分析.pandas.时间序列_pandas_08


【Python】数据分析.pandas.时间序列_pandas_09

​AttributeError: 'Timestamp' object has no attribute 'weekday_name'​​ 对于该异常是由于当前pandas版本靠后,要退回到之前版本使用。

【Python】数据分析.pandas.时间序列_pandas_10


【Python】数据分析.pandas.时间序列_数据_11

5.加减时间数据
Timedelta是时间相关类中的一个异类,它可以使用正负数来表示单位时间。使用Timedelta类可以实现对时间的运算。

周期名称

单位

说明

周期名称

单位

说明

weeks

星期

seconds

s

days

D

milliseconds

ms

毫秒

hours

h

小时

microseconds

us

微秒

minutes

m

分钟

nanoseconds

ns

纳秒

# 将lock_time的时间加上一天
time1 = order['lock_time']+pd.Timedelta(days=1)
print('加上一天时间之前的数据:\n',order['lock_time'][:5])
print('加上一天时间之后的数据:\n',time1[:5])
#加上一天时间之前的数据:
0 2016-08-01 11:11:46
1 2016-08-01 11:31:55
2 2016-08-01 12:54:37
3 2016-08-01 13:08:20
4 2016-08-01 13:07:16
Name: lock_time, dtype: datetime64[ns]
#加上一天时间之后的数据:
0 2016-08-02 11:11:46
1 2016-08-02 11:31:55
2 2016-08-02 12:54:37
3 2016-08-02 13:08:20
4 2016-08-02 13:07:16
Name: lock_time, dtype: datetime64[ns]

timeDelta = order['lock_time']-pd.to_datetime('2017-1-1')
print('lock_time减去2017年1月1日0点0时0分后的数据为:\n',timeDelta[:5])
print('数据类型为:',timeDelta.dtypes)
#lock_time减去2017年1月1日0点0时0分后的数据为:
0 -153 days +11:11:46
1 -153 days +11:31:55
2 -153 days +12:54:37
3 -153 days +13:08:20
4 -153 days +13:07:16
Name: lock_time, dtype: timedelta64[ns]
#数据类型为: timedelta64[ns]

任务实现:

import pandas as pd 

# 读取数据表
order = pd.read_table('data/meal_order_info.csv',sep=',',encoding='gbk')

# 转换数据类型
order['use_start_time'] = pd.to_datetime(order['use_start_time'])
order['lock_time'] = pd.to_datetime(order['lock_time'])

# 提取相关的时间信息
year = [i.year for i in order['lock_time']]
month = [i.month for i in order['lock_time']]
day = [i.day for i in order['lock_time']]
week = [i.week for i in order['lock_time']]
weekday = [i.weekday() for i in order['lock_time']]
weekday_name = [i.weekday_name for i in order['lock_time']]

print('年份信息:\n',year[:5])
print('月份信息:\n',month[:5])
print('日期信息:\n',day[:5])
print('周信息:\n',week[:5])
print('星期信息:\n',weekday[:5])
print('星期名称信息:\n',weekday_name[:5])
#年份信息:
[2016, 2016, 2016, 2016, 2016]
#月份信息:
[8, 8, 8, 8, 8]
#日期信息:
[1, 1, 1, 1, 1]
#周信息:
[31, 31, 31, 31, 31]
#星期信息:
[0, 0, 0, 0, 0]
#星期名称信息:
['Monday', 'Monday', 'Monday', 'Monday', 'Monday']

​​返回顶部​​

二、实际案例处理

2.1 案例一

需求:统计出911紧急拨号数据中不同月份的电话的次数的情况

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from matplotlib import font_manager

#设置中文
my_font = font_manager.FontProperties(fname="C:\Windows\Fonts\STXINGKA.TTF",size=18)

#读取csv文件
file_path = "911-calls/911.csv"
df = pd.read_csv(file_path)

df["timeStamp"] = pd.to_datetime(df["timeStamp"]) #将timeStamp转化为时间戳
df.set_index("timeStamp",inplace=True) #将timeStamp定义为索引

print(df)
# lat ... e
# timeStamp ...
# 2015-12-10 17:10:52 40.297876 ... 1
# 2015-12-10 17:29:21 40.258061 ... 1
# 2015-12-10 14:39:21 40.121182 ... 1
# 2015-12-10 16:47:36 40.116153 ... 1
# 2015-12-10 16:56:52 40.251492 ... 1
# ... ... ..
# 2020-06-08 13:07:24 40.136020 ... 1
# 2020-06-08 13:10:11 40.172526 ... 1
# 2020-06-08 13:10:41 40.125814 ... 1
# 2020-06-08 13:11:45 40.197947 ... 1
# 2020-06-08 13:14:43 40.140505 ... 1
# [645716 rows x 8 columns]

#统计出911紧急拨号数据中不同月份的电话的次数
count_by_month = df.resample("M").count()["title"]
print(count_by_month.head(4)
# lat
# timeStamp
# 2015-12-31 7916
# 2016-01-31 13096
# 2016-02-29 11396
# 2016-03-31 11059

#画图
_x = count_by_month.index
_y = count_by_month.values

#查看当前dataframe的方法
for i in _x:
print(dir(i))
break


#格式化x轴
_x = [i.strftime("%Y%m%d") for i in _x]

#设置图像大小
plt.figure(figsize=(20,8),dpi=80)

#绘图
plt.plot(range(len(_x)),_y)
plt.xticks(range(len(_x)),_x,rotation=45)
plt.xlabel("年/月/日",fontproperties=my_font)
plt.ylabel("次数",fontproperties=my_font)
plt.title("911紧急拨号数据中不同月份的电话的次数",fontproperties=my_font)

#设置网格
plt.grid(True,linestyle="-.",alpha=0.3)

#展示
plt.show()

【Python】数据分析.pandas.时间序列_数据_12


​​返回顶部​​

2.2 案例一解析

【Python】数据分析.pandas.时间序列_pandas_13


这里我们运用to_datetime()函数将原来字符串类型的时间转化为了datetime类型的时间,并且制定该列数据作为索引,原有数据不保留。

【Python】数据分析.pandas.时间序列_python_14

​​pandas重采样;指的是将时间序列从一个频率转化为另一个频率进行处理的过程​​​
降采样:将高频率数据转化为低频率数据
升采样:将低频率数据转化为高频数率据

这里将时间频率该定为按照月进行统计。

【Python】数据分析.pandas.时间序列_pandas_15


【Python】数据分析.pandas.时间序列_时间序列_16


在之前图形输出时横坐标包含了时间,会显得坐标冗长,视觉冲击强烈。在这里对横坐标进行格式化,只包含年月日,清晰明了。

Python中strftime()函数的用法
在这里,strftime()函数可以用来变换时间格式,让时间更好的展现出来。
strftime()函数可以把YYYY-MM-DD HH:MM:SS格式的日期字符串转换成其它形式的字符串。
​​​官方文档:strftime()​​

它可以用以下的符号对日期和时间进行格式化:

%d

日期

01-31

%f

小数形式的秒

SS.SSS

%H

小时

00-23

%j

算出某一天是该年的第几天

001-366

%m

月份

00-12

%M

分钟

00-59

%s

从1970年1月1日到现在的秒数

%S

00-59

%w

星期

0-6 (0是星期天)

%W

算出某一天属于该年的第几周

01-53

%Y

YYYY

%%

百分号

​​返回顶部​​

2.3 案例二

需求:统计出不同月份的不同类型的拨号次数的情况

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from matplotlib import font_manager

#设置中文
my_font = font_manager.FontProperties(fname="C:\Windows\Fonts\simfang.ttf",size=18)

#读取csv文件
file_path = "911-calls/911.csv"
df = pd.read_csv(file_path)

#把时间字符串转化为时间类型设置为索引
df["timeStamp"] = pd.to_datetime(df["timeStamp"])

#添加列,表示分类
temp_list = df["title"].str.split(":").tolist()
cate_list = [i[0] for i in temp_list]
df["cate"] =
pd.DataFrame(np.array(cate_list).reshape((df.shape[0]),1))
df.set_index("timeStamp",inplace=True)

# 设置图像大小
plt.figure(figsize=(20, 8), dpi=80)

#可以理解为对分组的数据表遍历,
#设置变量group_name(分类),group_data(分组后的数据表)
for group_name,group_data in df.groupby(by="cate"):
#对不同的分类进行绘图
count_by_month = group_data.resample("M").count()["title"]

_x = count_by_month.index
_y = count_by_month.values
_x = [i.strftime("%Y/%m/%d") for i in _x]

# 绘图
plt.plot(range(len(_x)), _y, label=group_name)

#设置坐标及图示
plt.xticks(range(len(_x)),_x,rotation=45)
plt.xlabel("年/月/日",fontproperties=my_font)
plt.ylabel("911紧急拨号次数",fontproperties=my_font)
plt.title("不同月份的不同类型的911紧急拨号次数的情况",fontproperties=my_font)
plt.legend(loc="best")

# 设置网格
plt.grid(True, linestyle="-.", alpha=0.3)

# 展示
plt.show()

【Python】数据分析.pandas.时间序列_python_17


​​返回顶部​​

2.4 案例二解析

案例二的需求与案例一的需求相比较,可以发现都是对每月的数据进行统计,只是案例二具体到了每个911紧急拨号的类型.

【Python】数据分析.pandas.时间序列_pandas_18


基于以上的分析,以上的代码就很容易理解了。我们首先添加date一列,同时将字符串型时间转化为时间类型并设置为索引。(详细解析见​​博客:pandas-分组、聚合里的911案例​​

​​注意:​​

这个地方在将时间类型列设置为索引时,必须放置在​df["cate"] = pd.DataFrame(np.array(cate_list).reshape((df.shape[0]),1))​之后,因为该行代码是添加一列,是在原来的dataframe结构基础上,它的索引标准还是从0开始的;若在之前就设置时间列为索引,后续添加date列时,索引不匹配,则会出现整列为NAN值。

【Python】数据分析.pandas.时间序列_python_19


在案例一中我们遍历的是统计好的每月数据,案例二我们要在此基础上,添加不同的类型。同样的我们在遍历每月数据的同时,遍历不同的类型。其中,每一次的遍历,就是对一种911紧急拨号类型的绘图处理。

以下是df.groupby(by=“cate”)的具体内容,由于它是个DataFrameGroupBy
object(对象),所以只能遍历的去查看。它本身是一个包含两个元素的元组,前面是类型,后面是个dataframe类型的数据,这也是为什么我们设置两个变量的原因。

for i in df.groupby(by="cate"):
print(i)

<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000024B3AFE0188>
('EMS', lat lng ... e cate
0 40.297876 -75.581294 ... 1 EMS
1 40.258061 -75.264680 ... 1 EMS
3 40.116153 -75.343513 ... 1 EMS
4 40.251492 -75.603350 ... 1 EMS
5 40.253473 -75.283245 ... 1 EMS
... ... ... .. ...
645708 40.424520 -75.526377 ... 1 EMS
645711 40.136020 -75.354606 ... 1 EMS
645712 40.172526 -75.284653 ... 1 EMS
645713 40.125814 -75.406699 ... 1 EMS
645714 40.197947 -75.533853 ... 1 EMS
[322880 rows x 10 columns])
('Fire', lat lng ... e cate
2 40.121182 -75.351975 ... 1 Fire
22 40.199006 -75.300058 ... 1 Fire
27 40.028903 -75.351822 ... 1 Fire
39 40.104206 -75.367665 ... 1 Fire
45 40.224923 -75.528045 ... 1 Fire
... ... ... .. ...
645670 40.084676 -75.168942 ... 1 Fire
645690 40.135345 -75.126997 ... 1 Fire
645706 40.161786 -75.061742 ... 1 Fire
645710 40.184228 -75.166720 ... 1 Fire
645715 40.140505 -75.310874 ... 1 Fire
[97623 rows x 10 columns])
('Traffic', lat lng ... e cate
9 40.102398 -75.291458 ... 1 Traffic
10 40.231990 -75.251891 ... 1 Traffic
11 40.084161 -75.308386 ... 1 Traffic
12 40.174131 -75.098491 ... 1 Traffic
13 40.062974 -75.135914 ... 1 Traffic
... ... ... .. ...
645700 40.116214 -75.120746 ... 1 Traffic
645701 40.285252 -75.381471 ... 1 Traffic
645702 40.184228 -75.166720 ... 1 Traffic
645705 40.072731 -75.155969 ... 1 Traffic
645709 40.002564 -75.223650 ... 1 Traffic
[225213 rows x 10 columns])

​​返回顶部​​

举报

相关推荐

0 条评论