零基础入门机器学习 Kaggle_Crime_Prediction
注:本文写自2019.10,是博主接触的第一个机器学习项目。很多地方考虑不够周全,文章中解释不到位之处多多担待。
题目回顾
题目名称:犯罪预测
题目简介:你需要根据相关数据来预测可能发生的犯罪类型。 训练数据位于train.csv,测试数据位于test.csv,最终你需要提交你对测试集的预测结果。
数据介绍:此数据集包含来⾃犯罪事件报告系统事件。 数据范围为1/1/2003⾄2015年5⽉13⽇。每条数据仅包含 ⼀种犯罪。
数据字段:Dates – 犯罪事件的时间戳 Category – 犯罪事件的类别 (仅在train.csv出现), 这是需要预测的⽬标变 量。 Descript – 犯罪事件的详细描述 (仅在train.csv出现) DayOfWeek – 星期⼏ PdDistrict – 警察局区的名称 Resolution – 如何解决犯罪事件 (仅在train.csv出现) Address – 犯罪事件的⼤致街道地址 X – 经度 Y – 纬度
TIPS
相关python包推荐:scikit-learn, numpy, csv
相关经验的话我⽐较懒,可以搜索以下内容获取更多信息。
google: “python 预测分类问题”
google: “kaggle 泰坦尼克号实战”
前言
准备工作:换镜像源并用cmd命令行安装需要的库和包(萌新费力的步骤)
0.1 在开始处调用库(首先针对绘图)
在使用python库之前必须引入python库 使用import代码
import numpy as np # 科学计算
import matplotlib.pyplot as plt # python绘图库
import pandas as pd # 数据分析
import seaborn as sns # 作图
import string
import matplotlib.colors as colors # 添加颜色
复制代码
0.2 用pandas载入csv训练和测试数据,进而可以进行数据的分析
train = pd.read_csv("D:\Computer\kaggle machine learning/task/train.csv")
test = pd.read_csv("D:\Computer\kaggle machine learning/task/test.csv")
train.info()
test.info() #获取文件中的数据类型及数目
复制代码
输出结果如下:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 600000 entries, 0 to 599999
Data columns (total 9 columns):
Dates 600000 non-null object
Category 600000 non-null object
Descript 600000 non-null object
DayOfWeek 600000 non-null object
PdDistrict 600000 non-null object
Resolution 600000 non-null object
Address 600000 non-null object
X 600000 non-null float64
Y 600000 non-null float64
dtypes: float64(2), object(7)
memory usage: 41.2+ MB
复制代码
Data columns (total 6 columns):
Dates 250000 non-null object
DayOfWeek 250000 non-null object
PdDistrict 250000 non-null object
Address 250000 non-null object
X 250000 non-null float64
Y 250000 non-null float64
dtypes: float64(2), object(4)
memory usage: 11.4+ MB
复制代码
print(train.isnull().sum()) # 查看数据中有没有缺失项
复制代码
Dates 0
Category 0
Descript 0
DayOfWeek 0
PdDistrict 0
Resolution 0
Address 0
X 0
Y 0
dtype: int64
复制代码
print(test.isnull().sum())
复制代码
Dates 0
DayOfWeek 0
PdDistrict 0
Address 0
X 0
Y 0
dtype: int64
复制代码
发现train训练集数据60w条,test测试集数据25w条,数据没有缺失的数据。
一、 进行数据的初步分析及特征分析
1.1 Category(要预测的目标变量)
print(train['Category'].describe())
复制代码
count 600000
unique 39
top LARCENY/THEFT
freq 119238
Name: Category, dtype: object
复制代码
cate_group = train.groupby(by='Category').size()
cate_group
cate_num = len(cate_group.index)
cate_num
cate_group.index = cate_group.index.map(string.capwords)
cate_group.sort_values(ascending=False,inplace=True)
# ascending=False按降序排序,指定inplace=True,将同时修改原数据
cate_group.plot(kind='bar',color=sns.color_palette('coolwarm',cate_num))
# 补充logy=True 绘制y轴的对数图形(把图形放大,看得更细腻,大佬操作)
plt.title('Number of Crime types')
plt.show()
复制代码
如果我们使用的是指数形式呢(使用logy=True启用对数)
我们通过观察易得6种数量最多的犯罪类型如下:
Category
ASSAULT
DRUG/NARCOTIC
LARCENY/THEFT
NON-CRIMINAL
OTHER OFFENSES
VEHICLE THEFT
复制代码
1.2 DayOfWeek
print(train['DayOfWeek'].describe())
复制代码
count 600000
unique 7
top Friday
freq 91634
Name: DayOfWeek, dtype: object
复制代码
Day_group = train.groupby(by='DayOfWeek').size()
Day_group
Day_num = len(Day_group.index)
Day_num
Day_group.index = Day_group.index.map(string.capwords)
Day_group.sort_values(ascending=False,inplace=True)
Day_group.plot(kind='bar',color=sns.color_palette('coolwarm',Day_num))
plt.title('The Number of Crime types')
plt.show()
复制代码
分析:在一周内,星期五犯罪数量最多,星期天犯罪数量最少,总的来说一周中五天的犯罪数目差距 不是很大,基本在80000+
1.3 PdDistrict
print(train['PdDistrict'].describe())
复制代码
count 600000
unique 10
top SOUTHERN
freq 107457
Name: PdDistrict, dtype: object
复制代码
dis_group = train.groupby(by='PdDistrict').size()
dis_group
dis_group = dis_group/sum(dis_group)
dis_group.index = dis_group.index.map(string.capwords)
dis_group.sort_values(ascending=True,inplace=True)
dis_group.plot(kind='barh',figsize=(15,10),fontsize=10,color=sns.color_palette('coolwarm',10))
plt.title('The Frequncy of crimes by district',fontsize=15)
plt.show()
复制代码
分析:犯罪的高频发生区域在Southern,其次是Mission Northern,Richmond是治安最好,犯罪情况与 PdDistrict有关联
1.4 year/month/day
由于我们需要对年月日分开分析,所以我们需要将year/month/day这样形式的字符分开
所以需要以下代码进行分析
fig=plt.figure()
fig.set(alpha=0.2)
#转化dates数据字段字符串类型为date数据类型 把date的三个量分离开
train['Dates']=pd.to_datetime(train['Dates'])
train['year'] = train.Dates.dt.year
train['month'] = train.Dates.dt.month
train['day'] = train.Dates.dt.day
train['hour'] = train.Dates.dt.hour
plt.subplot2grid((3,1),(0,0))
year_group = data_train.groupby(by='year').size()
plt.plot(year_group.index[:-1],year_group[:-1],'ks-')
plt.title('statistics of criminal cases measured by year')
plt.xlabel('year')
plt.ylabel('number of people')
plt.subplot2grid((3,1),(1,0))
month_group = data_train.groupby(by='month').size()
plt.plot(month_group,'ks-')
plt.title('statistics of criminal cases measured by month')
plt.xlabel('month')
plt.ylabel('number of people')
plt.subplot2grid((3,1),(2,0))
day_group = data_train.groupby(by='day').size()
plt.plot(day_group,'ks-')
plt.title('statistics of criminal cases measured by day')
plt.xlabel('day')
plt.ylabel('number of people')
复制代码
输出将时间字段字符串分离后的部分数据情况 如下(数据说明已经成功分解)
year 600000 non-null int64
month 600000 non-null int64
day 600000 non-null int64
hour 600000 non-null int64
dtypes: datetime64[ns](1), float64(2), int64(5), object(4)
复制代码
分析:2011年犯罪数量最少,2011年之后的数量激增,到2013年犯罪数量最多;8月份犯罪数量最少,犯罪数量最多的月份为10月份 5月份;除了月初和月末又明显的波动外,一个月内犯罪数目并没有显著的变化,基本稳定在171500-20000人。对于day的数据,更趋近于线性关系。
1.5 在星期几的某一个时刻的犯罪数量
week_group = train.groupby(['DayOfWeek','hour']).size() #多重分组
week_group = week_group.unstack() #对分组后的多重索引转为xy索引
week_group.T.plot(figsize=(12,8)) #行列互换后画图
plt.xlabel('hour of day',size=15)
plt.ylabel('Number of crimes',size=15)
plt.show()
复制代码
数据分析:12点和18点的犯罪数量最多,在凌晨数量开始显著下降,不同的时段犯罪数差别很大
PS.一定需要小心一点,groupby([‘DayOfWeek’,’hour’])中的hour是没有定义的,所以我必须出现前面的一行 代 码(将年月日中的三个参数分离开)如下:
train['hour'] = train.Dates.dt.hour
复制代码
1.6 Address
print(train['Address'].describe())
复制代码
count 600000
unique 22262
top 800 Block of BRYANT ST
freq 18064
Name: Address, dtype: object
复制代码
由上表可知:Address的数据种类很多,分布很零散,维度很大,选取特征困难
1.7 Resolution
(数据只在训练集上)
print(train['Resolution'].describe())
复制代码
count 600000
unique 17
top NONE
freq 359779
Name: Resolution, dtype: object
复制代码
分析:发现仅仅只有三种Resolution的数据比较多,其他的数据相对很少
1.8 Descript
(数据只在训练集上)
print(train['Descript'].describe())
复制代码
count 600000
unique 862
top GRAND THEFT FROM LOCKED AUTO
freq 41046
复制代码
分析:发现Descript的数据有862种,分布散乱,情况仅次于Address
1.9 位置坐标 X Y
print(train['X'].describe())
print(train['Y'].describe())
复制代码
count 600000.000000
mean -122.422635
std 0.030175
min -122.513642
25% -122.432956
50% -122.416442
75% -122.406959
max -120.500000
Name: X, dtype: float64
count 600000.000000
mean 37.770856
std 0.447932
min 37.707920
25% 37.752441
50% 37.775421
75% 37.784353
max 90.000000
Name: Y, dtype: float64
复制代码
分析:没有画出坐标图像,但是X和Y的坐标的std(标准差)分别为0.030175、0.447932,显然都非常小,所以说明地理位置坐标的变化幅度并不大,该参数并不会对结果产生太明显的影响。
1.10 数量前6的犯罪类别与hour的关系
top6 = list(cate_group.index[:6])
tmp = train[train['Category'].map(string.capwords).isin(top6)]
tmp_group = tmp.groupby(['Category','hour']).size()
tmp_group = tmp_group.unstack()
tmp_group.T.plot(figsize=(12,6),style='o-')
plt.show()
复制代码
分析:5点以后数量开始上升,12和18时出现数量峰值,不同的时段对于不同的犯罪情况均有影响。
1.11 数量前6的犯罪类别与month的关系
mon_g = tmp.groupby(['Category','month']).size()
mon_g = mon_g.unstack()
for i in range(6):
mon_g.iloc[i] = mon_g.iloc[i]/mon_g.sum(axis=1)[i]
mon_g.T.plot(figsize=(12,6),style='o-')
plt.show()
复制代码
分析:不同的月份对犯罪有很大的影响,5和10月是犯罪的峰值,ASSAULT对峰值做出贡献
1.12 数量前6的犯罪类别与year的关系
mon_g = tmp.groupby(['Category','year']).size()
mon_g = mon_g.unstack()
for i in range(6):
mon_g.iloc[i] = mon_g.iloc[i]/mon_g.sum(axis=1)[i]
mon_g.T.plot(figsize=(12,6),style='o-')
plt.show()
复制代码
分析:非常明显,2003~2006年VEHICLE THEFT的犯罪率极高,而后来偏低,各种犯罪类型频率在2014年(可能是治安变好了)开始显著下降
二、进行数据处理
#引入python中的sklearn库
from sklearn import preprocessing
#from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
#from sklearn.feature_selection import SelectKBest
#from sklearn.feature_selection import chi2
复制代码
2.1 对分类目标做标签化处理
#对分类目标做标签化处理
from sklearn.preprocessing import LabelEncoder #用于Label编码
from sklearn.preprocessing import OneHotEncoder #用于one-hot编码
label = preprocessing.LabelEncoder()
target = label.fit_transform(train.Category)
target
crime = label.fit_transform(train.Category)
复制代码
#对test数据中的Dates进行同样的分离处理
test['date'] = pd.to_datetime(test['Dates'])
test['year'] = test.date.dt.year
test['month'] = test.date.dt.month
test['day'] = test.date.dt.day
test['hour'] = test.date.dt.hour
test.info()
复制代码
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 250000 entries, 0 to 249999
Data columns (total 10 columns):
Dates 250000 non-null datetime64[ns]
DayOfWeek 250000 non-null object
PdDistrict 250000 non-null object
Address 250000 non-null object
X 250000 non-null float64
Y 250000 non-null float64
year 250000 non-null int64
month 250000 non-null int64
day 250000 non-null int64
hour 250000 non-null int64
dtypes: datetime64[ns](1), float64(2), int64(4), object(3)
memory usage: 19.1+ MB
复制代码
2.2 对train数据进行二值化处理并组合特征
#将train数据因子化
days = pd.get_dummies(train.DayOfWeek)
district = pd.get_dummies(train.PdDistrict)
hour = pd.get_dummies(train.Dates.dt.hour)
month = pd.get_dummies(train.Dates.dt.month)
year = pd.get_dummies(train.Dates.dt.year)
#组合train特征
train= pd.concat([days,district,hour,month,year], axis=1)
train['crime'] = crime
复制代码
2.3 对test数据进行同样二值化处理并组合特征
#将test数据因子化
days = pd.get_dummies(test.DayOfWeek)
district = pd.get_dummies(test.PdDistrict)
hour = pd.get_dummies(test.Dates.dt.hour)
test= pd.concat([days, district, hour], axis=1)
month = pd.get_dummies(test.Dates.dt.month)
year = pd.get_dummies(test.Dates.dt.year)
#组合test特征
test = pd.concat([days, district, hour,month,year],axis=1)
复制代码
上述二值化处理过程是因为我们需要将数据放进0-1的范围内进行处理
需要构造并运用的如图所示:
输出处理后的数据情况如下:
print(train.head(10))
print(test.head(10))
复制代码
Friday Monday Saturday Sunday Thursday ... 2012 2013 2014 2015 crime
0 0 1 0 0 0 ... 0 0 0 0 16
1 0 1 0 0 0 ... 0 0 0 0 25
2 0 1 0 0 0 ... 0 0 0 0 21
3 0 1 0 0 0 ... 0 0 0 0 21
4 0 1 0 0 0 ... 0 0 0 0 16
5 0 1 0 0 0 ... 0 0 0 0 35
6 0 1 0 0 0 ... 0 0 0 0 34
7 0 1 0 0 0 ... 0 0 0 0 21
8 0 1 0 0 0 ... 0 0 0 0 1
9 0 1 0 0 0 ... 0 0 0 0 21
[10 rows x 67 columns]
Friday Monday Saturday Sunday Thursday ... 2011 2012 2013 2014 2015
0 0 1 0 0 0 ... 0 0 0 0 0
1 0 1 0 0 0 ... 0 0 0 0 0
2 0 1 0 0 0 ... 0 0 0 0 0
3 0 1 0 0 0 ... 0 0 0 0 0
4 0 1 0 0 0 ... 0 0 0 0 0
5 0 1 0 0 0 ... 0 0 0 0 0
6 0 1 0 0 0 ... 0 0 0 0 0
7 0 1 0 0 0 ... 0 0 0 0 0
8 0 1 0 0 0 ... 0 0 0 0 0
9 0 1 0 0 0 ... 0 0 0 0 0
[10 rows x 66 columns]
复制代码
三、建立模型并验证评估模型效果
3.1 引入sklearn中的log_loss
from sklearn.metrics import log_loss
import time
复制代码
3.2 选取特征
然后既然是建模,我们就需要选取特征进行模型拟合,这里首先选取days和PdDistrict,代码如下:
features = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', 'BAYVIEW', 'CENTRAL', 'INGLESIDE', 'MISSION',
'NORTHERN', 'PARK', 'RICHMOND', 'SOUTHERN', 'TARAVAL', 'TENDERLOIN']
#然后添加三种时间数据参数到特征中
hourFea = [x for x in range(0,24)]
monFea = [x for x in range(1,12)]
yearFea = [x for x in range(2003,2015)]
features = features + hourFea + monFea + yearFea
复制代码
3.3 交叉验证的方法
交叉验证的基本思想是把在某种意义下将原始数据(dataset)进行分组,一部分做为训练集(train set),另一部分做为验证集(validation set or test set),首先用训练集对分类器进行训练,再利用验证集来测试训练得到的模型(model),以此来做为评价分类器的性能指标。于是我们在3.4步骤中划分该数据集。
3.4 划分数据集
#我们按照训练集6/10 测试集4/10 来划分数据集
X_train,X_test,y_train,y_test = train_test_split(train[features], train['crime'] , train_size = 0.6)
#代码解释
#X_是划分的数据集即train[features]选取特征的训练集划分为X_train,X_test两个部分,比例为3:2
#y_是划分的标签集即train['crime']打上的标签集划分为y_train,y_test两个部分
#然后让我们看看划分的数据情况吧
print("The length of original data is:", train[features].shape[0])
print("The length of train Data is:", X_train.shape[0])
print("The length of test Data is:", X_test.shape[0])
复制代码
The length of original data X is: 600000
The length of train Data is: 360000
The length of test Data is: 240000
复制代码
3.5 从sklearn库中 导入模型进行训练
(1)朴素贝叶斯
模型公式:
- 公式的右边是总结历史
- 公式的左边是预知未来
- 如果把Y看成类别,看成特征,就是在已知特征的情况下求类别的概率,而对的计算又全部转化到类别的特征分布上来。
- 朴素贝叶斯的概念:独立性假设,假设各个特征之间是独立不相关的。
© 版权声明文章版权归作者所有,未经允许请勿转载。THE END