需求介绍
美团有自己的城市等级,外卖依据其业务体量,重新划分了外卖的城市等级。这个城市根据其业务情况来划分的,比较详细。
现在有以下样本数据。
city_name | city_level | pnum | ddl |
临汾 | D2 | ** | ** |
南京 | A | ** | ** |
洛阳 | C1 | ** | ** |
无锡 | B1 | ** | ** |
其中分别是城市名,城市等级(D2,A,C1,B1,C2,D3,B2,S,D1),动销门店量,月订单量。现在需要fit一个模型,要求再增加新的城市可以给分出一个合适的城市等级。
数据探查
首先在空间描述点的聚集离散程度。
import plotly.plotly as py
import pandas as pd
import plotly
plotly.tools.set_credentials_file(username='your name', api_key='KCwJWZXjfSJ65bhCvc')
df = pd.read_csv('d:/src/waimaiknn.csv')
print(df.head())
print(df['pnum'])
scatter = dict(
mode = "markers",
name = "y",
type = "scatter3d",
x = df['city_level'], y = df['pnum'], z = df['ddl'],
marker = dict( size=2, color="rgb(23, 190, 207)" )
)
clusters = dict(
alphahull = 7,
name = "y",
opacity = 0.1,
type = "mesh3d",
x=df['city_level'], y=df['pnum'], z=df['ddl']
)
layout = dict(
title = '3d point clustering',
scene = dict(
xaxis = dict( zeroline=False ),
yaxis = dict( zeroline=False ),
zaxis = dict( zeroline=False ),
)
)
fig = dict( data=[scatter, clusters], layout=layout )
# Use py.iplot() for IPython notebook
py.plot(fig, filename='3d point clustering')
输出见: https://plot.ly/~junshan2009/16/_3d-point-clustering/#/
看到x坐标轴上的各个点聚集程度较好。
要求把数据划分为训练集和测试集,训练出模型后,用测试集测试训练效果。
数据准备
from sklearn.preprocessing import LabelBinarizer
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
import pandas as pd
import numpy as np
df = pd.read_table("d:/src/waimaiknn.txt")
pnum = np.array(df['pnum'][:-10])
ddl = np.array(df['ddl'][:-10])
x_train = np.column_stack((pnum, ddl))
print(x_train)
y_train = np.array(df['city_level'][:-10])
print(y_train)
x_test = np.column_stack((np.array(df['pnum'][-10:]), np.array(df['ddl'][-10:])))
y_test = np.array(df['city_level'][-10:])
数据准备好后开始训练模型,并且选一个单例看看测试的效果
k = 3
clf = KNeighborsClassifier(n_neighbors=k)
clf.fit(x_train, y_train.reshape(-1))
dem1 = clf.predict(np.array([4576, 1611779]).reshape(1, -1))[0]
print('预测出的城市是', dem1, '级别')
单例出的结果正确,接下来我们评估模型的效果,分为准确度,精准度,召回率三个方面。
准确率,就是这个分类器预测准确的百分率
精准率一般存在于二元分类,比如预测是否得癌症,结果只有:癌症,没癌症。我们宁愿没癌症预测成了癌症,也不愿有癌症的给预测了没癌症。其中这个有癌症的被预测出来,而没有预测为没癌症就是精准率。
因为这个不是二元分类,所以本次不做精准率评估。
召回率,真正正向类被预测为正向类的比率。
y_pred = clf.predict(x_test)
print(x_test)
print(y_test)
print(y_pred)
print('这次预测的准确率是', metrics.accuracy_score(y_test, y_pred))
# print('这次预测的精准率', metrics.precision_score(y_test,y_pred,average=None))
# print('召回率',metrics.recall_score(y_test,y_pred))
可以看到,预测的还是比较准的,准确度60%,错误的情况是
D1-D2
D3-C2
C1-C2
D1-D2
其中D3-C2是比较严重的错误,其他属于接近的错误。
可能是这个城市当月业绩有突然上升,导致了其位置的提高。因为外卖城市分级是静态的,销售数据每个月不一样。
预测出这种结果,从业务的角度来说,已经比较准确了。
通过上面的点图我们发现,D1,D2的y,z周聚集位置较为接近,这也是为什么D1,D2容易误判的原因吧。理想的情况是,X轴上面的,y,z轴点的聚集没有交叉。
探索
k=3是否合理,实际上邻近算法的k值需要设置成奇数防止平局的现象。
设置K=5的时候结果是一样的,但是设置成1结果会大打折扣
所以合理设置k值可以自己探索一下。