Pandas DateTime 超強總結
攜手創作,共同成長!這是我參與「掘金日新計劃 · 8 月更文挑戰」的第26天,點擊查看活動詳情
對於 Pandas 來説,可以處理眾多的數據類型,其中最有趣和最重要的數據類型之一就是時間序列數據。時間序列數據無處不在,它在各個行業都有很多應用。患者健康指標、股票價格變化、天氣記錄、經濟指標、服務器、網絡、傳感器和應用程序性能監控都是時間序列數據的應用方向
我們可以將時間序列數據定義為在不同時間間隔獲得並按時間順序排列的數據點的集合
Pandas 基本上是為分析金融時間序列數據而開發的,併為處理時間、日期和時間序列數據提供了一整套全面的框架
今天我們來討論在 Pandas 中處理日期和時間的多個方面,具體包含如下內容: - Timestamp 和 Period 對象的功能 - 如何使用時間序列 DataFrames - 如何對時間序列進行切片 - DateTimeIndex 對象及其方法 - 如何重新採樣時間序列數據
探索 Pandas 時間戳和週期對象
Pandas 庫提供了一個名為 Timestamp 的具有納秒精度的 DateTime 對象來處理日期和時間值。Timestamp 對象派生自 NumPy 的 datetime64 數據類型,使其比 Python 的 DateTime 對象更準確而且更快。下面讓我們使用 Timestamp 構造函數創建一些 Timestamp 對象。 ```Python 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:
Text
1982-09-04 01:35:10
1982-09-04 01:35:10
1982-09-04 01:35:10
如果將單個整數或浮點值傳遞給 Timestamp 構造函數,它會返回一個時間戳,該時間戳等於 Unix 紀元(1970 年 1 月 1 日)之後的納秒數:
Python
print(pd.Timestamp(5000))
Output:
Text
1970-01-01 00:00:00.000005
Timestamp 對象包含許多方法和屬性,可幫助我們訪問時間戳的不同功能。讓我們嘗試一下:
Python
time_stamp = pd.Timestamp('2022-02-09')
print('{}, {} {}, {}'.format(time_stamp.day_name(), time_stamp.month_name(), time_stamp.day, time_stamp.year))
Output:
Text
Wednesday, February 9, 2022
```
Timestamp 類的一個實例代表一個時間點,而 Period 對象的一個實例代表一個時期,例如一年、一個月等
例如,公司在一年的時間裏監控他們的收入。Pandas 庫提供了一個名為 Period 的對象來處理,如下所示:
Python
year = pd.Period('2021')
display(year)
Output:
Text
Period('2021', 'A-DEC')
我們可以看到它創建了一個代表 2021 年期間的 Period 對象,而“A-DEC”表示該期間是年度的,在 12 月結束
Period 對象提供了許多有用的方法和屬性。例如,如果要返回期間的開始和結束時間,可以使用以下屬性:
Python
print('Start Time:', year.start_time)
print('End Time:', year.end_time)
Output:
Text
Start Time: 2021-01-01 00:00:00
End Time: 2021-12-31 23:59:59.999999999
要創建每月期間,可以將特定月份傳遞給它,如下所示
Python
month = pd.Period('2022-01')
display(month)
print('Start Time:', month.start_time)
print('End Time:', month.end_time)
Output:
```Text
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 日期間的期間對象:
Python
day = pd.Period('2022-01', freq='D')
display(day)
print('Start Time:', day.start_time)
print('End Time:', day.end_time)
Output:
Text
Period('2022-01-01', 'D')
Start Time: 2022-01-01 00:00:00
End Time: 2022-01-01 23:59:59.999999999
我們還可以對週期對象執行算術運算。讓我們創建一個每小時頻率的新 period 對象,看看我們如何進行計算:
Python
hour = pd.Period('2022-02-09 16:00:00', freq='H')
display(hour)
display(hour + 2)
display(hour - 2)
Output:
Text
Period('2022-02-09 16:00', 'H')
Period('2022-02-09 18:00', 'H')
Period('2022-02-09 14:00', 'H')
我們可以使用 Pandas 日期偏移量獲得相同的結果:
Python
display(hour + pd.offsets.Hour(+2))
display(hour + pd.offsets.Hour(-2))
Output:
Text
Period('2022-02-09 18:00', 'H')
Period('2022-02-09 14:00', 'H')
要創建日期序列,可以使用 pandas range_dates() 方法。讓我們在代碼片段中嘗試一下:
Python
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:
Text
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 台服務器相關的關鍵信息:
Python
df = pd.read_csv('http://raw.githubusercontent.com/m-mehdi/pandas_tutorials/main/server_util.csv')
display(df.head())
Output:
Text
datetime server_id cpu_utilization free_memory session_count
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
讓我們看一下 DataFrame 的內容。每個 DataFrame 行代表服務器的基本性能指標,包括特定時間戳的 CPU 利用率、可用內存和會話計數。DataFrame 分解為一小時的片段。例如,從午夜到凌晨 4 點記錄的性能指標位於 DataFrame 的前五行
現在,讓我們詳細瞭解一下 DataFrame 的特性,例如它的大小和每列的數據類型:
Python
print(df.info())
Output:
Text
<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() 方法,如下:
Python
df['datetime'] = pd.to_datetime(df['datetime'])
當我們通過導入 CSV 文件創建 DataFrame 時,日期/時間值被視為字符串對象,而不是 DateTime 對象。pandas to_datetime() 方法將存儲在 DataFrame 列中的日期/時間值轉換為 DateTime 對象。將日期/時間值作為 DateTime 對象使操作它們變得更加容易。 運行以下語句並查看更改:
Python
print(df.info())
Output:
Text
<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() 方法更直接。讓我們嘗試一下:
Python
df = pd.read_csv('http://raw.githubusercontent.com/m-mehdi/pandas_tutorials/main/server_util.csv', parse_dates=['datetime'])
print(df.head())
Output:
Text
datetime server_id cpu_utilization free_memory session_count
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
運行上面的代碼會創建一個 DataFrame,其中 datetime 列的數據類型是 DateTime 對象
下面讓我們對 datetime 列應用一些基本方法
首先,讓我們看看如何在 DataFrame 中返回最早和最晚的日期。為此,我們可以簡單地在 datetime 列上應用 max() 和 min() 方法,如下所示:
Python
display(df.datetime.min())
display(df.datetime.max())
Output:
```Text
Timestamp('2019-03-06 00:00:00')
Timestamp('2019-04-08 23:00:00')
要選擇兩個特定日期之間的 DataFrame 行,我們可以創建一個布爾掩碼並使用 .loc 方法過濾特定日期範圍內的行:
Python
mask = (df.datetime >= pd.Timestamp('2019-03-06')) & (df.datetime < pd.Timestamp('2019-03-07'))
display(df.loc[mask])
Output:
Text
datetime server_id cpu_utilization free_memory session_count
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
… … … … … …
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 方法:
Python
df.set_index('datetime', inplace=True)
print(df)
Output:
```Text
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-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 方法選擇等於單個索引的所有行:
Python
print(df.loc['2019-03-07 02:00:00'].head(5))
Output:
Text
datetime server_id cpu_utilization free_memory session_count
2019-03-07 02:00:00 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
可以選擇與索引列中的特定時間戳部分匹配的行。讓我們嘗試一下:
Python
print(df.loc['2019-03-07'].head(5))
Output:
Text
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
選擇字符串可以是任何標準的日期格式,我們來看一些例子:
Python
df.loc['Apr 2019']
df.loc['8th April 2019']
df.loc['April 05, 2019 5pm']
我們還可以使用 .loc 方法對日期範圍內的行進行切片。以下語句將返回從 2019 年 4 月 3 日到 2019 年 4 月 4 日結束的所有行; 開始日期和結束日期都包括在內:
Python
display(df.loc['03-04-2019':'04-04-2019'])
但是運行它會引發一個令人討厭的未來警告。為了擺脱警告,我們可以在切片行之前對索引進行排序:
Python
display(df.sort_index().loc['03-04-2019':'04-04-2019'])
Output:
Text
datetime server_id cpu_utilization free_memory session_count
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
36000 rows × 4 columns
```
DateTimeIndex 方法
某些 pandas DataFrame 方法僅適用於 DateTimeIndex。下面我們來具體看一下,首先讓我們確保我們的 DataFrame 有一個 DateTimeIndex:
Python
print(type(df.index))
Output:
Text
<class 'pandas.core.indexes.datetimes.DatetimeIndex'>
要返回在特定時間收集的服務器監控數據,無論日期如何,請使用 at_time() 方法:
Python
display(df.at_time('09:00'))
Output:
Text
datetime server_id cpu_utilization free_memory session_count
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
1700 rows × 4 columns
此外,要選擇所有日期午夜和凌晨 2 點之間的所有服務器數據,可以使用 between_time() 方法。 讓我們嘗試一下:
Python
display(df.between_time('00:00','02:00'))
Output:
Text
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
2019-03-07 01:00:00 100 0.46 0.50 49
… … … … …
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 進行排序,以確保這些方法有效。讓我們試試這兩個例子:
Python
display(df.sort_index().first('5B'))
Output:
Text
datetime server_id cpu_utilization free_memory session_count
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
Python
display(df.sort_index().last('1W'))
Output:
Text
datetime server_id cpu_utilization free_memory session_count
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
2019-04-08 00:00:00 110 0.61 0.40 62
… … … … …
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
1200 rows × 4 columns
Python
df.sort_index().last('2W')
Output:
Text
datetime server_id cpu_utilization free_memory session_count
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
重新採樣時間序列數據
resample() 方法背後的邏輯類似於 groupby() 方法。它在任何可能的時間段內對數據進行分組。雖然我們可以使用 resample() 方法進行上採樣和下采樣,但我們將重點介紹如何使用它來執行下采樣,這會降低時間序列數據的頻率——例如,將每小時的時間序列數據轉換為每日或 每日時間序列數據到每月
以下示例返回服務器 ID 100 每天的平均 CPU 利用率、可用內存和活動會話計數。 為此,我們首先需要過濾 DataFrame 中服務器 ID 為 100 的行,然後將每小時數據重新採樣為每日數據。 最後,對結果應用 mean() 方法,得到三個指標的每日平均值:
Python
df[df.server_id == 100].resample('D')['cpu_utilization', 'free_memory', 'session_count'].mean()
Output:
Text
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 利用率和可用內存。讓我們嘗試一下:
Python
df.groupby(df.server_id).resample('M')['cpu_utilization', 'free_memory'].max()
Output:
Text
server_id datetime cpu_utilization free_memory
100 2019-03-31 0.56 0.62
2019-04-30 0.55 0.61
101 2019-03-31 0.91 0.32
2019-04-30 0.89 0.30
102 2019-03-31 0.85 0.36
… … … …
147 2019-04-30 0.61 0.57
148 2019-03-31 0.84 0.35
2019-04-30 0.83 0.34
149 2019-03-31 0.85 0.36
2019-04-30 0.83 0.34
100 rows × 2 columns
下面讓我們繪製每個服務器每月的平均 CPU 利用率,結果使我們能夠充分了解每個服務器的平均 CPU 利用率在幾個月內的變化
Python
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 Comparison')
Output:
Text
<AxesSubplot:title={'center':'The Average Monthly CPU Utilization Comparison'}, xlabel='server_id,datetime'>
寫在最後
Pandas 是一種出色的分析工具,尤其是在處理時間序列數據時。該庫提供了廣泛的工具來處理時間索引的 DataFrame
好了,這就是今天分享的內容,如果喜歡就點個贊吧~
- 用 Python 爬取股票實時數據
- Pandas DateTime 超強總結
- 原來使用 Pandas 繪製圖表也這麼驚豔!
- 蘿蔔爆肝Python自學學習路線
- Pandas GroupBy 深度總結
- 爬取近千張女神赫本的美照,做成網站並給其中的黑白照片上色,好玩!
- 兩個使用 Pandas 讀取結構不良 Excel 的方法,拿走不謝
- 爬取貓眼《長津湖》影評,分析觀影羣眾信息,還進行了明日票房預測,好玩!
- 十一將近,Python 帶你分析哪裏適合去
- 最新的B站彈幕和評論爬蟲,你們要的冰冰來啦!
- 動畫 | 論正確“借鑑”技術文的幾種等級
- 用Java實現人工智能?開玩笑!
- 數據分析入門系列教程-微博爬取
- 數據分析入門系列教程-數據採集
- 數據分析入門系列教程-數據清洗