In [1]: import pandas as pd

In [2]: import matplotlib.pyplot as plt
本教程使用的数据:
  • 在本教程中,空气质量数据有关\(NO_2\)使用小于 2.5 微米的颗粒物,由OpenAQ提供 并使用 py-openaq包下载。数据air_quality_no2_long.csv"集提供\(NO_2\)分别位于巴黎、安特卫普和伦敦的测量站FR04014BETR801伦敦威斯敏斯特的值。

    至原始数据
    In [3]: air_quality = pd.read_csv("data/air_quality_no2_long.csv")
    
    In [4]: air_quality = air_quality.rename(columns={"date.utc": "datetime"})
    
    In [5]: air_quality.head()
    Out[5]: 
        city country                   datetime location parameter  value   unit
    0  Paris      FR  2019-06-21 00:00:00+00:00  FR04014       no2   20.0  µg/m³
    1  Paris      FR  2019-06-20 23:00:00+00:00  FR04014       no2   21.8  µg/m³
    2  Paris      FR  2019-06-20 22:00:00+00:00  FR04014       no2   26.5  µg/m³
    3  Paris      FR  2019-06-20 21:00:00+00:00  FR04014       no2   24.9  µg/m³
    4  Paris      FR  2019-06-20 20:00:00+00:00  FR04014       no2   21.4  µg/m³
    
    In [6]: air_quality.city.unique()
    Out[6]: array(['Paris', 'Antwerpen', 'London'], dtype=object)
    

如何轻松处理时间序列数据#

使用 pandas 日期时间属性#

  • 我想将列中的日期用作datetime日期时间对象而不是纯文本

    In [7]: air_quality["datetime"] = pd.to_datetime(air_quality["datetime"])
    
    In [8]: air_quality["datetime"]
    Out[8]: 
    0      2019-06-21 00:00:00+00:00
    1      2019-06-20 23:00:00+00:00
    2      2019-06-20 22:00:00+00:00
    3      2019-06-20 21:00:00+00:00
    4      2019-06-20 20:00:00+00:00
                      ...           
    2063   2019-05-07 06:00:00+00:00
    2064   2019-05-07 04:00:00+00:00
    2065   2019-05-07 03:00:00+00:00
    2066   2019-05-07 02:00:00+00:00
    2067   2019-05-07 01:00:00+00:00
    Name: datetime, Length: 2068, dtype: datetime64[ns, UTC]
    

    最初,中的值datetime是字符串,不提供任何日期时间操作(例如提取年份、星期几……)。通过应用该to_datetime函数,pandas 解释字符串并将它们转换为日期时间(即)对象。在 pandas 中,我们将这些日期时间对象称为类似于 标准库中的。datetime64[ns, UTC]datetime.datetimepandas.Timestamp

笔记

由于许多数据集的其中一列中确实包含日期时间信息,因此 pandas 输入函数(例如pandas.read_csv()和 )可以在使用带有要读取为时间戳的列列表的参数pandas.read_json() 读取数据时进行日期转换 :parse_dates

pd.read_csv("../data/air_quality_no2_long.csv", parse_dates=["datetime"])

为什么这些pandas.Timestamp对象有用?让我们通过一些示例来说明附加值。

我们正在使用的时间序列数据集的开始日期和结束日期是哪天?

In [9]: air_quality["datetime"].min(), air_quality["datetime"].max()
Out[9]: 
(Timestamp('2019-05-07 01:00:00+0000', tz='UTC'),
 Timestamp('2019-06-21 00:00:00+0000', tz='UTC'))

使用pandas.Timestamp日期时间使我们能够使用日期信息进行计算并使它们具有可比性。因此,我们可以用它来获取时间序列的长度:

In [10]: air_quality["datetime"].max() - air_quality["datetime"].min()
Out[10]: Timedelta('44 days 23:00:00')

结果是一个pandas.Timedelta对象,类似于datetime.timedelta 标准 Python 库并定义持续时间。

转至用户指南

pandas 支持的各种时间概念在用户指南中有关时间相关概念的部分进行了解释。

  • 我想向DataFrame仅包含测量月份的新列添加

    In [11]: air_quality["month"] = air_quality["datetime"].dt.month
    
    In [12]: air_quality.head()
    Out[12]: 
        city country                  datetime  ... value   unit  month
    0  Paris      FR 2019-06-21 00:00:00+00:00  ...  20.0  µg/m³      6
    1  Paris      FR 2019-06-20 23:00:00+00:00  ...  21.8  µg/m³      6
    2  Paris      FR 2019-06-20 22:00:00+00:00  ...  26.5  µg/m³      6
    3  Paris      FR 2019-06-20 21:00:00+00:00  ...  24.9  µg/m³      6
    4  Paris      FR 2019-06-20 20:00:00+00:00  ...  21.4  µg/m³      6
    
    [5 rows x 8 columns]
    

    通过使用Timestamp日期对象,pandas 提供了许多与时间相关的属性。例如month, , 还有 year, quarter,... 所有这些属性都可以由dt访问器访问。

转至用户指南

时间和日期组件概述表中给出了现有日期属性的概述 。有关返回类似日期时间属性的访问器的更多详细信息将在有关dt 访问器dt的专门部分中进行说明。

  • 平均值是多少\(NO_2\)每个测量位置一周中每一天的浓度?

    In [13]: air_quality.groupby(
       ....:     [air_quality["datetime"].dt.weekday, "location"])["value"].mean()
       ....: 
    Out[13]: 
    datetime  location          
    0         BETR801               27.875000
              FR04014               24.856250
              London Westminster    23.969697
    1         BETR801               22.214286
              FR04014               30.999359
                                      ...    
    5         FR04014               25.266154
              London Westminster    24.977612
    6         BETR801               21.896552
              FR04014               23.274306
              London Westminster    24.859155
    Name: value, Length: 21, dtype: float64
    

    还记得统计计算教程groupby中 提供的拆分-应用-组合模式吗?在这里,我们想要计算给定的统计数据(例如平均值\(NO_2\)) 每个工作日每个测量位置。为了在工作日进行分组,我们使用 pandas 的 datetime 属性weekday(星期一 = 0 和星期日 = 6)Timestamp,该属性也可以由 dt访问器访问。可以对地点和工作日进行分组,以拆分每个组合的平均值计算。

    危险

    由于我们在这些示例中使用的时间序列非常短,因此分析无法提供长期的代表性结果!

  • 绘制典型的\(NO_2\)我们将所有站点的时间序列放在一起的白天模式。换句话说,一天中每个小时的平均值是多少?

    In [14]: fig, axs = plt.subplots(figsize=(12, 4))
    
    In [15]: air_quality.groupby(air_quality["datetime"].dt.hour)["value"].mean().plot(
       ....:     kind='bar', rot=0, ax=axs
       ....: )
       ....: 
    Out[15]: <Axes: xlabel='datetime'>
    
    In [16]: plt.xlabel("Hour of the day");  # custom x label using Matplotlib
    
    In [17]: plt.ylabel("$NO_2 (µg/m^3)$");
    
    ../../_images/09_bar_chart.png

    与前面的情况类似,我们想要计算给定的统计量(例如平均值\(NO_2\)对于一天中的每个小时,我们可以再次使用拆分-应用-组合方法。对于本例,我们使用hour pandas 的datetime 属性Timestamp,该属性也可由dt访问器访问。

日期时间作为索引#

在重塑教程中, pivot()介绍了如何重塑数据表,将每个测量位置作为单独的列:

In [18]: no_2 = air_quality.pivot(index="datetime", columns="location", values="value")

In [19]: no_2.head()
Out[19]: 
location                   BETR801  FR04014  London Westminster
datetime                                                       
2019-05-07 01:00:00+00:00     50.5     25.0                23.0
2019-05-07 02:00:00+00:00     45.0     27.7                19.0
2019-05-07 03:00:00+00:00      NaN     50.4                19.0
2019-05-07 04:00:00+00:00      NaN     61.9                16.0
2019-05-07 05:00:00+00:00      NaN     72.4                 NaN

笔记

通过旋转数据,日期时间信息成为表的索引。一般来说,将某列设置为索引可以通过该set_index函数来实现。

使用日期时间索引(即DatetimeIndex)提供了强大的功能。例如,我们不需要dt访问器来获取时间序列属性,而是直接在索引上使用这些属性:

In [20]: no_2.index.year, no_2.index.weekday
Out[20]: 
(Index([2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019,
        ...
        2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019],
       dtype='int32', name='datetime', length=1033),
 Index([1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        ...
        3, 3, 3, 3, 3, 3, 3, 3, 3, 4],
       dtype='int32', name='datetime', length=1033))

其他一些优点是方便的时间段子集或绘图上的适应时间尺度。让我们将其应用到我们的数据上。

  • 创建一个情节\(NO_2\)5月20日至21月底各站值

    In [21]: no_2["2019-05-20":"2019-05-21"].plot();
    
    ../../_images/09_time_section.png

    通过提供解析为日期时间的字符串,可以在 上选择数据的特定子集DatetimeIndex

转至用户指南

有关时间序列索引DatetimeIndex的部分提供了有关使用字符串进行切片的更多信息。

将时间序列重新采样到另一个频率#

  • 将当前每小时时间序列值聚合到每个站的每月最大值。

    In [22]: monthly_max = no_2.resample("ME").max()
    
    In [23]: monthly_max
    Out[23]: 
    location                   BETR801  FR04014  London Westminster
    datetime                                                       
    2019-05-31 00:00:00+00:00     74.5     97.0                97.0
    2019-06-30 00:00:00+00:00     52.5     84.7                52.0
    

    对于具有日期时间索引的时间序列数据,一种非常强大的方法是将时间序列转换为另一个频率的能力resample()(例如,将第二个数据转换为 5 分钟数据)。

resample()方法类似于groupby操作:

  • 它通过使用定义目标频率的字符串(例如M,, ...)提供基于时间的分组5H

  • 它需要一个聚合函数,例如mean, max,...

转至用户指南

偏移别名概述表中给出了用于定义时间序列频率的别名的概述。

定义后,时间序列的频率由属性提供 freq

In [24]: monthly_max.index.freq
Out[24]: <MonthEnd>
  • 绘制每日平均值图\(NO_2\)每个站的值。

    In [25]: no_2.resample("D").mean().plot(style="-o", figsize=(10, 5));
    
    ../../_images/09_resample_mean.png
转至用户指南

有关时间序列功能的更多详细信息,resampling请参阅用户指南中有关重采样的部分。

记住

  • to_datetime有效的日期字符串可以使用函数或作为读取函数的一部分转换为日期时间对象 。

  • pandas 中的日期时间对象支持使用访问器进行计算、逻辑运算和方便的日期相关属性dt

  • ADatetimeIndex包含这些与日期相关的属性并支持方便的切片。

  • Resample是更改时间序列频率的有效方法。

转至用户指南

时间序列和日期功能页面上给出了时间序列的完整概述。