Pandas DateTime 超强总结
原创
周萝⼘ 萝⼘⼤杂烩 2022-04-25 18:30
收录于合集
#时间序列 1 #Python 31 #python 51 #Pandas 2
对于 Pandas 来说,可以处理众多的数据类型,其中最有趣和最重要的数据类型之⼀
就是时间序列数据。时间序列数据⽆处不在,它在各个⾏业都有很多应⽤。患者健康
指标、股票价格变化、天⽓记录、经济指标、服务器、⽹络、传感器和应⽤程序性能
监控都是时间序列数据的应⽤⽅向
我们可以将时间序列数据定义为在不同时间间隔获得并按时间顺序排列的数据点的集
合
Pandas 基本上是为分析⾦融时间序列数据⽽开发的,并为处理时间、⽇期和时间序
列数据提供了⼀整套全⾯的框架
今天我们来讨论在 Pandas 中处理⽇期和时间的多个⽅⾯,具体包含如下内容:
Timestamp 和 Period 对象的功能
如何使⽤时间序列 DataFrames
如何对时间序列进⾏切⽚
DateTimeIndex 对象及其⽅法
如何重新采样时间序列数据
探索 Pandas 时间戳和周期对象
Pandas 库提供了⼀个名为 Timestamp 的具有纳秒精度的 DateTime 对象来处理⽇期
和时间值。Timestamp 对象派⽣⾃ NumPy 的 datetime64 数据类型,使其⽐ Python
的 DateTime 对象更准确⽽且更快。下⾯让我们使⽤ Timestamp 构造函数创建⼀些
Timestamp 对象。
import pandas as pd
import numpy as np
from IPython.display import display
print(pd.Timestamp(year=1982, month=9, day=4, hour=1, minute=35, second=10))
print(pd.Timestamp('1982-09-04 1:35.18'))
print(pd.Timestamp('Sep 04, 1982 1:35.18'))
Output:
1982-09-04 01:35:10
1982-09-04 01:35:10
1982-09-04 01:35:10
如果将单个整数或浮点值传递给 Timestamp 构造函数,它会返回⼀个时间戳,该时
间戳等于 Unix 纪元(1970 年 1 ⽉ 1 ⽇)之后的纳秒数:
print(pd.Timestamp(5000))
Output:
1970-01-01 00:00:00.000005
Timestamp 对象包含许多⽅法和属性,可帮助我们访问时间戳的不同功能。让我们尝
试⼀下:
time_stamp = pd.Timestamp('2022-02-09')
print('{}, {} {}, {}'.format(time_stamp.day_name(), time_stamp.month_name(), time_stamp.day
Output:
Wednesday, February 9, 2022
Timestamp 类的⼀个实例代表⼀个时间点,⽽ Period 对象的⼀个实例代表⼀个时
期,例如⼀年、⼀个⽉等
例如,公司在⼀年的时间⾥监控他们的收⼊。Pandas 库提供了⼀个名为 Period 的对
象来处理,如下所示:
year = pd.Period('2021')
display(year)
Output:
Period('2021', 'A-DEC')
我们可以看到它创建了⼀个代表 2021 年期间的 Period 对象,⽽“A-DEC”表示该期间
是年度的,在 12 ⽉结束
Period 对象提供了许多有⽤的⽅法和属性。例如,如果要返回期间的开始和结束时
间,可以使⽤以下属性:
print('Start Time:', year.start_time)
print('End Time:', year.end_time)
Output:
:
Start Time: 2021-01-01 00:00:00
End Time: 2021-12-31 23:59:59.999999999
要创建每⽉期间,可以将特定⽉份传递给它,如下所示
month = pd.Period('2022-01')
display(month)
print('Start Time:', month.start_time)
print('End Time:', month.end_time)
Output:
Period('2022-01', 'M')
Start Time: 2022-01-01 00:00:00
End Time: 2022-01-31 23:59:59.999999999
“M”表示周期的频率是每⽉⼀次。还可以使⽤ freq 参数显式指定周期的频率。下⾯的
代码创建了⼀个代表 2022 年 1 ⽉ 1 ⽇期间的期间对象:
day = pd.Period('2022-01', freq='D')
display(day)
print('Start Time:', day.start_time)
print('End Time:', day.end_time)
Output:
Period('2022-01-01', 'D')
Start Time: 2022-01-01 00:00:00
End Time: 2022-01-01 23:59:59.999999999
:
我们还可以对周期对象执⾏算术运算。让我们创建⼀个每⼩时频率的新 period 对
象,看看我们如何进⾏计算:
hour = pd.Period('2022-02-09 16:00:00', freq='H')
display(hour)
display(hour + 2)
display(hour - 2)
Output:
Period('2022-02-09 16:00', 'H')
Period('2022-02-09 18:00', 'H')
Period('2022-02-09 14:00', 'H')
我们可以使⽤ Pandas ⽇期偏移量获得相同的结果:
display(hour + pd.offsets.Hour(+2))
display(hour + pd.offsets.Hour(-2))
Output:
Period('2022-02-09 18:00', 'H')
Period('2022-02-09 14:00', 'H')
要创建⽇期序列,可以使⽤ pandas range_dates() ⽅法。让我们在代码⽚段中尝试⼀
下:
:
week = pd.date_range('2022-2-7', periods=7)
for day in week:
print('{}-{}\t{}'.format(day.day_of_week, day.day_name(), day.date()))
Output:
0-Monday
2022-02-07
1-Tuesday
2022-02-08
2-Wednesday 2022-02-09
3-Thursday
2022-02-10
4-Friday
2022-02-11
5-Saturday
2022-02-12
6-Sunday
2022-02-13
week 的数据类型是 DatetimeIndex 对象,⼀周中的每个⽇期都是 Timestamp 的⼀个
实例。所以我们可以使⽤所有适⽤于 Timestamp 对象的⽅法和属性
创建时间序列数据框
⾸先,让我们通过从 CSV ⽂件中读取数据来创建⼀个 DataFrame,该⽂件包含与连
续 34 天每⼩时记录的 50 台服务器相关的关键信息:
df = pd.read_csv('https://raw.githubusercontent.com/m-mehdi/pandas_tutorials/main/server_ut
display(df.head())
Output:
:
datetime
server_id
cpu_utilization free_memory
0
2019-03-06 00:00:00
100
0.40
0.54
52
1
2019-03-06 01:00:00
100
0.49
0.51
58
2
2019-03-06 02:00:00
100
0.49
0.54
53
3
2019-03-06 03:00:00
100
0.44
0.56
49
4
2019-03-06 04:00:00
100
0.42
0.52
54
session_count
让我们看⼀下 DataFrame 的内容。每个 DataFrame ⾏代表服务器的基本性能指标,
包括特定时间戳的 CPU 利⽤率、可⽤内存和会话计数。DataFrame 分解为⼀⼩时的
⽚段。例如,从午夜到凌晨 4 点记录的性能指标位于 DataFrame 的前五⾏
现在,让我们详细了解⼀下 DataFrame 的特性,例如它的⼤⼩和每列的数据类型:
print(df.info())
Output:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 40800 entries, 0 to 40799
Data columns (total 5 columns):
#
Column
Non-Null Count
Dtype
---
------
--------------
-----
0
datetime
40800 non-null
object
1
server_id
40800 non-null
int64
2
cpu_utilization
40800 non-null
float64
3
free_memory
40800 non-null
float64
4
session_count
40800 non-null
int64
dtypes: float64(2), int64(2), object(1)
memory usage: 1.6+ MB
None
运⾏上⾯的语句会返回⾏数和列数、总内存使⽤量、每列的数据类型等
根据上⾯的信息,datetime 列的数据类型是对象,这意味着时间戳存储为字符串值。
要将 datetime 列的数据类型从 string 对象转换为 datetime64 对象,我们可以使⽤
pandas 的 to_datetime() ⽅法,如下:
df['datetime'] = pd.to_datetime(df['datetime'])
当我们通过导⼊ CSV ⽂件创建 DataFrame 时,⽇期/时间值被视为字符串对象,⽽不
:
是 DateTime 对象。pandas to_datetime() ⽅法将存储在 DataFrame 列中的⽇期/时间
值转换为 DateTime 对象。将⽇期/时间值作为 DateTime 对象使操作它们变得更加容
易。运⾏以下语句并查看更改:
print(df.info())
Output:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 40800 entries, 0 to 40799
Data columns (total 5 columns):
#
Column
Non-Null Count
Dtype
---
------
--------------
-----
0
datetime
40800 non-null
datetime64[ns]
1
server_id
40800 non-null
int64
2
cpu_utilization
40800 non-null
float64
3
free_memory
40800 non-null
float64
4
session_count
40800 non-null
int64
dtypes: datetime64[ns](1), float64(2), int64(2)
memory usage: 1.6 MB
None
现在 datetime 列的数据类型是 datetime64[ns] 对象。[ns] 表示基于纳秒的时间格
式,它指定 DateTime 对象的精度
此外,我们可以让 pandas 的 read_csv() ⽅法将某些列解析为 DataTime 对象,这⽐
使⽤ to_datetime() ⽅法更直接。让我们尝试⼀下:
df = pd.read_csv('https://raw.githubusercontent.com/m-mehdi/pandas_tutorials/main/server_ut
print(df.head())
Output:
datetime
server_id
:
0 2019-03-06 00:00:00
cpu_utilization
free_memory
session_count
100
0.40
0.54
52
1 2019-03-06 01:00:00
100
0.49
0.51
58
2 2019-03-06 02:00:00
100
0.49
0.54
53
3 2019-03-06 03:00:00
100
0.44
0.56
49
4 2019-03-06 04:00:00
100
0.42
0.52
54
运⾏上⾯的代码会创建⼀个 DataFrame,其中 datetime 列的数据类型是 DateTime 对
象
下⾯让我们对 datetime 列应⽤⼀些基本⽅法
⾸先,让我们看看如何在 DataFrame 中返回最早和最晚的⽇期。为此,我们可以简
单地在 datetime 列上应⽤ max() 和 min() ⽅法,如下所示:
display(df.datetime.min())
display(df.datetime.max())
Output:
Timestamp('2019-03-06 00:00:00')
Timestamp('2019-04-08 23:00:00')
要选择两个特定⽇期之间的 DataFrame ⾏,我们可以创建⼀个布尔掩码并使⽤ .loc
⽅法过滤特定⽇期范围内的⾏:
mask = (df.datetime >= pd.Timestamp('2019-03-06')) & (df.datetime < pd.Timestamp(
display(df.loc[mask])
Output:
:
datetime
server_id
cpu_utilization free_memory
0
2019-03-06 00:00:00
100
0.40
0.54
52
1
2019-03-06 01:00:00
100
0.49
0.51
58
session_count
2
2019-03-06 02:00:00
100
0.49
0.54
53
3
2019-03-06 03:00:00
100
0.44
0.56
49
4
2019-03-06 04:00:00
100
0.42
0.52
54
…
…
…
…
40003
2019-03-06 19:00:00
149
0.74
0.24
81
40004
2019-03-06 20:00:00
149
0.73
0.23
81
40005
2019-03-06 21:00:00
149
0.79
0.29
83
40006
2019-03-06 22:00:00
149
0.73
0.29
82
40007
2019-03-06 23:00:00
149
0.75
0.24
84
…
…
1200 rows × 5 columns
切⽚时间序列
为了使时间戳切⽚成为可能,我们需要将 datetime 列设置为 DataFrame 的索引。要
将列设置为 DataFrame 的索引,请使⽤ set_index ⽅法:
df.set_index('datetime', inplace=True)
print(df)
Output:
datetime
server_id
cpu_utilization
free_memory
2019-03-06 00:00:00
100
0.40
0.54
52
2019-03-06 01:00:00
100
0.49
0.51
58
2019-03-06 02:00:00
100
0.49
0.54
53
2019-03-06 03:00:00
100
0.44
0.56
49
2019-03-06 04:00:00
100
0.42
0.52
54
...
...
...
...
...
2019-04-08 19:00:00
149
0.73
0.20
81
2019-04-08 20:00:00
149
0.75
0.25
83
2019-04-08 21:00:00
149
0.80
0.26
82
2019-04-08 22:00:00
149
0.75
0.29
82
2019-04-08 23:00:00
149
0.75
0.24
80
[40800 rows x 4 columns]
要使⽤ .loc ⽅法选择等于单个索引的所有⾏:
:
session_count
print(df.loc['2019-03-07 02:00:00'].head(5))
Output:
cpu_utilization
free_memory
session_count
2019-03-07 02:00:00
datetime
server_id
100
0.44
0.50
56
2019-03-07 02:00:00
101
0.78
0.21
87
2019-03-07 02:00:00
102
0.75
0.27
80
2019-03-07 02:00:00
103
0.76
0.28
85
2019-03-07 02:00:00
104
0.74
0.24
77
可以选择与索引列中的特定时间戳部分匹配的⾏。让我们尝试⼀下:
print(df.loc['2019-03-07'].head(5))
Output:
datetime
server_id
cpu_utilization
free_memory
session_count
2019-03-07 00:00:00
100
0.51
0.52
55
2019-03-07 01:00:00
100
0.46
0.50
49
2019-03-07 02:00:00
100
0.44
0.50
56
2019-03-07 03:00:00
100
0.45
0.52
51
2019-03-07 04:00:00
100
0.42
0.50
53
选择字符串可以是任何标准的⽇期格式,我们来看⼀些例⼦:
df.loc['Apr 2019']
df.loc['8th April 2019']
df.loc['April 05, 2019 5pm']
:
我们还可以使⽤ .loc ⽅法对⽇期范围内的⾏进⾏切⽚。以下语句将返回从 2019 年 4
⽉ 3 ⽇到 2019 年 4 ⽉ 4 ⽇结束的所有⾏;开始⽇期和结束⽇期都包括在内:
display(df.loc['03-04-2019':'04-04-2019'])
但是运⾏它会引发⼀个令⼈讨厌的未来警告。为了摆脱警告,我们可以在切⽚⾏之前
对索引进⾏排序:
display(df.sort_index().loc['03-04-2019':'04-04-2019'])
Output:
datetime
server_id
cpu_utilization free_memory
2019-03-06 00:00:00
100
0.40
0.54
52
2019-03-06 00:00:00
135
0.50
0.55
55
2019-03-06 00:00:00
110
0.54
0.40
61
2019-03-06 00:00:00
136
0.58
0.40
64
2019-03-06 00:00:00
109
0.57
0.41
61
…
…
…
2019-04-04 23:00:00
143
0.43
0.52
50
2019-04-04 23:00:00
111
0.53
0.52
59
2019-04-04 23:00:00
149
0.75
0.24
85
2019-04-04 23:00:00
138
0.40
0.56
47
2019-04-04 23:00:00
107
0.63
0.33
73
…
…
session_count
36000 rows × 4 columns
DateTimeIndex ⽅法
某些 pandas DataFrame ⽅法仅适⽤于 DateTimeIndex。下⾯我们来具体看⼀下,⾸
先让我们确保我们的 DataFrame 有⼀个 DateTimeIndex:
:
print(type(df.index))
Output:
<class 'pandas.core.indexes.datetimes.DatetimeIndex'>
要返回在特定时间收集的服务器监控数据,⽆论⽇期如何,请使⽤ at_time() ⽅法:
display(df.at_time('09:00'))
Output:
datetime
server_id
cpu_utilization free_memory
2019-03-06 09:00:00
100
0.48
0.51
51
2019-03-07 09:00:00
100
0.45
0.49
56
2019-03-08 09:00:00
100
0.45
0.53
53
2019-03-09 09:00:00
100
0.45
0.51
53
2019-03-10 09:00:00
100
0.49
0.55
55
…
…
…
2019-04-04 09:00:00
149
0.75
0.21
80
2019-04-05 09:00:00
149
0.71
0.26
83
2019-04-06 09:00:00
149
0.75
0.30
83
2019-04-07 09:00:00
149
0.81
0.28
77
2019-04-08 09:00:00
149
0.82
0.24
86
…
…
session_count
1700 rows × 4 columns
此外,要选择所有⽇期午夜和凌晨 2 点之间的所有服务器数据,可以使⽤
between_time() ⽅法。让我们尝试⼀下:
display(df.between_time('00:00','02:00'))
Output:
:
datetime
server_id
cpu_utilization free_memory
session_count
2019-03-06 00:00:00
100
0.40
0.54
52
2019-03-06 01:00:00
100
0.49
0.51
58
2019-03-06 02:00:00
100
0.49
0.54
53
2019-03-07 00:00:00
100
0.51
0.52
55
0.50
49
2019-03-07 01:00:00
100
0.46
…
…
…
2019-04-07 01:00:00
149
0.74
0.21
78
2019-04-07 02:00:00
149
0.76
0.26
74
2019-04-08 00:00:00
149
0.75
0.28
75
2019-04-08 01:00:00
149
0.69
0.27
79
2019-04-08 02:00:00
149
0.78
0.20
85
…
…
5100 rows × 4 columns
我们可以使⽤ first() ⽅法根据特定的⽇期偏移量选择第⼀个 DataFrame ⾏。例如,将
5B 作为⽇期偏移量传递给该⽅法会返回前五个⼯作⽇内具有索引的所有⾏。同样,
将 1W 传递给 last() ⽅法会返回上周内所有带有索引的 DataFrame ⾏。需要注意的
是,必须按其索引对 DataFrame 进⾏排序,以确保这些⽅法有效。让我们试试这两
个例⼦:
display(df.sort_index().first('5B'))
Output:
datetime
server_id
cpu_utilization free_memory
2019-03-06
100
0.40
0.54
52
2019-03-06
135
0.50
0.55
55
2019-03-06
110
0.54
0.40
61
2019-03-06
136
0.58
0.40
64
2019-03-06
109
0.57
0.41
61
…
…
…
…
2019-03-12
134
0.53
0.45
61
2019-03-12
144
0.68
0.31
73
2019-03-12
113
0.76
0.24
83
2019-03-12
114
0.58
0.48
67
2019-03-12
131
0.58
0.42
67
…
7250 rows × 4 columns
:
display(df.sort_index().last('1W'))
session_count
display(df.sort_index().last('1W'))
Output:
datetime
server_id
cpu_utilization free_memory
2019-04-08 00:00:00
106
0.44
0.62
49
2019-04-08 00:00:00
112
0.72
0.29
81
2019-04-08 00:00:00
100
0.43
0.54
51
2019-04-08 00:00:00
137
0.75
0.28
83
0.40
62
2019-04-08 00:00:00
110
0.61
…
…
…
2019-04-08 23:00:00
128
0.64
0.41
64
2019-04-08 23:00:00
127
0.67
0.33
78
2019-04-08 23:00:00
126
0.71
0.33
73
2019-04-08 23:00:00
123
0.71
0.22
83
2019-04-08 23:00:00
149
0.75
0.24
80
…
…
session_count
1200 rows × 4 columns
df.sort_index().last('2W')
Output:
datetime
server_id
2019-04-01 00:00:00
120
0.54
0.48
63
2019-04-01 00:00:00
104
0.73
0.31
83
2019-04-01 00:00:00
103
0.77
0.22
82
2019-04-01 00:00:00
124
0.39
0.55
49
2019-04-01 00:00:00
127
0.68
0.37
73
…
…
…
2019-04-08 23:00:00
128
0.64
0.41
64
2019-04-08 23:00:00
127
0.67
0.33
78
2019-04-08 23:00:00
126
0.71
0.33
73
2019-04-08 23:00:00
123
0.71
0.22
83
2019-04-08 23:00:00
149
0.75
0.24
80
…
…
9600 rows × 4 columns
:
cpu_utilization free_memory
session_count
重新采样时间序列数据
resample() ⽅法背后的逻辑类似于 groupby() ⽅法。它在任何可能的时间段内对数据
进⾏分组。虽然我们可以使⽤ resample() ⽅法进⾏上采样和下采样,但我们将重点介
绍如何使⽤它来执⾏下采样,这会降低时间序列数据的频率——例如,将每⼩时的时
间序列数据转换为每⽇或 每⽇时间序列数据到每⽉
以下示例返回服务器 ID 100 每天的平均 CPU 利⽤率、可⽤内存和活动会话计数。为
此,我们⾸先需要过滤 DataFrame 中服务器 ID 为 100 的⾏,然后将每⼩时数据重新
采样为每⽇数据。最后,对结果应⽤ mean() ⽅法,得到三个指标的每⽇平均值:
df[df.server_id == 100].resample('D')['cpu_utilization', 'free_memory', 'session_count'
Output:
datetime
cpu_utilization free_memory
session_count
2019-03-06
0.470417
0.535417
53.000000
2019-03-07
0.455417
0.525417
53.666667
2019-03-08
0.478333
0.532917
54.541667
2019-03-09
0.472917
0.523333
54.166667
2019-03-10
0.465000
0.527500
54.041667
2019-03-11
0.469583
0.528750
53.916667
2019-03-12
0.475000
0.533333
53.750000
2019-03-13
0.462917
0.521667
52.541667
2019-03-14
0.472083
0.532500
54.875000
2019-03-15
0.470417
0.530417
53.500000
2019-03-16
0.463750
0.530833
54.416667
2019-03-17
0.472917
0.532917
52.041667
2019-03-18
0.475417
0.535000
53.333333
2019-03-19
0.460833
0.546667
54.791667
...
我们还可以通过链接 groupby() 和 resample() ⽅法来查看每个服务器 ID 的相同结
果。以下语句返回每个服务器每⽉的最⼤ CPU 利⽤率和可⽤内存。让我们尝试⼀
:
下:
df.groupby(df.server_id).resample('M')['cpu_utilization', 'free_memory'].max()
Output:
server_id
100
2019-03-31
2019-04-30
101
datetime
0.55
2019-03-31
2019-04-30
0.89
0.56
cpu_utilization free_memory
0.62
0.61
0.91
0.32
0.30
102
2019-03-31
0.85
…
…
…
147
2019-04-30
0.61
0.57
148
2019-03-31
0.84
0.35
2019-04-30
149
…
0.83
2019-03-31
2019-04-30
0.83
0.36
0.34
0.85
0.36
0.34
100 rows × 2 columns
下⾯让我们绘制每个服务器每⽉的平均 CPU 利⽤率,结果使我们能够充分了解每个
服务器的平均 CPU 利⽤率在⼏个⽉内的变化
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(24, 8))
df.groupby(df.server_id).resample('M')['cpu_utilization'].mean()\
.plot.bar(color=['green', 'gray'], ax=ax, title='The Average Monthly CPU Utilization Compar
Output:
:
<AxesSubplot:title={'center':'The Average Monthly CPU Utilization Comparison'}, xlabel='ser
写在最后
Pandas 是⼀种出⾊的分析⼯具,尤其是在处理时间序列数据时。该库提供了⼴泛的
⼯具来处理时间索引的 DataFrame
好了,这就是今天分享的内容,如果喜欢就点个赞吧~
推荐阅读
点击标题可跳转
10⾏Python代码能做出哪些有趣的事情
:
⽤Python分析中国⼤学分布,终于知道为什么好⼤学难上了
喜欢此内容的⼈还喜欢
今⽇开营!3天搞定Excel数据分析
...爱数据LoveData
3天掌握⼯具+思维!Excel数据分析实战营千万别错过
...爱数据LoveData
SQL常⽤函数系列——带你玩转⽇期函数
:
...爱数据LoveData
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )