<p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2020%2F0905%2F05b0f00ej00qg5wxa0033c000ob00g8c.jpg&thumbnail=660x&quality=80&type=jpg"/><br/></p><p>维基百科对于特征工程的定义是:利用相关领域知识,通过数据挖掘技术从原始数据中提取特征的过程。这些特征可以用来提高机器学习算法的性能。</p><p>不过,特征工程不一定非得很花哨。特征工程的一个简单但普遍的处理对象是时间序列数据。特征工程在这个领域的重要性是因为(原始)时间序列数据通常只包含一个表示时间属性的列,即日期时间(或时间戳)。</p><p>对于日期时间数据,特征工程可以看作是从独立的(不同的)特征数据中提取有用的信息。例如,从“2020–07–01 10:21:05”这日期时间数据中,我们可能需要从中提取以下特征:</p><p>1. 月份:7</p><p>1. 本月第几日:1</p><p>1. 周几:周三(通过2020-07-01判断得到)</p><p>1. 时刻:10:21:05</p><p>从日期时间数据中提取这类特征正是本文的目标。之后,我们将结合我们的工程实际中的特征数据,将其作为预测因子,并且建立一个gradient boosting 回归预测模型。具体来说,我们将预测地铁州际交通量。</p><p><h5>本文目录</h5></p><p>本文主要包含以下内容:</p><p><strong>详细阐述如何从时间日期数据中提取以下特征数据:</strong></p><p>1. 月份</p><p>1. 时间数据处于每月第几日</p><p>1. 周几</p><p>1. 时间</p><p>1. 时段分类(早上、下午等)</p><p>1. 周末标记(如果是周末则添加标记1,否则添加标记0)</p><p><strong>如何将上述特种数据用于搭建Gradient Boosting 回归模型,并且实现对于地铁州际交通量的预测</strong></p><p><h5>数据情况</h5></p><p>在本文中,我们使用地铁州际交通量数据集,它可以在UCI机器学习库(https://archive.ics.uci.edu/ml/datasets/Metro+Interstate+Traffic+Volume)中找到。该数据集是明尼苏达州圣保罗州明尼阿波利斯市I-94的每小时交通量,其中包括2012-2018年的天气和假日数据。这48204行数据包含以下属性:</p><p>1. holiday:类型数据,包含美国国家法定假日、区域假日、明尼苏达州博览会等</p><p>1. temp:数值型数据,平均温度(开尔文)</p><p>1. rain_1h:数值型数据,每小时降雨(毫米)</p><p>1. snow_1h:数值型数据,每小时降雪(毫米)</p><p>1. clouds_all:数值型数据,云层情况(百分比)</p><p>1. weather_main:类型数据,当前天气的分类描述(简要)</p><p>1. weather_description:类型数据,当前天气的分类描述(详细)</p><p>1. data_time:时间序列数据</p><p>1. traffic_volume:数值型数据,每小时I-94 ATR 301记录的西行交通量(本文预测目标)</p><p>接下来,我们首先载入数据:</p><p># import libraries<br/>import pandas as pd<br/>import numpy as np<br/>import matplotlib.pyplot as plt<br/># load the data<br/>raw = pd.read_csv('Metro_Interstate_Traffic_Volume.csv')<br/># display first five rows<br/>raw.head()<br/># display details for each column<br/>raw.info()</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2020%2F0905%2Fe97b9d0ep00qg5wxb000gc000ha003bc.png&thumbnail=660x&quality=80&type=jpg"/><br/></p><p>raw.head()</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2020%2F0905%2Fa1957ce8p00qg5wxb000hc000f30061c.png&thumbnail=660x&quality=80&type=jpg"/><br/></p><p>raw.info()</p><p>查看info信息,我们发现data_time这一类目是object类型,所以我们需要将其转化为datetime类型:</p><p># convert date_time column to datetime type<br/>raw.date_time = pd.to_datetime(raw.date_time)从上面的info方法的输出中,我们知道除了date_time列之外还有其他的分类特征。但是由于本文的主要主题是处理时间序列数据,我们将重点关注针对date_time的特性工程。</p><p><strong>Month</strong></p><p>Pandas自身有许多易于使用的方法来处理datetime类型的数据。要提取时间/日期信息,我们只需调用pd.Series.dt。pd.Series.dt.month是提取month信息所需的函数。这将产生一系列int64格式的月份数字(例如1代表1月,10代表10月)。</p><p># extract month feature<br/>months = raw.date_time.dt.month</p><p><strong>Day of month</strong></p><p>和Month类似,我们只需要调用pd.Series.dt.day函数。以2012-10-27 09:00:00为例,调用该函数提取结果为27。</p><p># extract day of month feature<br/>day_of_months = raw.date_time.dt.day</p><p><strong>Hour</strong></p><p>类似地,pd.Series.dt.hour将生产对应的小时信息数据(范围为0-23的整数)。</p><p># extract hour feature<br/>hours = raw.date_time.dt.hour</p><p><strong>Day name</strong></p><p>获取Day name的方式和上面几个数据有所不同。我们想要确定raw.date_time序列中关于星期几的信息,需要以下两个步骤。首先,通过pd.Series.dt.day_name()生成day name序列。然后,我们需要通过pd.get_dummies()进行独热编码(one-hot encode)。</p><p># first: extract the day name literal<br/>to_one_hot = raw.date_time.dt.day_name()<br/># second: one hot encode to 7 columns<br/>days = pd.get_dummies(to_one_hot)<br/>#display data<br/>days</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2020%2F0905%2Fcap00qg5wx8000bc000dd0078c.png&thumbnail=660x&quality=80&type=jpg"/><br/></p><p><strong>Daypart</strong></p><p>在本部分中,我们将基于Hour数据创建一个分组。我们希望有六个小组代表每一天的各个部分。它们是黎明(02.00-05.59)、上午(06.00-09.59)、中午(10.00-13.59)、下午(14.00-17.59)、晚上(18.00-21.59)和午夜(22.00-次日01.59)。</p><p>为此,我们创建了一个标识函数,稍后将使用该函数来作为数据系列的apply方法。然后,我们对得到的dayparts执行一个热编码。</p><p># daypart function<br/>def daypart(hour):<br/>if hour in [2,3,4,5]:<br/>return "dawn"<br/>elif hour in [6,7,8,9]:<br/>return "morning"<br/>elif hour in [10,11,12,13]:<br/>return "noon"<br/>elif hour in [14,15,16,17]:<br/>return "afternoon"<br/>elif hour in [18,19,20,21]:<br/>return "evening"<br/>else: return "midnight"<br/># utilize it along with apply method<br/>raw_dayparts = hours.apply(daypart)<br/># one hot encoding<br/>dayparts = pd.get_dummies(raw_dayparts)<br/># re-arrange columns for convenience<br/>dayparts = dayparts[['dawn','morning','noon','afternoon','evening','midnight']]<br/>#display data<br/>dayparts</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2020%2F0905%2Fa87d0ff9p00qg5wx9000bc000as0076c.png&thumbnail=660x&quality=80&type=jpg"/><br/></p><p><strong>Weekend flag</strong></p><p>我们从date_time时间序列数据中提取的最后一个特征是is_weekend。这一特征指示给定的日期时间是否在周末(星期六或星期日)。为了实现这一目标,我们将利用pd.Series.dt.day_name()方法以及lambda函数。</p><p># is_weekend flag<br/>day_names = raw.date_time.dt.day_name()<br/>is_weekend = day_names.apply(lambda x : 1 if x in ['Saturday','Sunday'] else 0)</p><p><strong>Holiday flag 以及 weather</strong></p><p>幸运的是,这些数据还包含公共假日信息。信息是细粒度的,因为它提到每个公共假日的名称。尽管如此,本文假设对每个假期进行编码并没有显著的好处。因此,让我们创建一个二进制特性来指示对应的日期是否是假日。</p><p># is_holiday flag<br/>is_holiday = raw.holiday.apply(lambda x : 0 if x == "None" else 1)</p><p>我们需要考虑的最后一个分类特征是天气。我们只对该特征进行如下独热编码。</p><p># one-hot encode weather<br/>weathers = pd.get_dummies(raw.weather_main)<br/>#display data<br/>weathers</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2020%2F0905%2F091e46fap00qg5wx9000dc000gn0073c.png&thumbnail=660x&quality=80&type=jpg"/><br/></p><p><h5>特征处理后的数据</h5></p><p>现在,我们终于有了最终的可用于训练的数据!让我们创建一个名为features的全新数据集,它包含所有的特征,包括数值型特征(我们从原始数据中按原样放置)和类型特征(我们设计的特性)。</p><p># features table<br/>#first step: include features with single column nature<br/>features = pd.DataFrame({<br/>'temp' : raw.temp,<br/>'rain_1h' : raw.rain_1h,<br/>'snow_1h' : raw.snow_1h,<br/>'clouds_all' : raw.clouds_all,<br/>'month' : months,<br/>'day_of_month' : day_of_months,<br/>'hour' : hours,<br/>'is_holiday' : is_holiday,<br/>'is_weekend' : is_weekend<br/>})<br/>#second step: concat with one-hot encode typed features<br/>features = pd.concat([features, days, dayparts, weathers], axis = 1)<br/># target column<br/>target = raw.traffic_volume</p><p>在我们将数据输入模型之前,我们需要分割数据(训练集和测试集)。请注意,下面我们不随机化我们的数据,这是由于我们的数据具有时间序列特征。</p><p>#split data into training and test data<br/>X_train, X_test, y_train, y_test = train_test_split(features, target, test_size=0.1, shuffle = False)</p><p><h5>建立回归预测模型</h5></p><p>现在我们准备建立我们的模型来预测地铁州际交通量。在这项工作中,我们将使用Gradient Boosting回归模型。</p><p>该模型的理论和具体细节超出了本文的讨论范围。但是简单来说,gradient-boosting模型属于集成模型,它使用梯度下降算法来降低弱学习模型(决策树)中的预测损失。</p><p><strong>训练模型</strong></p><p>让我们在训练数据上实例化模型并训练模型!</p><p>from sklearn import datasets, ensemble<br/># define the model parameters<br/>params = {'n_estimators': 500,<br/>'max_depth': 4,<br/>'min_samples_split': 5,<br/>'learning_rate': 0.01,<br/>'loss': 'ls'}<br/># instantiate and train the model<br/>gb_reg = ensemble.GradientBoostingRegressor(params)<br/>gb_reg.fit(X_train, y_train)</p><p><strong>评价模型</strong></p><p>我们选择两个指标来评价模型:MAPE 和 R2得分。在测试集上使用训练完成的模型进行预测,然后计算这两个指标。</p><p># define MAPE function<br/>def mape(true, predicted):<br/>inside_sum = np.abs(predicted - true) / true<br/>return round(100 * np.sum(inside_sum ) / inside_sum.size,2)<br/># import r2 score<br/>from sklearn.metrics import r2_score<br/># evaluate the metrics<br/>y_true = y_test<br/>y_pred = gb_reg.predict(X_test)<br/>#print(f"GB model MSE is {round(mean_squared_error(y_true, y_pred),2)}")<br/>print(f"GB model MAPE is {mape(y_true, y_pred)} %")<br/>print(f"GB model R2 is {round(r2_score(y_true, y_pred)* 100 , 2)} %")</p><p>我们可以看出我们的模型性能相当不错。我们的MAPE低于15%,而R2得分略高于95%。</p><p><strong>结果可视化</strong></p><p>为了直观理解模型性能,结果可视化很有必要。</p><p>由于我们的测试数据(4820个数据点)的长度,我们只绘制了最后100个数据点上的实际值和模型预测值。此外,我们还包括另一个模型(在下面的绘图代码中称为gb_reg_lite),它不包含日期时间特征作为其预测因子(它只包含非日期时间列作为特征,包括temp、weather等)。</p><p>fig, ax = plt.subplots(figsize = (12,6))<br/>index_ordered = raw.date_time.astype('str').tolist()[-len(X_test):][-100:]<br/>ax.set_xlabel('Date')<br/>ax.set_ylabel('Traffic Volume')<br/># the actual values<br/>ax.plot(index_ordered, y_test[-100:].to_numpy(), color='k', ls='-', label = 'actual')<br/># predictions of model with engineered features<br/>ax.plot(index_ordered, gb_reg.predict(X_test)[-100:], color='b', ls='--', label = 'predicted; with date-time features')<br/># predictions of model without engineered features<br/>ax.plot(index_ordered, gb_reg_lite.predict(X_test_lite)[-100:], color='r', ls='--', label = 'predicted; w/o date-time features')<br/>every_nth = 5<br/>for n, label in enumerate(ax.xaxis.get_ticklabels()):<br/>if n % every_nth != 0:<br/>label.set_visible(False)<br/>ax.tick_params(axis='x', labelrotation= 90)<br/>plt.legend()<br/>plt.title('Actual vs predicted on the last 100 data points')<br/>plt.draw()</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2020%2F0905%2Fc4p00qg5wx90030c000j000btc.png&thumbnail=660x&quality=80&type=jpg"/><br/></p><p>该图中蓝色虚线与黑色实线十分接近。也就是说,我们提出的gradient-boosting模型可以很好地预测地铁交通量。</p><p>同时,我们看到不使用日期时间特征的模型在性能上出现了差异(红色虚线)。为什么会这样?只是因为我们会依赖交通工具,交通流量在周末趋于减少,但在高峰时段出现高峰。因此,如果我们不对日期时间数据进行特征工程处理,我们将错过这些重要的预测因子!</p><p>作者:Pararawendy Indarjo</p><p>deephub翻译组 OliverLee</p>
讯享网

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/169347.html