【Kaggle纽约出租车车程用时预测实战(3)】多样式数据特征工程

1、时间特征

1) 首先回顾一下数据

print( ' train shape ',train.shape)
print( ' test shape ',test.shape)

–> 输出的结果为:

 train shape  (1458644, 11)
 test shape  (625134, 9)

2) 提取时间特征

① 先举个小栗子:假使存在df1和df2数据如下

df1 = pd.DataFrame(np.random.randn(10,2))
df1['time'] = pd.period_range('2020/3/1',periods=10)

df2 = pd.DataFrame(np.random.randn(10,2))
df2['time'] = pd.period_range('2020/3/1',periods=10)

–> 输出的结果为:(以df1为例,查看数据,df2数据几乎是类似)
在这里插入图片描述
② 如果想同时将df1df2里面的'time'字段都单独提取出年月日的数据,可以直接使用遍历循环,如下,然后进行一次操作即可满足要求

for df in (df1,df2):
    df['year'] = df['time'].dt.year
    df['month'] = df['time'].dt.month
    df['day'] = df['time'].dt.day

–> 输出的结果为:(这次查看一下df2中的数据,可以看到数据已经被拆分了)
在这里插入图片描述
③ 因此可以使用便利循环对测试数据和训练数据的时间字段进行具体时间刻度的提取,如下

for df in (train,test):
    df['year']  = df['pickup_datetime'].dt.year
    df['month'] = df['pickup_datetime'].dt.month
    df['day']   = df['pickup_datetime'].dt.day
    df['hr']    = df['pickup_datetime'].dt.hour
    df['minute']= df['pickup_datetime'].dt.minute
    df['store_and_fwd_flag'] = 1 * (df.store_and_fwd_flag.values == 'Y')
    #这个是出租车运营厂商的数据字段

④ 根据kaggle比赛的要求,将预测的形成使用log的方式表示,在最后加了评分标准的字段,这一步可以参照之前处理左转或者右转的字段

train = train.assign(log_trip_duration = np.log(train.trip_duration+1))
2. 假期信息判断

存在两种可能性,一个是当前时间是属于正常的周末,还有一个就是属于法定的节假日,判断的话,需要两个知识点的储备

① 指定长度的列表的创建

ls_ = [0]*10

ls_ = np.zeros(10)

–> 输出的结果为:(上面两种方式都可以输出指定长度的列表,一般创建指定长度的列表是用来存放数据的,至于最初里面是什么数据是没有影响的)

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

② 如何判断是否是周末,pands里面有进行周末判断的方法,如下

#date(yy,mm,dd).isoweekday() in (6,7) date为datetime里面的模块
from datetime import date
date(2020,3,22).isoweekday() in (6,7)

–> 输出的结果为:(今天是属于周末)

True

1) 封装函数,判断时间是否属于假期

def restday(year,month,day,holidays):
    is_rest    = [None]*len(year)
    is_weekend = [None]*len(year)
    i=0
    for yy,mm,dd in zip(year,month,day):        
        is_weekend[i] = date(yy,mm,dd).isoweekday() in (6,7)
        is_rest[i]    = is_weekend[i] or date(yy,mm,dd) in holidays 
        i+=1
    return is_rest,is_weekend

接着调用函数,对测试数据和训练数据进行假期字段的信息添加假期字段信息

rest_day,weekend = restday(train.year,train.month,train.day,holidays)
train['rest_day'] = rest_day
train['weekend'] = weekend

rest_day,weekend = restday(test.year,test.month,test.day,holidays)
test['rest_day'] = rest_day
test['weekend'] = weekend

train['pickup_time'] = train.hr+train.minute/60
test['pickup_time'] = test.hr+test.minute/60

–> 输出的结果为:(以测试数据上的内容进行部分展示)
在这里插入图片描述
2) 进行时段的划分

既然获取了具体的时间,那么就可以把时间进行精细化处理,比如划分为早晚高峰,白天或者黑夜等,还是遍历循环,这样在测试集和训练集上就都可以实现相应字段的修改

for df in (train,test):

    df['hr_categori'] = np.nan #创建一个空字段,选择一个内容进行占位,不影响后面数据的插入
    df.loc[(df.rest_day == False)&(df.hr <= 9)&(df.hr >= 7), 'hr_categori'] = "rush"
    df.loc[(df.rest_day == False)&(df.hr <= 18)&(df.hr >= 16), 'hr_categori'] = "rush"
    df.loc[(df.rest_day == False)&(df.hr < 16)&(df.hr > 9), 'hr_categori'] = "day"
    df.loc[(df.rest_day == False)&(df.hr < 7)|(df.hr > 18), 'hr_categori'] = "night"
    df.loc[(df.rest_day == True)&(df.hr < 18)&(df.hr > 7), 'hr_categori'] = "day"
    df.loc[(df.rest_day == True)&(df.hr <= 7)|(df.hr >= 18), 'hr_categori'] = "night"

3) 查看特征维度

print( ' train shape ',train.shape)
print( ' test shape ',test.shape)

–> 输出的结果为:(可以发现多出来一个特征)

 train shape  (1458644, 21)
 test shape  (625134, 18)

这个特征就是kaggle比赛上面要求的,评价标准

print([i for i in train.columns if i not in test.columns])

–> 输出的结果为:

['dropoff_datetime', 'trip_duration', 'log_trip_duration']
3. 整合距离数据

前面已经处理过了距离数据相关的信息,这里可以直接加载到测试和训练数据集上面来

train = train.join(osrm_data.set_index('id'), on='id')
test = test.join(osrm_test.set_index('id'), on='id')

print( ' train shape ',train.shape)
print( ' test shape ',test.shape)

–> 输出的结果为:(可使用join方式合并数据,也可以使用pd.merge方法进行合并,增加的特征就是之前处理过后的距离数据的字段)

 train shape  (1458644, 26)
 test shape  (625134, 23)
4. 整合天气数据

1) 按照重要字段进行数据整合

天气中下雪对行车速度的影响是最大的,这里挑选该字段进行整合

weather['snow']= 1*(weather.Events=='Snow') + 1*(weather.Events=='Fog\n\t,\nSnow')
weather['year'] = weather['Time'].dt.year
weather['month'] = weather['Time'].dt.month
weather['day'] = weather['Time'].dt.day
weather['hr'] = weather['Time'].dt.hour
weather = weather[weather['year'] == 2016][['month','day','hr','Temp.','Precip','snow','Visibility']]
print(weather.shape)
print(weather.head())

–> 输出的结果为:(获取年月日是为了进行数据的合并,可以只获得一个字段的信息,即可进行数据匹配)

(8739, 7)

	month	day	hr	Temp.	Precip	snow	Visibility
22	1		1	0	5.6		0.0		0		16.1
23	1		1	1	5.6		0.0		0		16.1
24	1		1	2	5.6		0.0		0		16.1
25	1		1	3	5.0		0.0		0		16.1
26	1		1	4	5.0		0.0		0		16.1

然后将处理后的数据添加到测试及训练集上,因为该数据量只用8000多,远远低于测试及训练集数据,所以在合并的时候注意合并方式

train = pd.merge(train, weather, on = ['month', 'day', 'hr'], how = 'left')
test = pd.merge(test, weather, on = ['month', 'day', 'hr'], how = 'left')

2)查看特征数据的维度

print( ' train shape ',train.shape)
print( ' test shape ',test.shape)

–> 输出的结果为:(已经达到30个了)

 train shape  (1458644, 30)
 test shape  (625134, 27)
5. 聚类确定所属区域

前面在进行纽约市出租车车程的聚类时候是直接将所有的上车及下车的经纬度全部组合在一块了,发现运行的过程是十分的缓慢。由于接触过深度学习,在模型训练的时候可以将数据划分批次然后再进行训练,这样数据量是没有发生变化的,但是训练的速度是有着显著的提高。

1) 组合数据

之前是放在列表里,现在为了进行批次的训练,需要将数据转化为所需要的数据类型

coords = np.vstack((train[['pickup_latitude', 'pickup_longitude']].values,
                    train[['dropoff_latitude', 'dropoff_longitude']].values,
                    test[['pickup_latitude', 'pickup_longitude']].values,
                    test[['dropoff_latitude', 'dropoff_longitude']].values))
print(coords)

–> 输出的结果为:

[[ 40.76793671, -73.98215485],
 [ 40.73856354, -73.98041534],
 [ 40.7639389 , -73.97902679],
 ...,
 [ 40.74866486, -73.87660217],
 [ 40.89178848, -73.85426331],
 [ 40.76937866, -73.96932983]]

2) 按批次进行聚类分析

随机抽取部分数据,然后按照批次进行整理输出(np.random.permutation())。类似于深度学习里面的一个batch一个batch进行训练,这里也不再使用KMeans,而是使用下面的一个分支 MiniBatchKMeans,这就和深度学习里面的模型训练对应上了,这里的一个batch的大小为10000个数据量

sample_ind = np.random.permutation(len(coords))[:1000000]
kmeans = MiniBatchKMeans(n_clusters=8, batch_size=10000).fit(coords[sample_ind])

3) 模型预测

根据已经拟合好的聚类的模型,按照输入的上车及下车的经纬度,给出测试集和和训练集中对应上下车区域的类别判断(其中的数字并不是代表着大小,仅仅是聚类后的标号)

train.loc[:, 'pickup_cluster'] = kmeans.predict(train[['pickup_latitude', 'pickup_longitude']])
train.loc[:, 'dropoff_cluster'] = kmeans.predict(train[['dropoff_latitude', 'dropoff_longitude']])
test.loc[:, 'pickup_cluster'] = kmeans.predict(test[['pickup_latitude', 'pickup_longitude']])
test.loc[:, 'dropoff_cluster'] = kmeans.predict(test[['dropoff_latitude', 'dropoff_longitude']])

train[['pickup_latitude', 'pickup_longitude','dropoff_latitude', 'dropoff_longitude','pickup_cluster','dropoff_cluster']].head()

–> 输出的结果为:

	pickup_latitude	pickup_longitude	dropoff_latitude	dropoff_longitude	pickup_cluster	dropoff_cluster
0	40.767937		-73.982155			40.765602			-73.964630			5				1
1	40.738564		-73.980415			40.731152			-73.999481			5				0
2	40.763939		-73.979027			40.710087			-74.005333			5				0
3	40.719971		-74.010040			40.706718			-74.012268			0				0
4	40.793209		-73.973053			40.782520			-73.972923			1				1

4) 查看数据特征维度

print( ' train shape ',train.shape)
print( ' test shape ',test.shape)

–> 输出的结果为:

 train shape  (1458644, 32)
 test shape  (625134, 29)
6. 确定各区域类的平均车速

各区域类的平均车速的确定,首先是要获取平均速度,然后再利用上一步获取的区域分类的数据,在进行区域和速度字段的数据汇总即可

1) 确定平均速度

train['speed'] = train['total_distance'] / train['trip_duration']
train[['speed','total_distance','trip_duration']].head()

–> 输出的结果为:(进行数据的查看)
在这里插入图片描述
2) 确定各区域中平均车速

首先获得各区域内上下车的次数

a = pd.concat([train,test]).groupby(['pickup_cluster']).size().reset_index()
b = pd.concat([train,test]).groupby([ 'dropoff_cluster']).size().reset_index()

–> 输出的结果为:(a中的数据)
在这里插入图片描述
–> 输出的结果为:(b中的数据,可以看出上车次数多的区域对应着下车次数也较多)
在这里插入图片描述
接着将数据整整合到测试和训练数据上

train = pd.merge(train, a, on = ['pickup_cluster'], how = 'left')
test = pd.merge(test, a, on = ['pickup_cluster'], how = 'left')

train = pd.merge(train, b, on = ['dropoff_cluster'], how = 'left')
test = pd.merge(test, b, on = ['dropoff_cluster'], how = 'left')

最后获取各区域直接的平均速度

pick_up_speed = train[['speed', 'pickup_cluster']].groupby(['pickup_cluster']).mean().reset_index()
pick_up_speed = pick_up_speed.rename(columns = {'speed': 'ave_pickup_speed'})
drop_off_speed = train[['speed', 'dropoff_cluster']].groupby(['dropoff_cluster']).mean().reset_index()
drop_off_speed = drop_off_speed.rename(columns = {'speed': 'ave_dropoff_speed'})

3) 数据查看

print(pick_up_speed)
print(drop_off_speed)

–> 输出的结果为:

   pickup_cluster  ave_pickup_speed
0               0          5.067469
1               1          5.494199
2               2          0.000000
3               3         11.242965
4               4          8.405111
5               5          5.047294
6               6         12.841142
7               7          6.225725

   dropoff_cluster  ave_dropoff_speed
0                0           4.986800
1                1           5.976817
2                2           0.000000
3                3          11.935437
4                4           8.552266
5                5           4.691077
6                6          35.699330
7                7           6.885238

4) 将平均速度添加到数据并删除’speed’字段

train = pd.merge(train, pick_up_speed, on = ['pickup_cluster'], how = 'left')
test = pd.merge(test, pick_up_speed, on = ['pickup_cluster'], how = 'left')

train = pd.merge(train, drop_off_speed, on = ['dropoff_cluster'], how = 'left')
test = pd.merge(test, drop_off_speed, on = ['dropoff_cluster'], how = 'left')

train = train.drop(['speed'], axis = 1)

5) 查看特征数据维度

print( ' train shape ',train.shape)
print( ' test shape ',test.shape)

print(train.columns)

–> 输出的结果为:

 train shape  (1458644, 36)
 test shape  (625134, 33)

['id', 'vendor_id', 'pickup_datetime', 'dropoff_datetime',
 'passenger_count', 'pickup_longitude', 'pickup_latitude',
 'dropoff_longitude', 'dropoff_latitude', 'store_and_fwd_flag',
 'trip_duration', 'year', 'month', 'day', 'hr', 'minute',
 'log_trip_duration', 'rest_day', 'weekend', 'pickup_time',
 'hr_categori', 'total_distance', 'total_travel_time', 'number_of_steps',
 'right_steps', 'left_steps', 'Temp.', 'Precip', 'snow', 'Visibility',
 'pickup_cluster', 'dropoff_cluster', '0_x', '0_y', 'ave_pickup_speed',
 'ave_dropoff_speed']
原创文章 159 获赞 93 访问量 4万+

猜你喜欢

转载自blog.csdn.net/lys_828/article/details/104767951