DatetimeSubtraction#

通常,我们的数据集中会有日期时间变量,我们希望确定它们之间的时间差。例如,如果我们处理金融数据,我们可能会有变量 贷款申请日期,记录客户申请贷款的日期和时间,以及变量 出生日期,记录客户的出生日期。通过这两个变量,我们想要推断出 客户在申请时的年龄。为了做到这一点,我们可以计算 date_of_loan_applicationdate_of_birth 之间的年份差,并将其捕获到一个新变量中。

在另一个例子中,如果我们试图预测房屋的价格,并且我们有关于房屋建造年份的信息,我们可以推断出房屋在销售时的年龄。通常,较老的房屋价格较低。为了计算房屋的年龄,我们只需计算销售日期与建造日期之间的年份差。

Python 程序提供了许多选项来操作 datetime 对象,例如 datetime 模块。由于您很可能使用 Pandas 数据框,我们将重点介绍 pandas,然后介绍如何使用 Feature-engine 自动化该过程。

使用 pandas 减去 datetime 特征#

在Python中,我们可以使用pandas减去datetime对象。要在pandas中处理datetime变量,我们需要确保时间戳(可以以各种格式表示,如字符串(str)、对象("O")或datetime)被转换为datetime。如果没有,我们可以通过执行 pd.to_datetime(df[variable_of_interest]) 将字符串转换为datetime对象。

让我们创建一个包含2个日期时间变量的玩具数据框,用于一个简短的演示:

import numpy as np
import pandas as pd

data = pd.DataFrame({
    "date1": pd.date_range("2019-03-05", periods=5, freq="D"),
    "date2": pd.date_range("2018-03-05", periods=5, freq="W")})

print(data)

这是我们创建的数据,包含两个日期时间变量:

       date1      date2
0 2019-03-05 2018-03-11
1 2019-03-06 2018-03-18
2 2019-03-07 2018-03-25
3 2019-03-08 2018-04-01
4 2019-03-09 2018-04-08

现在,我们可以利用 pandas 的减法运算符将 date2date1 中减去,并将差值捕获到一个新的变量中:

data["diff"] = data["date1"].sub(data["date2"])

print(data)

表示天数差异的新变量位于数据框的右侧:

       date1      date2     diff
0 2019-03-05 2018-03-11 359 days
1 2019-03-06 2018-03-18 353 days
2 2019-03-07 2018-03-25 347 days
3 2019-03-08 2018-04-01 341 days
4 2019-03-09 2018-04-08 335 days

如果我们希望时间单位不是天,我们可以使用 numpy 的 timedelta。以下示例展示了如何使用此语法:

data["diff"] = data["date1"].sub(data["date2"], axis=0).div(
    np.timedelta64(1, "Y").astype("timedelta64[ns]"))

print(data)

我们现在看到新的变量现在表示年份的差异,在数据框的右侧:

       date1      date2      diff
0 2019-03-05 2018-03-11  0.982909
1 2019-03-06 2018-03-18  0.966481
2 2019-03-07 2018-03-25  0.950054
3 2019-03-08 2018-04-01  0.933626
4 2019-03-09 2018-04-08  0.917199

如果你想减去不同的 datetime 变量,你必须为每次减法编写代码行。幸运的是,我们可以使用 DatetimeSubstraction() 来自动化这个过程。

使用 Feature-engine 进行日期时间减法#

DatetimeSubstraction() 自动从彼此中减去多个日期和时间特征。你只需要在 variables 参数中指示减法操作右侧的特征,并在 reference 参数中指示左侧的特征。你还可以通过 output_unit 参数更改输出单位。

DatetimeSubstraction() 适用于 dtype 为 datetime 的变量,以及对象类型和分类变量,前提是它们可以解析为 datetime 格式。这将在转换器的后台完成。

继续前面的例子,以下是我们如何使用 DatetimeSubstraction() 获取天数差异:

import pandas as pd
from feature_engine.datetime import DatetimeSubtraction

data = pd.DataFrame({
    "date1": pd.date_range("2019-03-05", periods=5, freq="D"),
    "date2": pd.date_range("2018-03-05", periods=5, freq="W")})

dtf = DatetimeSubtraction(
    variables="date1",
    reference="date2",
    output_unit="Y")

data = dtf.fit_transform(data)

print(data)

通过 transform()DatetimeSubstraction() 返回一个新的数据框,包含原始变量以及带有时间差的新变量:

       date1      date2  date1_sub_date2
0 2019-03-05 2018-03-11         0.982909
1 2019-03-06 2018-03-18         0.966481
2 2019-03-07 2018-03-25         0.950054
3 2019-03-08 2018-04-01         0.933626
4 2019-03-09 2018-04-08         0.917199

计算后丢弃原始变量#

我们可以在计算后选择删除原始的日期时间变量:

import pandas as pd
from feature_engine.datetime import DatetimeSubtraction

data = pd.DataFrame({
    "date1": pd.date_range("2019-03-05", periods=5, freq="D"),
    "date2": pd.date_range("2018-03-05", periods=5, freq="W")})

dtf = DatetimeSubtraction(
    variables="date1",
    reference="date2",
    output_unit="M",
    drop_original=True
)

data = dtf.fit_transform(data)

print(data)

在这种情况下,生成的数据框仅包含两个原始变量之间的时间差:

   date1_sub_date2
0        11.794903
1        11.597774
2        11.400645
3        11.203515
4        11.006386

同时减去多个变量#

我们可以同时执行多次减法。在这个例子中,我们将新的日期时间变量作为字符串添加到玩具数据框中。这个想法是为了展示 DatetimeSubstraction() 将在幕后将这些字符串转换为日期时间以执行减法操作。

import pandas as pd
from feature_engine.datetime import DatetimeSubtraction

data = pd.DataFrame({
    "date1" : ["2022-09-01", "2022-10-01", "2022-12-01"],
    "date2" : ["2022-09-15", "2022-10-15", "2022-12-15"],
    "date3" : ["2022-08-01", "2022-09-01", "2022-11-01"],
    "date4" : ["2022-08-15", "2022-09-15", "2022-11-15"],
})

dtf = DatetimeSubtraction(variables=["date1", "date2"], reference=["date3", "date4"])

data = dtf.fit_transform(data)

print(data)

生成的数据框包含原始变量以及表示日期对象之间时间差的新变量。

        date1       date2       date3       date4  date1_sub_date3  \
0  2022-09-01  2022-09-15  2022-08-01  2022-08-15             31.0
1  2022-10-01  2022-10-15  2022-09-01  2022-09-15             30.0
2  2022-12-01  2022-12-15  2022-11-01  2022-11-15             30.0

   date2_sub_date3  date1_sub_date4  date2_sub_date4
0             45.0             17.0             31.0
1             44.0             16.0             30.0
2             44.0             16.0             30.0

处理缺失值#

默认情况下,DatetimeSubstraction() 如果在传递给 fit()transform() 方法的数据框中,减法变量包含 NA,则会引发错误。我们可以通过将参数 missing_values 设置为 "ignore" 来覆盖此行为,并允许在包含 nan 的变量之间进行计算。以下是一个代码示例:

import numpy as np
import pandas as pd
from feature_engine.datetime import DatetimeSubtraction

data = pd.DataFrame({
    "date1" : ["2022-09-01", "2022-10-01", "2022-12-01"],
    "date2" : ["2022-09-15", np.nan, "2022-12-15"],
    "date3" : ["2022-08-01", "2022-09-01", "2022-11-01"],
    "date4" : ["2022-08-15", "2022-09-15", np.nan],
})

dtf = DatetimeSubtraction(
    variables=["date1", "date2"],
    reference=["date3", "date4"],
    missing_values="ignore")

data = dtf.fit_transform(data)

print(data)

当任何变量包含 NAN 时,带有时间差的新特征也将显示 NAN:

        date1       date2       date3       date4  date1_sub_date3  \
0  2022-09-01  2022-09-15  2022-08-01  2022-08-15             31.0
1  2022-10-01         NaN  2022-09-01  2022-09-15             30.0
2  2022-12-01  2022-12-15  2022-11-01         NaN             30.0

   date2_sub_date3  date1_sub_date4  date2_sub_date4
0             45.0             17.0             31.0
1              NaN             16.0              NaN
2             44.0              NaN              NaN

处理不同的时区#

如果我们有来自不同时区的时间戳或变量,我们仍然可以通过首先将所有时间戳设置为通用中央时区,使用 DatetimeSubstraction() 进行减法操作。以下是一个代码示例,我们返回以微秒为单位的时间差:

import pandas as pd
from feature_engine.datetime import DatetimeSubtraction

data = pd.DataFrame({
    "date1": ['12:34:45+3', '23:01:02-6', '11:59:21-8', '08:44:23Z'],
    "date2": ['09:34:45+1', '23:01:02-6+1', '11:59:21-8-2', '08:44:23+3']
})

dfts = DatetimeSubtraction(
    variables="date1",
    reference="date2",
    utc=True,
    output_unit="ms",
    format="mixed"
)

new = dfts.fit_transform(data)

print(new)

我们看到结果数据框中以微秒为单位的时间差:

        date1         date2  date1_sub_date2
0  12:34:45+3    09:34:45+1        3600000.0
1  23:01:02-6  23:01:02-6+1       25200000.0
2  11:59:21-8  11:59:21-8-2       21600000.0
3   08:44:23Z    08:44:23+3       10800000.0

将任意名称添加到新变量#

通常,我们只想计算几个时间差。在这种情况下,我们可能也希望为新变量分配特定的名称。在这个代码示例中,我们就是这样做的:

import pandas as pd
from feature_engine.datetime import DatetimeSubtraction

data = pd.DataFrame({
    "date1": pd.date_range("2019-03-05", periods=5, freq="D"),
    "date2": pd.date_range("2018-03-05", periods=5, freq="W")})

dtf = DatetimeSubtraction(
    variables="date1",
    reference="date2",
    new_variables_names=["my_new_var"]
    )

data = dtf.fit_transform(data)

print(data)

在生成的数据框中,我们看到时间差异被捕获在一个名为 my_new_var 的变量中:

       date1      date2  my_new_var
0 2019-03-05 2018-03-11       359.0
1 2019-03-06 2018-03-18       353.0
2 2019-03-07 2018-03-25       347.0
3 2019-03-08 2018-04-01       341.0
4 2019-03-09 2018-04-08       335.0

我们应该注意传递一个包含尽可能多新变量名称的变量列表。将要创建的变量数量是通过将参数 variables 中的变量数量乘以参数 reference 中的变量数量得到的。

get_feature_names_out()#

最后,我们可以提取转换后的数据框的名称,以与 Scikit-learn 管道兼容:

import pandas as pd
from feature_engine.datetime import DatetimeSubtraction

data = pd.DataFrame({
    "date1" : ["2022-09-01", "2022-10-01", "2022-12-01"],
    "date2" : ["2022-09-15", "2022-10-15", "2022-12-15"],
    "date3" : ["2022-08-01", "2022-09-01", "2022-11-01"],
    "date4" : ["2022-08-15", "2022-09-15", "2022-11-15"],
})

dtf = DatetimeSubtraction(variables=["date1", "date2"], reference=["date3", "date4"])
dtf.fit(data)

dtf.get_feature_names_out()

以下是应用 transform() 方法后,任何数据框中将出现的变量名称:

['date1',
 'date2',
 'date3',
 'date4',
 'date1_sub_date3',
 'date2_sub_date3',
 'date1_sub_date4',
 'date2_sub_date4']

结合提取和减去日期时间特征#

我们还可以通过减去日期时间变量来结合从日期时间特征创建数值变量与创建新特征:

import pandas as pd
from sklearn.pipeline import Pipeline
from feature_engine.datetime import DatetimeFeatures, DatetimeSubtraction

data = pd.DataFrame({
    "date1" : ["2022-09-01", "2022-10-01", "2022-12-01"],
    "date2" : ["2022-09-15", "2022-10-15", "2022-12-15"],
    "date3" : ["2022-08-01", "2022-09-01", "2022-11-01"],
    "date4" : ["2022-08-15", "2022-09-15", "2022-11-15"],
})

dtf = DatetimeFeatures(variables=["date1", "date2"], drop_original=False)
dts = DatetimeSubtraction(
    variables=["date1", "date2"],
    reference=["date3", "date4"],
    drop_original=True,
)

pipe = Pipeline([
    ("features", dtf),("subtraction", dts)
])

data = pipe.fit_transform(data)

print(data)

在以下输出中,我们看到包含从不同日期时间变量中提取的特征的新数据框,随后是捕获时间差异创建的特征:

   date1_month  date1_year  date1_day_of_week  date1_day_of_month  date1_hour  \
0            9        2022                  3                   1           0
1           10        2022                  5                   1           0
2           12        2022                  3                   1           0

   date1_minute  date1_second  date2_month  date2_year  date2_day_of_week  \
0             0             0            9        2022                  3
1             0             0           10        2022                  5
2             0             0           12        2022                  3

   date2_day_of_month  date2_hour  date2_minute  date2_second  \
0                  15           0             0             0
1                  15           0             0             0
2                  15           0             0             0

   date1_sub_date3  date2_sub_date3  date1_sub_date4  date2_sub_date4
0             31.0             45.0             17.0             31.0
1             30.0             44.0             16.0             30.0
2             30.0             44.0             16.0             30.0

其他资源#

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

../../_images/feml.png

机器学习的特征工程#

../../_images/fetsf.png

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











或者阅读我们的书:

../../_images/cookbook.png

Python 特征工程手册#














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