【火炉炼AI】机器学习019-项目案例:使用SVM回归器估算交通流量

【火炉炼AI】机器学习019-项目案例:使用SVM回归器估算交通流量

(本文所使用的Python库和版本号: Python 3.5, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )

我们都知道,SVM是一个很好地分类器,不仅适用于线性分类模型,而且还适用于非线性模型,但是,在另一方面,SVM不仅可以用于解决分类问题,还可以用于解决回归问题。

本项目打算使用SVM回归器来估算交通流量,所使用的方法和过程与我的上一篇文章【火炉炼AI】机器学习018-项目案例:根据大楼进出人数预测是否举办活动非常类似,所采用的数据处理方法也是大同小异。


1. 准备数据集

本项目所使用的数据集来源于UCI大学数据集,很巧合的是,这个数据集与上一篇文章(大楼进出人数)的数据集位于同一个网页中。

1.1 了解数据集

本数据集统计了洛杉矶Dodgers棒球队在主场比赛期间,体育场周围马路通过的车流量,数据存放在两个文件下:Dodgers.data文件和Dodgers.events文件,这两个文件各列的主要说明为:

Dodgers.data中有50400个样本数据,每一行的基本属性为:

Dodgers.data文件中各属性说明

而Dodgers.events文件有中81行数据,每一行数据的基本属性为:

Dodges.events文件中各列属性说明

1.2 数据规整

本项目的数据规整主要是将这两个文件中的内容整合到一个可用的数据集中。

1.2.1 规整之一:读取文件错误及其解决办法

本来,我以为读取这两个文件直接用pd.read_csv()即可,就像我以前的多篇文章中用到的一样,然而,本项目中,直接调用该方法读取文件却报错。

# 1 准备数据集
# 从文件中加载数据集
feature_data_path='E:\PyProjects\DataSet\BuildingInOut/Dodgers.data'
feature_set=pd.read_csv(feature_data_path,header=None)
print(feature_set.info())
# print(feature_set.head()) 
# print(feature_set.tail()) # 检查没有问题

label_data_path='E:\PyProjects\DataSet\BuildingInOut/Dodgers.events'
label_set=pd.read_csv(label_data_path,header=None)
print(label_set.info())
# print(label_set.head())
# print(label_set.tail()) # 读取没有问题,

上面的代码在第二个pd.read_csv()时报以下错误,看来是原始文件的编码出现问题。

-------------------------------------输---------出--------------------------------

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa0 in position 5: invalid start byte

--------------------------------------------完-------------------------------------

查看原始Dodger.events文件,我们可以发现,每一行的末尾有一个不能识别的未知字符。

由于每一行末尾出现未知字符故而不能直接读取内容

此时我的解决办法是:用记事本将Dodger.events文件打开,在“另存为”中,将编码格式修改为"UTF-8",保存为一个新的文件,此时新文件中就没有了未知字符,如下图所示。

将编码格式修改为utf-8后再保存

再用pd.read_csv()就没有任何问题。

1.2.2 规整之二:删除缺失数据,拆分数据

由于Dodger.data文件中的样本存在缺失数据,其车流量为-1的表示缺失数据,对缺失数据的处理方式有很多种,此处由于整个样本量比较大,故而我直接将缺失数据删除。另外,由于原始数据中并不全都是用逗号分隔开,故而需要将列进行分隔,代码如下:

# 删除缺失数据
feature_set2=feature_set[feature_set[1]!=-1] # 只获取不是-1的DataFrame即可。
# print(feature_set2) # 没有问题

feature_set2=feature_set2.reset_index(drop=True)
print(feature_set2.head())
# 第0列既包含日期,又包含时间,故要拆分成两列
need_split_col=feature_set2[0].copy()
feature_set2[0]=need_split_col.map(lambda x: x.split()[0].strip())
feature_set2[2]=need_split_col.map(lambda x: x.split()[1].strip())
print(feature_set2.head()) # 拆分没有问题

-------------------------------------输---------出--------------------------------

0 1
0 4/11/2005 7:35 23
1 4/11/2005 7:40 42
2 4/11/2005 7:45 37
3 4/11/2005 7:50 24
4 4/11/2005 7:55 39
0 1 2
0 4/11/2005 23 7:35
1 4/11/2005 42 7:40
2 4/11/2005 37 7:45
3 4/11/2005 24 7:50
4 4/11/2005 39 7:55

--------------------------------------------完-------------------------------------

1.2.3 规整之三:日期格式的统一化

在我们进行这两个DataFrame的合并和日期比较之前,需要先将这两个DataFrame中的日期格式统一化,从两个文件中读取的日期都是String类型,但是从Dodgers.data中读取的日期格式是如4/11/2005的形式,而从Dodgers.events中读取的日期格式是比如:05/01/05形式,显然这两个String之间难以直接比较。幸好Pandas有内置的to_datetime函数,可以直接将这两种日期进行格式统一化。代码为:

# 将两个DataFrame中的日期格式统一,两个DataFrame中的日期目前还是String类型,格式不统一无法比较
feature_set2[0]=pd.to_datetime(feature_set2[0])
print(feature_set2[0][:5]) # 打印第0列的前5行

label_set[0]=pd.to_datetime(label_set[0])
print(label_set[0][:5])

-------------------------------------输---------出--------------------------------

0 2005-04-11
1 2005-04-11
2 2005-04-11
3 2005-04-11
4 2005-04-11
Name: 0, dtype: datetime64[ns]
0 2005-04-12
1 2005-04-13
2 2005-04-15
3 2005-04-16
4 2005-04-17
Name: 0, dtype: datetime64[ns]

--------------------------------------------完-------------------------------------

1.2.4 规整之四:合并两个文件到一个数据集中

在合并文件的时候,我们要知道哪些特征属性是进行机器学习所必须的,此处我们选择的特征列包括有(日期,时间,对手球队名,是否比赛期间),故而我们需要从Dodgers.data文件中选取日期和时间,从Dodger.events文件中选取对手球队名和是否比赛期间的信息,放置到一个数据集中。具体代码如下:

# 合并两个文件到一个数据集中
feature_set2[3]='NoName' # 对手球队名称暂时用NoName来初始化 
feature_set2[4]=0 # 是否比赛期间暂时用否来代替

def calc_mins(time_str):
    nums=time_str.split(':')
    return 60*int(nums[0])+int(nums[1]) # 将时间转换为分钟数

for row_id,date in enumerate(label_set[0]): # 先取出label中的日期
    temp_df=feature_set2[feature_set2[0]==date]
    if temp_df is None:
        continue
    
    # 只要这一天有比赛,不管是不是正在比赛,都把对手球队名称写入第3列
    rows=temp_df.index.tolist()
    feature_set2.loc[rows,3]=label_set.iloc[row_id,4]
    start_min=calc_mins(label_set.iloc[row_id,1])
    stop_min=calc_mins(label_set.iloc[row_id,2])
    for row in temp_df[2]: # 在逐一判断时间是否位于label中时间之间
        feature_min=calc_mins(row)
        if feature_min>=start_min and feature_min<=stop_min: 
            feature_row=temp_df[temp_df[2]==row].index.tolist()
            feature_set2.loc[feature_row,4]=1 
        
# feature_set2.to_csv('d:/feature_set2_Dodgers.csv') # 保存后打印查看没有问题

打开保存的feature_set2_Dodgers.csv,查看发现有很多NoName的行数,这些行数表示当天没有比赛,故而没有对手名。对于NoName样本的处理方式也有多种多用,根据具体的需求不同而不同,可以把它当做ground truth来对待,也可以直接删除,也可以保留作为一种情况来进行训练。此处我直接将其删除。

1.2.5 规整之五:将日期转换为星期数并保存数据集

这部分主要是将日期转换为星期数,并保存数据集到硬盘,方便下次直接读取文件。代码为:

feature_set3=feature_set2[feature_set2[3]!='NoName'].reset_index(drop=True) # 去掉NoName的样本

# 进一步处理,由于日期在以后的日子里不可重复,作为feature并不合适,而可以用星期数来代替,
feature_set3[5]=feature_set3[0].map(lambda x: x.strftime('%w')) # 将日期转换为星期数
feature_set3=feature_set3.reindex(columns=[0,2,5,3,4,1])
print(feature_set3.tail()) # 查看转换没有问题

feature_set3.to_csv('E:\PyProjects\DataSet\BuildingInOut/Dodgers_Sorted_Set.txt') # 将整理好的数据集保存,下次可以直接读取

-------------------------------------输---------出--------------------------------

0 2 5 3 4 1
22411 2005-09-29 23:35 4 Arizona 0 9
22412 2005-09-29 23:40 4 Arizona 0 13
22413 2005-09-29 23:45 4 Arizona 0 11
22414 2005-09-29 23:50 4 Arizona 0 14
22415 2005-09-29 23:55 4 Arizona 0 17

--------------------------------------------完-------------------------------------

########################小**********结###############################

1. 这个项目的主要难点也在于数据处理方面,其主要的规整方法和上一篇文章类似。

#################################################################


2. 构建SVM回归模型

使用SVM构建回归模型的关键在于导入SVR模块,而不是分类模型中所用的SVC模块,其SVR所用的参数也需要做相应的调整,此处够安静SVM回归模型的代码为:

from sklearn.svm import SVR # 此处不一样,导入的是SVR而不是SVC
regressor = SVR(kernel='rbf',C=10.0,epsilon=0.2) # 这些参数是优化得来
regressor.fit(train_X, train_y)

-------------------------------------输---------出--------------------------------

SVR(C=10.0, cache_size=200, coef0=0.0, degree=3, epsilon=0.2, gamma='auto',
kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)

--------------------------------------------完-------------------------------------

在对模型进行定义和训练之后,就需要使用测试集对模型进行测试,如下是测试代码和输出结果:

y_predict_test=regressor.predict(test_X)
# 使用评价指标来评估模型的好坏
import sklearn.metrics as metrics
print('平均绝对误差:{}'.format(
    round(metrics.mean_absolute_error(y_predict_test,test_y),2)))
print('均方误差MSE:{}'.format(
    round(metrics.mean_squared_error(y_predict_test,test_y),2)))
print('中位数绝对误差:{}'.format(
    round(metrics.median_absolute_error(y_predict_test,test_y),2)))
print('解释方差分:{}'.format(
    round(metrics.explained_variance_score(y_predict_test,test_y),2)))
print('R方得分:{}'.format(
    round(metrics.r2_score(y_predict_test,test_y),2)))

-------------------------------------输---------出--------------------------------

平均绝对误差:5.16
均方误差MSE:50.45
中位数绝对误差:3.75
解释方差分:0.63
R方得分:0.62

--------------------------------------------完-------------------------------------

貌似结果不太好,可能SVR中的参数还需要进一步优化.

很多朋友给我留言,问我训练好的SVM模型如何保存和重新调用,这部分内容去我在前面的文章中已经介绍过了,具体请看:【火炉炼AI】机器学习003-简单线性回归器的创建,测试,模型保存和加载


注:本部分代码已经全部上传到(我的github)上,欢迎下载。

参考资料:

1, Python机器学习经典实例,Prateek Joshi著,陶俊杰,陈小莉译

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容