Kaggle旧金山犯罪分类预测----非数值型特征问题

来源:互联网 发布:电路热仿真软件 编辑:程序博客网 时间:2024/05/22 06:13

Kaggle是一个数据分析建模的应用竞赛平台,有点类似KDD-CUP(国际知识发现和数据挖掘竞赛),企业或者研究者可以将问题背景、数据、期望指标等发布到Kaggle上,以竞赛的形式向广大的数据科学家征集解决方案。而热爱数据挖掘的小伙伴们可以下载/分析数据,使用统计/机器学习/数据挖掘等知识,建立算法模型,得出结果并提交,排名top的可能会有奖金.
应用机器学习,千万不要一上来就试图做到完美,先撸一个baseline的model出来,再进行后续的分析步骤,一步步提高,所谓后续步骤可能包括『分析model现在的状态(欠/过拟合),分析我们使用的feature的作用大小,进行feature selection,以及我们模型下的bad case和产生的原因』等等。
1. 要对数据有自己的认识
2. 对数据中的特殊点/离群点进行分析和处理
3. 特征工程(feature engineering)很重要了!
4. 尝试模型融合(model ensemble)

  1. 问题介绍

在旧金山这个地方,一度犯罪率还挺高的,很多人都经历过大到暴力案件,小到东西被偷,车被划的事情。当地警方努力地去总结和想办法降低犯罪率,一个挑战是在给出犯罪的地点和时间的之后,要第一时间确定这可能是一个什么样的犯罪类型,以确定警力等等。犯罪报告里面包括日期,描述,星期几,所属警区,处理结果,地址,GPS定位等信息。

2.查看数据
数据可以在Kaggle比赛数据页面下载到.大家也可以在博主提供的百度网盘地址中下载到。
我们依旧用pandas载入数据,先看看数据内容。

import pandas as pdimport numpy as np#用pandas载入csv训练数据,并解析第一列为日期格式train=pd.read_csv('/Users/Hanxiaoyang/sf_crime_data/train.csv', parse_dates = ['Dates'])test=pd.read_csv('/Users/Hanxiaoyang/sf_crime_data/test.csv', parse_dates = ['Dates'])train

可以用train.info()和train.describe()获取行列信息

我们依次解释一下每一列的含义:
Date: 日期
Category: 犯罪类型,比如 Larceny/盗窃罪 等.
Descript: 对于犯罪更详细的描述
DayOfWeek: 星期几
PdDistrict: 所属警区
Resolution: 处理结果,比如说『逮捕』『逃了』
Address: 发生街区位置
X and Y: GPS坐标
train.csv中的数据时间跨度为12年,包含了90w+的记录。另外,这部分数据,大家从上图上也可以看出来,大部分都是『类别』型,比如犯罪类型,比如星期几。

  1. 特征预处理
    数据中类别和文本型非常多,我们要进行特征预处理,对于类别特征,我们用最常见的因子化操作将其转成数值型,比如我们把犯罪类型用因子化进行encode,也就是说生成如下的向量:
    星期一/Monday = 1,0,0,0,…
    星期二/Tuesday = 0,1,0,0,…
    星期三/Wednesday = 0,0,1,0,…

    用pandas的get_dummies()可以直接拿到这样的一个二值化的01向量。Pandas里面还有一个很有用的方法LabelEncoder可以用于对类别编号。对于已有的数据特征,我们打算做下面的粗略变换:
    1.LabelEncoder**对犯罪类型做编号**
    2.处理时间,在我看来,也许犯罪发生的时间点(小时)是非常重要的,因此我们会用Pandas把这部分数据抽出来;
    3.对街区,星期几,时间点用get_dummies()因子化;
    4.做一些组合特征,比如把上述三个feature拼在一起,再因子化一下;
    具体的数据和特征处理如下:
import pandas as pdimport numpy as npfrom sklearn.cross_validation import train_test_splitfrom sklearn import preprocessing#用LabelEncoder对不同的犯罪类型编号leCrime = preprocessing.LabelEncoder()crime = leCrime.fit_transform(train.Category)#因子化星期几,街区,小时等特征days = pd.get_dummies(train.DayOfWeek)district = pd.get_dummies(train.PdDistrict)hour = train.Dates.dt.hourhour = pd.get_dummies(hour) #组合特征trainData = pd.concat([hour, days, district], axis=1)trainData['crime']=crime#对于测试数据做同样的处理days = pd.get_dummies(test.DayOfWeek)district = pd.get_dummies(test.PdDistrict)hour = test.Dates.dt.hourhour = pd.get_dummies(hour) testData = pd.concat([hour, days, district], axis=1)trainData

4.进行建模
这个多分类问题中,Kaggle的评定标准是multi-class log_loss,这个值越小,表示最后的效果越好。
-log P(yt|yp) = -(yt log(yp) + (1 - yt) log(1 - yp))

我们可以快速地筛出一部分重要的特征,搭建一个baseline系统,再考虑步步优化。比如我们这里简单一点,取小时时间点,星期几和街区作为分类器输入特征,我们用scikit-learn中的train_test_split函数拿到训练集和交叉验证集。代码如下:

import pandas as pdimport numpy as npfrom sklearn.cross_validation import train_test_splitfrom sklearn import preprocessingfrom sklearn.metrics import log_lossfrom sklearn.naive_bayes import BernoulliNBimport time#用pandas载入csv训练数据,并解析第一列为日期格式train=pd.read_csv(r'C:\Users\lujinyu\Desktop\atae-lstm\atae-lstm\data\train.csv', parse_dates = ['Dates'])test=pd.read_csv(r'C:\Users\lujinyu\Desktop\atae-lstm\atae-lstm\data\test.csv', parse_dates = ['Dates'])#print(train.info(),train.describe())#用LabelEncoder对不同的犯罪类型编号leCrime = preprocessing.LabelEncoder()crime = leCrime.fit_transform(train.Category)#因子化星期几,街区,小时等特征days = pd.get_dummies(train.DayOfWeek)district = pd.get_dummies(train.PdDistrict)hour = train.Dates.dt.hourhour = pd.get_dummies(hour)#组合特征trainData = pd.concat([hour, days, district], axis=1)trainData['crime']=crime#对于测试数据做同样的处理days = pd.get_dummies(test.DayOfWeek)district = pd.get_dummies(test.PdDistrict)hour = test.Dates.dt.hourhour = pd.get_dummies(hour)testData = pd.concat([hour, days, district], axis=1)features = ['Friday', 'Monday', 'Saturday', 'Sunday', 'Thursday', 'Tuesday','Wednesday', 'BAYVIEW', 'CENTRAL', 'INGLESIDE', 'MISSION','NORTHERN', 'PARK', 'RICHMOND', 'SOUTHERN', 'TARAVAL', 'TENDERLOIN']hourFea = [x for x in range(0,24)]features = features + hourFea# 分割训练集(3/5)和测试集(2/5)training, validation = train_test_split(trainData, test_size=0.6)'''X_train,X_test, y_train, y_test =cross_validation.train_test_split(train_data,train_target,test_size=0.4, random_state=0)train_data:所要划分的样本特征集train_target:所要划分的样本结果test_size:样本占比,如果是整数的话就是样本的数量random_state:是随机数的种子。随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:种子不同,产生不同的随机数;种子相同,即使实例不同也产生相同的随机数。'''# 朴素贝叶斯建模,计算log_lossmodel = BernoulliNB()'''ernoulliNB假设特征的先验概率为二元伯努利分布,即如下式:P(Xj=xjl|Y=Ck)=P(j|Y=Ck)xjl+(1−P(j|Y=Ck)(1−xjl)此时l只有两种取值。xjl只能取值0或者1。BernoulliNB一共有4个参数,其中3个参数的名字和意义和MultinomialNB完全相同。唯一增加的一个参数是binarize。这个参数主要是用来帮BernoulliNB处理二项分布的,可以是数值或者不输入。如果不输入,则BernoulliNB认为每个数据特征都已经是二元的。否则的话,小于binarize的会归为一类,大于binarize的会归为另外一类。在使用BernoulliNB的fit或者partial_fit方法拟合数据后,我们可以进行预测。此时预测有三种方法,包括predict,predict_log_proba和predict_proba。 predict方法就是我们最常用的预测方法,直接给出测试集的预测类别输出。predict_proba则不同,它会给出测试集样本在各个类别上预测的概率。容易理解,predict_proba预测出的各个类别概率里的最大值对应的类别,也就是predict方法得到类别。predict_log_proba和predict_proba类似,它会给出测试集样本在各个类别上预测的概率的一个对数转化。转化后predict_log_proba预测出的各个类别对数概率里的最大值对应的类别,也就是predict方法得到类别。。'''nbStart = time.time()model.fit(training[features], training['crime'])'''partial_fit说明:增量的训练一批样本 这种方法被称为连续几次在不同的数据集,从而实现核心和在线学习,这是特别有用的,当数据集很大的时候,不适合在内存中运算 该方法具有一定的性能和数值稳定性的开销,因此最好是作用在尽可能大的数据块(只要符合内存的预算开销) '''nbCostTime = time.time() - nbStart#消耗的时间predicted = np.array(model.predict_proba(validation[features]))print("朴素贝叶斯建模耗时 %f 秒" %(nbCostTime))print("朴素贝叶斯log损失为 %f" %(log_loss(validation['crime'], predicted)))

结果如下:

D:\Anaconda3\python.exe C:/Users/lujinyu/Desktop/atae-lstm/atae-lstm/TEST.py朴素贝叶斯建模耗时 11.314548 秒朴素贝叶斯log损失为 2.584893Process finished with exit code 0
原创粉丝点击