在金融、经济、物理学等领域,都需要在多个时间点观测或者测量数据,这样就产生了关于时间序列的数据。
时间序列数据(Time Series Data)是在不同时间上收集到的数据,这类数据是按时间顺序收集到的,用于描述现象随时间变化的情况。
学会如何对时间序列数据进行巧妙的处理非常重要,Pandas为我们提供了强大的时间序列数据处理的方法。
Python标准库包含了日期和时间数据的数据类型,datetime模块是开始处理时间数据最广泛的。
下面我们先简单的了解下python日期和时间数据类型。
datetime是一个关于时间的库,常用的类有:
日期类型的使用:
import datetime
# 创建日期
date = datetime.date(2020,5,31)
print(date)
# 获取年
print(date.year)
# 获取月
print(date.month)
# 获取日
print(date.day)
2020-05-31
2020
5
31
时间(time)类型的使用,如下所示:
import datetime
time = datetime.time(13,14,20)
print(time)
# 获取小时
print(time.hour)
# 获取分钟
print(time.minute)
# 获取秒
print(time.second)
13:14:20
13
14
20
日期和时间的结合(datetime):
import datetime
datetime = datetime.datetime(2020,5,31,13,14,20)
print(datetime)
# 获取年
print(datetime.year)
# 获取月
print(datetime.month)
# 获取日
print(datetime.day)
# 获取小时
print(datetime.hour)
# 获取分钟
print(datetime.minute)
# 获取秒
print(datetime.second)
2020-05-31 13:14:20
2020
5
31
13
14
20
datetime模块:
datetime = datetime.now()
print(datetime)
2020-05-31 12:21:27.681568
现在我们知道如何使用datetime模块创建时间,但是有些时候我们可能需要将datetime类型转成字符串样式。
例如:将datetime.datetime(2019, 9, 9, 13, 14, 20)转换成2019-9-9 13:14:20样式的字符串。
有的同学会问道:“datetime.datetime(2019, 9, 9, 13, 14, 20)输出的的结果不就是2019-9-9 13:14:20吗?为什么还需要变?”。
没错,它的结果就是我们想要的样式,但是,需要注意的是它的类型是datetime,并不是str。
如果我们只是单一的想改变类型,就可以使用强制类型转换:
datetime = datetime.now()
print(type(datetime))
str_datetime = str(datetime)
print(str_datetime)
print(type(str_datetime))
2020-05-31 12:28:05.940736
需求1:将datetime.datetime(2019, 9, 9, 13, 14, 20)转换成9/9/2019 13:14样式的字符串。
使用strftime()方法便可破解此需求。
import datetime
date_time = datetime.datetime(2020,5,31,14,13,20)
str_time = date_time.strftime('%m/%d/%Y %H:%M:%S')
print(str_time)
05/31/2020 14:13:20
strftime()方法的作用是将时间格式转化为自定义字符串格式,格式可以完全自定义。%m/%d/%Y %H:%M就是格式化以后的样式,%m、%d等是时间格式化占位符。
关于时间格式的汇总如下:
需求2:请将str类型转化成datetime类型。
例如:将字符串类型的Aug-23-19 20:13转化成2019-08-23 20:13:00样式的datetime类型。
可以使用strptime()方法解决此需求。
import datetime
strp = datetime.datetime.strptime('Aug-23-19 20:13','%b-%d-%y %H:%M')
print(strp)
print(type(strp))
2019-08-23 20:13:00
strptime()方法的作用是字符串时间转化为datetime格式,需要注意的是要按一定的格式输出时间。
例如:第二个参数不可写成%B-%d-%Y %H:%M ,或者%b / %d / %Y %H:%M,要与字符串表达式保持一致。
使用Pandas的date_range()方法可以快速创建出一个日期范围。
pd.date_range(start=None,end=None,periods=None,freq='D')
# 使用start和end以及默认的freq参数创建:
import pandas as pd
date = pd.date_range(start='20190505',end='20190606')
# 使用start和end以及频率参数freq为10天创建:
date2 = pd.date_range(start='20190505',end='20190606',freq='10D')
# 使用start和periods以及默认的频率参数创建:
date3 = pd.date_range(start='20200505',periods=10,freq='D')
print(date)
print(date2)
print(date3)
DatetimeIndex(['2019-05-05', '2019-05-06', '2019-05-07', '2019-05-08',
'2019-05-09', '2019-05-10', '2019-05-11', '2019-05-12',
'2019-05-13', '2019-05-14', '2019-05-15', '2019-05-16',
'2019-05-17', '2019-05-18', '2019-05-19', '2019-05-20',
'2019-05-21', '2019-05-22', '2019-05-23', '2019-05-24',
'2019-05-25', '2019-05-26', '2019-05-27', '2019-05-28',
'2019-05-29', '2019-05-30', '2019-05-31', '2019-06-01',
'2019-06-02', '2019-06-03', '2019-06-04', '2019-06-05',
'2019-06-06'],
dtype='datetime64[ns]', freq='D')
DatetimeIndex(['2019-05-05', '2019-05-15', '2019-05-25', '2019-06-04'], dtype='datetime64[ns]', freq='10D')
DatetimeIndex(['2020-05-05', '2020-05-06', '2020-05-07', '2020-05-08',
'2020-05-09', '2020-05-10', '2020-05-11', '2020-05-12',
'2020-05-13', '2020-05-14'],
dtype='datetime64[ns]', freq='D')
根据以上的的代码结果可以得出以下结论:
start和end以及freq配合能够生成start和end范围内以频率freq的一组时间索引。
start和periods以及freq配合能够生成从start开始的频率为freq的periods个时间索引。
上面我们提到时间索引,是因为date_range()方法生成的对象类型是DatetimeIndex,这个类型就是pandas中的时间索引类型。
关于频率的更多缩写:
有时候我们会对一天或者一个月的数据进行分析,这就需要我们将时间设置成数据的索引,然后通过时间索引获取到一定时间范围内的数据进行分析。
现在我们创建一个以时间序列为索引的Series数据。
# 首先,使用pd.date_range()来创建从2019-01-01开始的时间索引:
import pandas as pd
time_index = pd.date_range(start='20190901',periods=365)
time_index
DatetimeIndex(['2019-09-01', '2019-09-02', '2019-09-03', '2019-09-04',
'2019-09-05', '2019-09-06', '2019-09-07', '2019-09-08',
'2019-09-09', '2019-09-10',
...
'2020-08-21', '2020-08-22', '2020-08-23', '2020-08-24',
'2020-08-25', '2020-08-26', '2020-08-27', '2020-08-28',
'2020-08-29', '2020-08-30'],
dtype='datetime64[ns]', length=365, freq='D')
# 然后,使用numpy的随机数创建365个随机整数:
import numpy as np
data = np.random.randint(100,size=365)
data
array([11, 1, 66, 19, 33, 98, 22, 93, 11, 3, 98, 74, 75, 13, 31, 88, 94,
77, 26, 62, 64, 92, 15, 49, 16, 6, 51, 17, 91, 95, 83, 75, 88, 72,
45, 95, 88, 84, 90, 22, 61, 17, 23, 87, 69, 78, 39, 20, 4, 78, 82,
55, 0, 2, 53, 50, 3, 93, 44, 76, 80, 50, 96, 7, 35, 23, 15, 68,
25, 33, 3, 69, 47, 26, 82, 16, 17, 29, 14, 30, 28, 34, 98, 14, 94,
96, 80, 77, 46, 30, 39, 34, 31, 91, 56, 11, 73, 90, 26, 45, 40, 59,
87, 23, 49, 30, 15, 30, 89, 5, 61, 77, 44, 4, 67, 28, 5, 80, 20,
50, 59, 94, 95, 68, 73, 34, 46, 78, 64, 21, 16, 91, 48, 45, 80, 99,
5, 52, 36, 83, 79, 15, 92, 22, 49, 76, 42, 34, 45, 85, 99, 13, 52,
23, 61, 99, 93, 33, 83, 63, 44, 15, 62, 24, 0, 92, 89, 71, 59, 27,
77, 2, 45, 15, 66, 87, 32, 62, 58, 14, 67, 46, 63, 2, 59, 81, 60,
70, 38, 95, 66, 3, 53, 56, 92, 40, 67, 40, 0, 13, 65, 85, 82, 75,
9, 40, 72, 36, 98, 32, 95, 18, 11, 57, 32, 81, 34, 34, 48, 85, 84,
9, 37, 92, 89, 96, 87, 89, 51, 6, 93, 37, 74, 56, 96, 93, 88, 73,
11, 27, 92, 48, 98, 39, 81, 11, 93, 31, 53, 93, 53, 60, 36, 94, 54,
87, 24, 73, 86, 17, 96, 38, 48, 53, 68, 94, 79, 36, 42, 68, 58, 76,
29, 2, 44, 92, 43, 69, 27, 44, 5, 64, 77, 59, 82, 40, 84, 10, 69,
67, 13, 15, 42, 62, 97, 47, 79, 11, 14, 19, 17, 17, 18, 16, 70, 43,
2, 38, 3, 9, 56, 36, 95, 94, 56, 29, 33, 2, 59, 21, 0, 27, 11,
39, 62, 91, 74, 62, 97, 32, 40, 69, 84, 6, 11, 19, 62, 32, 17, 49,
88, 33, 37, 46, 68, 38, 48, 88, 33, 28, 97, 8, 46, 73, 82, 5, 32,
74, 72, 67, 34, 4, 49, 65, 41])
# 最后,创建出以时间序列为索引的Series数据
import pandas as pd
import numpy as np
time_index = pd.date_range(start='20190901',periods=365)
data = np.random.randint(100,size=365)
date_time = pd.Series(data=data,index=time_index)
date_time
2019-09-01 1
2019-09-02 63
2019-09-03 50
2019-09-04 71
2019-09-05 21
..
2020-08-26 92
2020-08-27 78
2020-08-28 11
2020-08-29 35
2020-08-30 70
Freq: D, Length: 365, dtype: int64
现在已经成功创建出数据,并将时间索引值设置成数据的索引项,接下来的重点是如何根据时间序列索引获取数据呢?
我们在获取数据的时候,可以直接使用字符串的形式获取以及切片操作。
# 依据年份索引
date_time['2020']
2020-01-01 70
2020-01-02 60
2020-01-03 65
2020-01-04 78
2020-01-05 95
..
2020-08-26 92
2020-08-27 78
2020-08-28 11
2020-08-29 35
2020-08-30 70
Freq: D, Length: 243, dtype: int64
# 依据年月索引
date_time['2019-10']
2019-10-01 58
2019-10-02 62
2019-10-03 18
2019-10-04 39
2019-10-05 15
2019-10-06 3
2019-10-07 70
2019-10-08 24
2019-10-09 61
2019-10-10 95
2019-10-11 97
2019-10-12 68
2019-10-13 19
2019-10-14 96
2019-10-15 54
2019-10-16 13
2019-10-17 71
2019-10-18 62
2019-10-19 28
2019-10-20 24
2019-10-21 80
2019-10-22 72
2019-10-23 69
2019-10-24 30
2019-10-25 60
2019-10-26 55
2019-10-27 71
2019-10-28 72
2019-10-29 86
2019-10-30 53
2019-10-31 43
Freq: D, dtype: int64
# 依据时间戳进行切片
date_time['2019-10-05':'2020-05-01']
2019-10-05 15
2019-10-06 3
2019-10-07 70
2019-10-08 24
2019-10-09 61
..
2020-04-27 11
2020-04-28 75
2020-04-29 70
2020-04-30 34
2020-05-01 89
Freq: D, Length: 210, dtype: int64
有的时候用csv导入到时间数据时,默认的是字符串的数据类型 ,当可视化的时候,会出现没有按时间先后顺序的方式绘图 ,所以需要将字符串解析为时间类型的数据类型。
使用Pandas的to_datetime方法可以将字符串形式的日期转换成时间格式。
pd.to_datime(arg,format=None)
to_datetime()方法会将字符串类型的时间转换成Timestamp(‘2019-10-05 00:00:00’)时间戳类型。
import pandas as pd
pd.to_datetime('2019-10-15')
Timestamp('2019-10-15 00:00:00')
如果想对时间格式修改,还可以使用to_pydatetime()方法将Timestamp类型转换成datetime类型。
pd.to_datetime('2019-10-15').to_pydatetime()
datetime.datetime(2019, 10, 15, 0, 0)
需要注意的是字符串日期中包含中文,我们可以这样处理:
pd.to_datetime('2019年10月10日',format='%Y年%m月%d日')
Timestamp('2019-10-10 00:00:00')
请根据数据完成以下需求:
- 分别算出2016年到2019年,每年5月份的总销售额。
- 2018年各地区的5月份的总销售额对比。
- 计算出2018年各个季度的总销售额(1-3月为第一季度,4-6为第二季度,7-9为第三季度,10-12为第四季度)。
- 计算出2018年各季度各地区的总销售额。
import pandas as pd
# 导入数据
path = r'/Users/davidlin/Desktop/data-coding/data/commerce.xls'
sales_data = pd.read_excel(path)
# 第一个问题:计算2016-209年5月的销售总额
# 将订单日期设置为数据的索引
sales_data.index=sales_data['订单日期']
# 计算2016-2019年5月的销售额之和
for i in range(6,10):
date = '201'+str(i)+'-05'
# 根据日期索引获取销售额列的数据,并求和
sales_amount = sales_data[date]['销售额'].sum()
print('{}的销售总额为{:.2f}元。'.format(date,sales_amount))
行 ID | 订单 ID | 订单日期 | 邮寄方式 | 客户 ID | 客户名称 | 细分 | 城市 | 省/自治区 | 国家 | 地区 | 产品 ID | 类别 | 子类别 | 产品名称 | 销售额 | 数量 | 折扣 | 利润 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | US-2019-1357144 | 2019-04-27 | 二级 | 曾惠-14485 | 曾惠 | 公司 | 杭州 | 浙江 | 中国 | 华东 | 办公用-用品-10002717 | 办公用品 | 用品 | Fiskars 剪刀, 蓝色 | 163.696 | 10 | 0.37 | -60.704 |
1 | 2 | CN-2019-1973789 | 2019-06-15 | 标准级 | 许安-10165 | 许安 | 消费者 | 内江 | 四川 | 中国 | 西南 | 办公用-信封-10004832 | 办公用品 | 信封 | GlobeWeis 搭扣信封, 红色 | 159.440 | 10 | 0.00 | 42.560 |
2 | 3 | CN-2019-1973789 | 2019-06-15 | 标准级 | 许安-10165 | 许安 | 消费者 | 内江 | 四川 | 中国 | 西南 | 办公用-装订-10001505 | 办公用品 | 装订机 | Cardinal 孔加固材料, 回收 | 65.920 | 10 | 0.37 | 4.200 |
3 | 5 | CN-2018-2975416 | 2018-05-31 | 二级 | 万兰-15730 | 万兰 | 消费者 | 汕头 | 广东 | 中国 | 中南 | 办公用-器具-10003452 | 办公用品 | 器具 | KitchenAid 搅拌机, 黑色 | 1409.920 | 11 | 0.00 | 550.200 |
4 | 6 | CN-2017-4497736 | 2017-10-27 | 标准级 | 俞明-18325 | 俞明 | 消费者 | 景德镇 | 江西 | 中国 | 华东 | 技术-设备-10001640 | 技术 | 设备 | 柯尼卡 打印机, 红色 | 11163.580 | 17 | 0.00 | 3783.780 |
# 第二个问题:计算2018年5月各地区的总销售额
data = sales_data['2018-05']
groups = data.groupby('地区')
# 分别计算各地区的销售总额
for group_name,value in groups:
sales_all = value['销售额'].sum()
print('{}地区2018年5月份的销售总额为{:.2f}元。'.format(group_name,sales_all))
东北地区2018年5月份的销售总额为58698.98元。
中南地区2018年5月份的销售总额为80690.21元。
华东地区2018年5月份的销售总额为153767.85元。
华北地区2018年5月份的销售总额为70674.69元。
西北地区2018年5月份的销售总额为15043.16元。
西南地区2018年5月份的销售总额为29359.40元。
地区
东北 42
中南 64
华东 84
华北 41
西北 9
西南 28
dtype: int64
# 第三个问题:计算出各个季度的总销售额
Q1 = sales_data['2018-01':'2018-03']['销售额'].sum()
Q2 = sales_data['2018-04':'2018-06']['销售额'].sum()
Q3 = sales_data['2018-07':'2018-09']['销售额'].sum()
Q4 = sales_data['2018-10':'2018-12']['销售额'].sum()
print('''
2018年第一季度的总销售额为{:.2f}元;
2018年第二季度的总销售额为{:.2f}元;
2018年第三季度的总销售额为{:.2f}元;
2018年第四季度的总销售额为{:.2f}元。'''.format(Q1,Q2,Q3,Q4))
2018年第一季度的总销售额为588269.65元;
2018年第二季度的总销售额为1084969.66元;
2018年第三季度的总销售额为1155180.63元;
2018年第四季度的总销售额为1505355.92元。
# 第四个问题:计算2018年各季度各地区的总销售额。
Q1_area = sales_data['2018-01':'2018-03'].groupby('地区')['销售额'].sum()
Q2_area = sales_data['2018-04':'2018-06'].groupby('地区')['销售额'].sum()
Q3_area = sales_data['2018-07':'2018-09'].groupby('地区')['销售额'].sum()
Q4_area = sales_data['2018-10':'2018-12'].groupby('地区')['销售额'].sum()
print('''
2018年各季度各地区的销售总额分别为:
第一季度:
{}
第二季度:
{}
第三季度:
{}
第四季度:
{}
'''.format(Q1_area,Q2_area,Q3_area,Q4_area))
2018年各季度各地区的销售总额分别为:
第一季度:
地区
东北 179643.353
中南 84444.402
华东 143707.440
华北 78643.176
西北 42066.024
西南 59765.256
Name: 销售额, dtype: float64
第二季度:
地区
东北 149468.096
中南 275229.727
华东 370572.171
华北 185044.910
西北 26896.188
西南 77758.564
Name: 销售额, dtype: float64
第三季度:
地区
东北 204187.616
中南 283578.345
华东 369739.215
华北 136339.921
西北 63392.432
西南 97943.104
Name: 销售额, dtype: float64
第四季度:
地区
东北 236502.685
中南 350783.303
华东 478426.016
华北 215142.952
西北 72989.032
西南 151511.932
Name: 销售额, dtype: float64