DatetimeFeatures#

在数据科学和机器学习项目中常用的数据集中,变量通常包含日期和时间的信息。**出生日期**和**购买时间**是这些变量的两个例子。它们通常被称为“日期时间特征”,即数据类型为日期和时间的数据。

我们通常不会在原始格式中使用日期时间变量来训练机器学习模型,例如用于回归、分类或聚类的模型。相反,我们可以通过提取日期时间变量的不同日期和时间组件来从中提取大量信息。

日期和时间组件的示例包括年份、月份、一年中的第几周、一周中的第几天、小时、分钟和秒。

使用 pandas 处理日期时间特征#

在Python中,我们可以通过开源库pandas的`dt`模块提取日期和时间组件。例如,通过执行以下操作:

data = pd.DataFrame({"date": pd.date_range("2019-03-05", periods=20, freq="D")})

data["year"] = data["date"].dt.year
data["quarter"] = data["date"].dt.quarter
data["month"] = data["date"].dt.month

在前面的代码块中,我们从时间戳变量中创建了3个特征:季度*和*月

使用 Feature-engine 的日期时间特征#

DatetimeFeatures() 自动从日期时间变量中提取多个日期和时间特征。它适用于数据类型为日期时间的变量,以及可以解析为日期时间格式的对象类型和分类变量。它*不能*从数值变量中提取特征。

DatetimeFeatures() 在底层使用了 pandas 的 dt 模块,因此自动化了日期时间特征工程。通过指定我们想要使用 DatetimeFeatures() 创建的特征,我们可以在两行代码中同时从各种变量中创建多个日期和时间变量。

DatetimeFeatures() 可以自动创建 pandas dt 支持的所有特征以及更多,例如,一个指示事件是否发生在周末的二进制特征,以及学期。

使用 DatetimeFeatures() 我们可以选择从日期时间变量中提取哪些日期和时间特征。我们还可以同时从一个或多个日期时间变量中提取日期和时间特征。

通过以下示例,我们突出了 DatetimeFeatures() 在表格数据中的功能和多功能性。

提取日期特征#

在这个例子中,我们将从一个数据框的特定变量中提取三个 日期特征。特别地,我们感兴趣的是 月份一年中的第几天,以及那天是否是 该月的最后一天

首先,我们将创建一个包含2个日期变量的玩具数据框:

import pandas as pd
from feature_engine.datetime import DatetimeFeatures

toy_df = pd.DataFrame({
    "var_date1": ['May-1989', 'Dec-2020', 'Jan-1999', 'Feb-2002'],
    "var_date2": ['06/21/2012', '02/10/1998', '08/03/2010', '10/31/2020'],
})

现在,我们将从数据集中的第二个日期时间变量中提取变量月份、月末和年中的天数。

dtfs = DatetimeFeatures(
    variables="var_date2",
    features_to_extract=["month", "month_end", "day_of_year"]
)

df_transf = dtfs.fit_transform(toy_df)

df_transf

通过 transform(),从 datetime 变量中提取的特征被添加到数据框中。

我们在以下输出中看到新功能:

  var_date1  var_date2_month  var_date2_month_end  var_date2_day_of_year
0  May-1989                6                    0                    173
1  Dec-2020                2                    0                     41
2  Jan-1999                8                    0                    215
3  Feb-2002               10                    1                    305

默认情况下,DatetimeFeatures() 会删除从中提取日期和时间特征的变量,在本例中为 var_date2。要保留该变量,我们只需在初始化转换器时指定 drop_original=False

最后,我们可以如下获取返回数据中的变量名称:

dtfs.get_feature_names_out()
['var_date1',
 'var_date2_month',
 'var_date2_month_end',
 'var_date2_day_of_year']

提取时间特征#

在这个例子中,我们将从数据集中的两个时间变量中提取 分钟 特征。

首先,让我们创建一个包含2个时间变量和一个对象变量的玩具数据集。

import pandas as pd
from feature_engine.datetime import DatetimeFeatures

toy_df = pd.DataFrame({
    "not_a_dt": ['not', 'a', 'date', 'time'],
    "var_time1": ['12:34:45', '23:01:02', '11:59:21', '08:44:23'],
    "var_time2": ['02:27:26', '10:10:55', '17:30:00', '18:11:18'],
})

DatetimeFeatures() 自动查找所有可以解析为日期时间的变量。因此,如果我们想从所有日期时间变量中提取时间特征,我们不需要指定它们。

请注意,从版本2.0.0开始,pandas弃用了参数 infer_datetime_format。因此,如果你想让pandas推断日期时间格式并且你有不同的格式,你需要通过将 "mixed" 传递给 format 参数来明确表示,如下所示。

dfts = DatetimeFeatures(features_to_extract=["minute"], format="mixed")

df_transf = dfts.fit_transform(toy_df)

df_transf

我们在以下输出中看到新功能:

  not_a_dt  var_time1_minute  var_time2_minute
0      not                34                27
1        a                 1                10
2     date                59                30
3     time                44                11

转换器在数据框中发现了两个可以转换为日期时间的变量,并从中提取了请求的特征。

被检测为日期时间的变量存储在转换器的 variables_ 属性中:

dfts.variables_
['var_time1', 'var_time2']

原始的 datetime 变量默认从数据中删除。这使得数据集准备好用于训练线性回归或随机森林等机器学习算法。

如果我们想保留datetime变量,只需在初始化转换器时指定 drop_original=False

最后,如果我们想要获取输出数据中的变量名称,我们可以使用:

dfts.get_feature_names_out()
['not_a_dt', 'var_time1_minute', 'var_time2_minute']

提取日期和时间特征#

在这个例子中,我们将结合前两个例子中看到的内容,从包含日期和时间信息的两个变量中提取日期特征 - 年份 - 和时间特征 - 小时

让我们继续创建一个包含3个日期时间变量的玩具数据集。

import pandas as pd
from feature_engine.datetime import DatetimeFeatures

toy_df = pd.DataFrame({
    "var_dt1": pd.date_range("2018-01-01", periods=3, freq="H"),
    "var_dt2": ['08/31/00 12:34:45', '12/01/90 23:01:02', '04/25/01 11:59:21'],
    "var_dt3": ['03/02/15 02:27:26', '02/28/97 10:10:55', '11/11/03 17:30:00'],
})

现在,我们设置 DatetimeFeatures() 从两个日期时间变量中提取特征。在这种情况下,我们不希望在提取特征后删除日期时间变量。

dfts = DatetimeFeatures(
    variables=["var_dt1", "var_dt3"],
    features_to_extract=["year", "hour"],
    drop_original=False,
    format="mixed",
)
df_transf = dfts.fit_transform(toy_df)

df_transf

我们可以在以下输出中看到生成的数据框:

              var_dt1            var_dt2            var_dt3  var_dt1_year  \
0 2018-01-01 00:00:00  08/31/00 12:34:45  03/02/15 02:27:26          2018
1 2018-01-01 01:00:00  12/01/90 23:01:02  02/28/97 10:10:55          2018
2 2018-01-01 02:00:00  04/25/01 11:59:21  11/11/03 17:30:00          2018

   var_dt1_hour  var_dt3_year  var_dt3_hour
0             0          2015             2
1             1          1997            10
2             2          2003            17

就是这样。新功能现在已添加到数据框中。

时间序列#

时间序列数据由按时间顺序索引的数据点组成。时间通常在数据框的索引中。我们可以从时间戳索引中提取特征,并将它们用于时间序列回归或分类,以及时间序列预测。

通过 DatetimeFeatures() ,我们还可以从数据框索引中创建日期和时间特征。

让我们创建一个带有日期时间索引的玩具数据框。

import pandas as pd

X = {"ambient_temp": [31.31, 31.51, 32.15, 32.39, 32.62, 32.5, 32.52, 32.68],
     "module_temp": [49.18, 49.84, 52.35, 50.63, 49.61, 47.01, 46.67, 47.52],
     "irradiation": [0.51, 0.79, 0.65, 0.76, 0.42, 0.49, 0.57, 0.56],
     "color": ["green"] * 4 + ["blue"] * 4,
     }

X = pd.DataFrame(X)
X.index = pd.date_range("2020-05-15 12:00:00", periods=8, freq="15min")

X.head()

下面我们看到我们的玩具数据框的输出:

                     ambient_temp  module_temp  irradiation  color
2020-05-15 12:00:00         31.31        49.18         0.51  green
2020-05-15 12:15:00         31.51        49.84         0.79  green
2020-05-15 12:30:00         32.15        52.35         0.65  green
2020-05-15 12:45:00         32.39        50.63         0.76  green
2020-05-15 13:00:00         32.62        49.61         0.42   blue

我们可以如下从索引中提取特征:

from feature_engine.datetime import DatetimeFeatures

dtf = DatetimeFeatures(variables="index")

Xtr = dtf.fit_transform(X)

Xtr

我们可以看到,转换器创建了默认的时间特征,并将它们添加到数据框的末尾。

                     ambient_temp  module_temp  irradiation  color  month  \
2020-05-15 12:00:00         31.31        49.18         0.51  green      5
2020-05-15 12:15:00         31.51        49.84         0.79  green      5
2020-05-15 12:30:00         32.15        52.35         0.65  green      5
2020-05-15 12:45:00         32.39        50.63         0.76  green      5
2020-05-15 13:00:00         32.62        49.61         0.42   blue      5
2020-05-15 13:15:00         32.50        47.01         0.49   blue      5
2020-05-15 13:30:00         32.52        46.67         0.57   blue      5
2020-05-15 13:45:00         32.68        47.52         0.56   blue      5

                     year  day_of_week  day_of_month  hour  minute  second
2020-05-15 12:00:00  2020            4            15    12       0       0
2020-05-15 12:15:00  2020            4            15    12      15       0
2020-05-15 12:30:00  2020            4            15    12      30       0
2020-05-15 12:45:00  2020            4            15    12      45       0
2020-05-15 13:00:00  2020            4            15    13       0       0
2020-05-15 13:15:00  2020            4            15    13      15       0
2020-05-15 13:30:00  2020            4            15    13      30       0
2020-05-15 13:45:00  2020            4            15    13      45       0

我们可以按如下方式获取输出数据框中所有变量的名称:

dtf.get_feature_names_out()
['ambient_temp',
 'module_temp',
 'irradiation',
 'color',
 'month',
 'year',
 'day_of_week',
 'day_of_month',
 'hour',
 'minute',
 'second']

重要#

我们强烈建议指定您希望从日期时间变量中提取的日期和时间特征。

如果你有太多的时间变量,这可能是不可能的。在这种情况下,请记住,如果你从只有时间的变量中提取日期特征,或者从只有日期的变量中提取时间特征,你的特征将是没有意义的。

让我们通过一个例子来探讨结果。我们创建一个仅包含时间变量的数据集。

import pandas as pd
from feature_engine.datetime import DatetimeFeatures

toy_df = pd.DataFrame({
    "not_a_dt": ['not', 'a', 'date', 'time'],
    "var_time1": ['12:34:45', '23:01:02', '11:59:21', '08:44:23'],
    "var_time2": ['02:27:26', '10:10:55', '17:30:00', '18:11:18'],
})

现在我们错误地只提取日期特征:

dfts = DatetimeFeatures(
    features_to_extract=["year", "month", "day_of_week"],
    format="mixed",
)
df_transf = dfts.fit_transform(toy_df)

df_transf
  not_a_dt  var_time1_year  var_time1_month  var_time1_day_of_week  var_time2_year \
0      not            2021               12                      2            2021
1        a            2021               12                      2            2021
2     date            2021               12                      2            2021
3     time            2021               12                      2            2021

   var_time2_month  var_time2_day_of_week
0               12                      2
1               12                      2
2               12                      2
3               12                      2

转换器仍将创建基于当前日期(文档创建日期)的特征。

如果我们有一个只包含日期变量的数据框:

import pandas as pd
from feature_engine.datetime import DatetimeFeatures

toy_df = pd.DataFrame({
    "var_date1": ['May-1989', 'Dec-2020', 'Jan-1999', 'Feb-2002'],
    "var_date2": ['06/21/12', '02/10/98', '08/03/10', '10/31/20'],
})

而我们错误地提取了小时和分钟:

dfts = DatetimeFeatures(
    features_to_extract=["hour", "minute"],
    format="mixed",
)
df_transf = dfts.fit_transform(toy_df)

print(df_transf)
   var_date1_hour  var_date1_minute  var_date2_hour  var_date2_minute
0               0                 0               0                 0
1               0                 0               0                 0
2               0                 0               0                 0
3               0                 0               0                 0

新特性将包含值 0。

自动化特征提取#

我们可以通过在列表中传递特征名称,来指示我们希望从日期时间变量中提取哪些特征,就像在前面的示例中所做的那样。

另外,DatetimeFeatures() 有默认选项来提取一组常用的特征,或者所有支持的特征。

首先创建一个玩具数据框:

import pandas as pd
from feature_engine.datetime import DatetimeFeatures

toy_df = pd.DataFrame({
    "var_dt1": pd.date_range("2018-01-01", periods=3, freq="H"),
    "var_dt2": ['08/31/00 12:34:45', '12/01/90 23:01:02', '04/25/01 11:59:21'],
    "var_dt3": ['03/02/15 02:27:26', '02/28/97 10:10:55', '11/11/03 17:30:00'],
})

最常见的功能#

现在,我们将从其中一个变量中提取**最常见**的日期和时间特征。为此,我们将参数 features_to_extract 保留为 None

dfts = DatetimeFeatures(
    variables=["var_dt1"],
    features_to_extract=None,
    drop_original=False,
)

df_transf = dfts.fit_transform(toy_df)

df_transf
              var_dt1            var_dt2            var_dt3  var_dt1_month  \
0 2018-01-01 00:00:00  08/31/00 12:34:45  03/02/15 02:27:26              1
1 2018-01-01 01:00:00  12/01/90 23:01:02  02/28/97 10:10:55              1
2 2018-01-01 02:00:00  04/25/01 11:59:21  11/11/03 17:30:00              1

   var_dt1_year  var_dt1_day_of_week  var_dt1_day_of_month  var_dt1_hour  \
0          2018                    0                     1             0
1          2018                    0                                   1
2          2018                    0                  1                2

    var_dt1_minute    var_dt1_second
0               0                  0
1               0                  0
2               0                  0

我们的新数据集包含了原始特征以及从这些特征中提取的新变量。

我们可以在其属性中找到由转换器提取的特征组:

dfts.features_to_extract_
['month',
 'year',
 'day_of_week',
 'day_of_month',
 'hour',
 'minute',
 'second']

所有支持的功能#

我们也可以通过将参数 features_to_extract 设置为 "all" 来自动提取所有支持的功能:

dfts = DatetimeFeatures(
    variables=["var_dt1"],
    features_to_extract='all',
    drop_original=False,
)

df_transf = dfts.fit_transform(toy_df)

print(df_transf)
              var_dt1            var_dt2            var_dt3  var_dt1_month  \
0 2018-01-01 00:00:00  08/31/00 12:34:45  03/02/15 02:27:26              1
1 2018-01-01 01:00:00  12/01/90 23:01:02  02/28/97 10:10:55              1
2 2018-01-01 02:00:00  04/25/01 11:59:21  11/11/03 17:30:00              1

   var_dt1_quarter  var_dt1_semester  var_dt1_year  \
0                1                 1          2018
1                1                 1          2018
2                1                 1          2018

   var_dt1_week  var_dt1_day_of_week  ...  var_dt1_month_end  var_dt1_quarter_start  \
0             1                    0  ...                  0                      1
1             1                    0  ...                  0                      1
2             1                    0  ...                  0                      1

   var_dt1_quarter_end  var_dt1_year_start  var_dt1_year_end  \
0                    0                   1                 0
1                    0                   1                 0
2                    0                   1                 0

   var_dt1_leap_year  var_dt1_days_in_month  var_dt1_hour  var_dt1_minute  \
0                  0                     31             0               0
1                  0                     31             1               0
2                  0                     31             2               0

   var_dt1_second
0               0
1               0
2               0

我们可以在其属性中找到由转换器提取的特征组:

dfts.features_to_extract_
['month',
 'quarter',
 'semester',
 'year',
 'week',
 'day_of_week',
 'day_of_month',
 'day_of_year',
 'weekend',
 'month_start',
 'month_end',
 'quarter_start',
 'quarter_end',
 'year_start',
 'year_end',
 'leap_year',
 'days_in_month',
 'hour',
 'minute',
 'second']

自动提取和选择特征#

如果我们有一个包含日期变量、时间变量以及日期和时间变量的数据框,我们可以提取所有特征,或者从所有变量中提取最常见的特征,然后使用 DropConstantFeatures() 类继续移除不相关的特征。

让我们创建一个包含混合日期时间变量的数据框。

import pandas as pd
from sklearn.pipeline import Pipeline
from feature_engine.datetime import DatetimeFeatures
from feature_engine.selection import DropConstantFeatures

toy_df = pd.DataFrame({
    "var_date": ['06/21/12', '02/10/98', '08/03/10', '10/31/20'],
    "var_time1": ['12:34:45', '23:01:02', '11:59:21', '08:44:23'],
    "var_dt": ['08/31/00 12:34:45', '12/01/90 23:01:02', '04/25/01 11:59:21', '04/25/01 11:59:21'],
})

现在,我们在 Scikit-learn 管道中排列 DatetimeFeaturesDropConstantFeatures()DatetimeFeatures 将为时间变量创建从今天派生的日期特征,并为仅日期变量创建值为 0 的时间特征。DropConstantFeatures() 将识别并从数据集中删除这些特征。

pipe = Pipeline([
    ('datetime', DatetimeFeatures(format="mixed")),
    ('drop_constant', DropConstantFeatures()),
])

pipe.fit(toy_df)
Pipeline(steps=[('datetime', DatetimeFeatures()),
                ('drop_constant', DropConstantFeatures())])
df_transf = pipe.transform(toy_df)

print(df_transf)
   var_date_month  var_date_year  var_date_day_of_week  var_date_day_of_month  \
0               6           2012                     3                     21
1               2           1998                     1                     10
2               8           2010                     1                      3
3              10           2020                     5                     31

   var_time1_hour  var_time1_minute  var_time1_second  var_dt_month  \
0              12                34                45             8
1              23                 1                 2            12
2              11                59                21             4
3               8                44                23             4

   var_dt_year  var_dt_day_of_week  var_dt_day_of_month  var_dt_hour  \
0         2000                   3                   31           12
1         1990                   5                    1           23
2         2001                   2                   25           11
3         2001                   2                   25           11

   var_dt_minute   var_dt_second
0             34              45
1              1               2
2             59              21
3             59              21

如你所见,我们在转换后的数据集中没有常量特征。

处理不同的时区#

时间感知的日期时间变量在格式处理上可能会特别麻烦。我们将简要展示 DatetimeFeatures() 在三种不同场景下如何处理这些变量。

案例 1:我们的数据集包含一个以对象格式表示的时间感知变量,不同观测值之间可能存在不同的时区。我们在初始化转换器时传递 utc=True,以确保它将所有数据转换为 UTC 时区。

import pandas as pd
from feature_engine.datetime import DatetimeFeatures

toy_df = pd.DataFrame({
    "var_tz": ['12:34:45+3', '23:01:02-6', '11:59:21-8', '08:44:23Z']
})

dfts = DatetimeFeatures(
    features_to_extract=["hour", "minute"],
    drop_original=False,
    utc=True,
    format="mixed",
)

df_transf = dfts.fit_transform(toy_df)

df_transf
       var_tz  var_tz_hour  var_tz_minute
0  12:34:45+3            9             34
1  23:01:02-6            5              1
2  11:59:21-8           19             59
3   08:44:23Z            8             44

案例 2:我们的数据集中包含一个变量,该变量被转换为特定时区的本地化日期时间。然而,我们决定希望将所有日期时间信息提取为如同在UTC时区一样。

import pandas as pd
from feature_engine.datetime import DatetimeFeatures

var_tz = pd.Series(['08/31/00 12:34:45', '12/01/90 23:01:02', '04/25/01 11:59:21'])
var_tz = pd.to_datetime(var_tz, format="mixed")
var_tz = var_tz.dt.tz_localize("US/eastern")
var_tz
0   2000-08-31 12:34:45-04:00
1   1990-12-01 23:01:02-05:00
2   2001-04-25 11:59:21-04:00
dtype: datetime64[ns, US/Eastern]

在初始化转换器时,我们需要传递 utc=True 以恢复到UTC时区。

toy_df = pd.DataFrame({"var_tz": var_tz})

dfts = DatetimeFeatures(
    features_to_extract=["day_of_month", "hour"],
    drop_original=False,
    utc=True,
)

df_transf = dfts.fit_transform(toy_df)

df_transf
                     var_tz  var_tz_day_of_month  var_tz_hour
0 2000-08-31 12:34:45-04:00                   31           16
1 1990-12-01 23:01:02-05:00                    2            4
2 2001-04-25 11:59:21-04:00                   25           15

案例 3:在上述示例中,给定一个变量如 var_tz,我们现在希望提取特征时保留原始时区本地化,因此我们传递 utc=FalseNone。在这种情况下,我们将其保留为 None,这是默认选项。

dfts = DatetimeFeatures(
    features_to_extract=["day_of_month", "hour"],
    drop_original=False,
    utc=None,
)

df_transf = dfts.fit_transform(toy_df)

print(df_transf)
                     var_tz  var_tz_day_of_month  var_tz_hour
0 2000-08-31 12:34:45-04:00                   31           12
1 1990-12-01 23:01:02-05:00                    1           23
2 2001-04-25 11:59:21-04:00                   25           11

注意,从这个数据框中提取的小时与在 案例2 中获得的小时不同。

缺少时间戳#

DatetimeFeatures 可以选择忽略缺失的时间戳,或者在遇到日期时间变量中的缺失值时引发错误。

附加资源#

你可以在以下 Jupyter notebook 中找到如何使用 DatetimeFeatures() 处理真实数据集的示例。

有关如何创建和使用 datetime 列功能的教程,请查看以下课程:

../../_images/feml.png

机器学习的特征工程#

../../_images/fetsf.png

时间序列预测的特征工程#











或者阅读我们的书:

../../_images/cookbook.png

Python 特征工程手册#














我们的书籍和课程都适合初学者和更高级的数据科学家。通过购买它们,您正在支持 Feature-engine 的主要开发者 Sole。