一、背景介绍
1.1 小米扫地机器人智能导航系统
2020年全球服务型机器人销售额为94.6亿美元,同比增涨22.54%;预计到2023年,全球服务机器人市场有望突破201亿美元。人工智能技术是服务机器人获得实质性发展的重要引擎,目前正在从感知智能向认知智能加速迈进。如何使用人工智能技术为机器人提供更为智能化的思维是目前的重中之重,解决这个难题可以极大极高自身产品的竞争力。
本次项目将对小米扫地机器人在移动清扫过程中的机器人的运动轨迹数据进来机器学习模型的搭建,该模型可以通过机器人传感器自身搜集到的数据来智能判断移动方向来达到智能导航的目的。
1.2 数据集介绍
该数据集中X0~X23和front,left,right,back 均是传感器的参数,label则是最终选择的移动方向。共有4865行数据。本篇文章使用python代码。
二、导包与加载数据集
2.1 导入依赖库
from matplotlib import pyplot as plt
%matplotlib inline
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings("ignore")
2.2 加载数据
data = pd.read_csv('xiaomidata.csv')
三、数据探索
3.1 打印数据集的前5行数据
data.head(5)
3.2 统计数据中的缺失值数量
- 统计数据集有多少行有缺失
- 统计数据集有多少列有缺失
print(((data.isnull()).sum(axis=1)>0).sum())
print(((data.isnull()).sum(axis=0)>0).sum())
3.3 统计数据中的重复样本的数量
- 统计数据集有多少行重复
data.duplicated().sum()
四、数据清洗
查看data数据集中标签('Class')的分布
data['label'].value_counts()
使用describe函数查看data数据集中各列特征的分布
对结果使用转置可一次性展示 (仅展示部分)
data.drop(['label'],axis=1).describe().T
画出特征分布的直方图 (仅展示部分)
fig = plt.figure(figsize=(15,30))
features = list(data.drop(['label'],axis=1).columns)
for i,col in enumerate(features):
axe = fig.add_subplot(np.ceil(len(features)/4),4,i+1)
axe.hist(data[col],bins=20);
plt.title(col)
五、特征工程
通过观察数据我们发现:
- 数据的量纲差距不大。
- 数据不存在重复和缺失。
- 特征均为连续值。
首先分离特征和标签,并划分训练集和测试集,命名为X_train,X_test,y_train,y_test
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(data.drop(['label'],axis=1),data['label'],test_size = 0.2,random_state=0)
5.1 连续特征离散化
5.1.1 方法一:使用等距离散化的方法,将连续特征按固定间隔分组
函数一是equal_distance_cut,他记录数据集分成几份时的界值,data为数据集,bins为份数
函数二是apply_on_train_and_test,他调用函数一记录训练集中的界值,并施加在训练集和测试集上进行分箱,并返回分箱后的训练集和测试集
# 方法一示例
def equal_distance_cut(data,bins):
Cutpoint = {}
for i in range(len(data.columns)):
cut = (np.max(data.iloc[:,i])-np.min(data.iloc[:,i]))/bins
Cutpointlist = []
for j in range((bins-1)):
cutpoint = np.min(data.iloc[:,i]) + (j+1)*cut
Cutpointlist.append(cutpoint)
Cutpoint[i] = Cutpointlist
return Cutpoint
def apply_on_train_and_test(train, test, bins):
Cutpoint = equal_distance_cut(train,10)
train_set = pd.DataFrame(np.zeros_like(train),columns=train.columns,index=train.index)
test_set = pd.DataFrame(np.zeros_like(test),columns=test.columns,index=test.index)
for i in range(len(train.columns)):
for j in range((bins-1)):
train_set.iloc[:,i][train.iloc[:,i] > Cutpoint[i][j]]=j
for i in range(len(test.columns)):
for j in range((bins-1)):
test_set.iloc[:,i][test.iloc[:,i] > Cutpoint[i][j]]=j
return train_set, test_set
X_train_split_1, X_test_split_1 = apply_on_train_and_test(X_train, X_test, 10)
5.1.2 方法二:使用等频离散化的方法,将连续特征按固定样本数分组
函数equal_frequency_cut将数据排序后分成数份,train和test为数据集,bins为份数,并返回分箱后的训练集和测试集
# 方法二示例
def equal_frequency_cut(train, test, bins):
train_set = train.copy()
test_set = test.copy()
edages = pd.Series([i/bins for i in range(bins)])
for col in train.columns:
train_set[col] = train_set[col].rank(pct=1).astype(float).apply(lambda x: (edages >= x).argmax())
for col in test.columns:
test_set[col] = test_set[col].rank(pct=1).astype(float).apply(lambda x: (edages >= x).argmax())
return train_set, test_set
X_train_split_2, X_test_split_2 = equal_frequency_cut(X_train, X_test, 10)
5.2 特征过滤
5.2.1 思路1:使用PCA进行降维
#对训练集和测试集使用PCA进行降维,注意应自行决定保留特征数目
from sklearn.decomposition import PCA
pca = PCA(25)
X_train_pca = pca.fit_transform(X_train)
X_test_pca = pca.transform(X_test)
5.2.2 思路2.使用随机森林方法进行特征选择
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(max_features=15,max_depth=10,n_estimators=1024,n_jobs=-1,random_state=0)
rf.fit(X_train,y_train)
imp = np.argsort(rf.feature_importances_)[::-1]
imp_slct = imp[:25]
X_train_slct=pd.DataFrame(X_train).iloc[:,imp_slct]
六、选择模型进行交叉验证和网格搜索
- 使用分类模型。
- 注意模型对数据规整的需求。
这里以pca降维后的数据拟合随机森林模型作为演示
# 分类模型
from sklearn.ensemble import RandomForestClassifier
clf_model = RandomForestClassifier(max_features=9,max_depth=16,n_estimators=2048,n_jobs=-1,random_state=0)
clf_model.fit(X_train_pca,y_train)
分类模型测试集上效果:auc和混淆矩阵评估
from sklearn.metrics import roc_auc_score, accuracy_score
print('分类模型:')
y_test_pred_clf = clf_model.predict_proba(X_test_pca)
y_test_pred = clf_model.predict(X_test_pca)
# 对标签one-hot编码后使用宏方法计算auc和acc,你也可以使用微方法
print('ml model auc score {:.6f}'.format(roc_auc_score(pd.get_dummies(y_test),y_test_pred_clf,average='macro')))
print('---------------')
print('ml model accuracy score {:.6f}'.format(accuracy_score(y_test,y_test_pred)))
print('\n随机模型:')
# 随机猜测函数对比
y_test_random_clf = np.random.uniform(low=0.0,high=1.0,size=(len(y_test),4))
y_test_random_pred = np.argmax(y_test_random_clf,axis=1)
print('random model auc score {:.6f}'.format(roc_auc_score(pd.get_dummies(y_test),y_test_random_clf,average='macro')))
print('---------------')
print('ml model accuracy score {:.6f}'.format(accuracy_score(y_test,y_test_random_pred)))
七、模型评价的深入思考
对于多分类模型,我们需要逐类查看预测效果
- 代码将所有类别的ROC曲线分别呈现,也可以修改代码将他们在一张图上呈现,两种方法的代码都会呈现。
7.1 计算各类别fpr和tpr
from sklearn.metrics import roc_curve, auc
fpr = dict()
tpr = dict()
thresholds = dict()
roc_auc = dict()
for i in range(4):
fpr[i], tpr[i], thresholds[i] = roc_curve(pd.get_dummies(y_test).iloc[:, i], y_test_pred_clf[:, i])
roc_auc[i] = auc(fpr[i], tpr[i])
7.2 AUC曲线可视化
7.2.1 4类的ROC曲线在4张子图呈现
from itertools import cycle
# Plot all ROC curves
lw=2
plt.figure()
colors = cycle(['aqua', 'darkorange', 'cornflowerblue','red'])
names = ['Move-Forward','Sharp-Right-Turn','Slight-Right-Turn','Slight-Left-Turn']
fig = plt.figure(figsize=(10,10))
for i, color in zip(range(4), colors):
axe = fig.add_subplot(2,2,i+1)
axe.plot(fpr[i], tpr[i], color=color, lw=lw,
label='ROC curve of class {0} (area = {1:0.2f})'.format(i, roc_auc[i]))
plt.plot([0, 1], [0, 1], 'k--', lw=lw)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC for '+names[i])
plt.legend(loc="lower right")
plt.show()
7.2.2 将所有类别的ROC在一张图呈现
lw=2
plt.figure()
colors = cycle(['aqua', 'darkorange', 'cornflowerblue','red'])
names = ['Move-Forward','Sharp-Right-Turn','Slight-Right-Turn','Slight-Left-Turn']
fig = plt.figure(figsize=(10,10))
for i, color in zip(range(4), colors):
plt.plot(fpr[i], tpr[i], color=color, lw=lw,
label='ROC curve of class {0} (area = {1:0.2f})'.format(i, roc_auc[i]))
plt.plot([0, 1], [0, 1], 'k--', lw=lw)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC for 4 class')
plt.legend(loc="lower right")
plt.show()
八、结论 (对ROC曲线的浅浅解释)
本文主要采用精度(accuracy)以及受试者工作特征曲线下面积(AUC)作为主要的模型评价指标。
精度(accuracy):精度是分类任务中最常用的性能度量,它指的是分类正确的样本数与总样本数的比重。
当正负样本不均衡时,精度并不是--个很好的度量指标。本文已经在数据预处理阶段进行正负样本均衡的处理消除了正负样本不均衡对精度的影响,故本文将采用精度作为模型评价标准之一。
特征曲线下面积(AUC): AUC是另外一个应用广泛的二分类器评价标准。“ 真正例率” 指在全部正样本中,分类无误的正样本所占的比重,“ 假正例率”指在全部负样本中,分类错误的负样本所占的比重。以“真正例率”为竖直方向,“ 假正例率”为水平方向构建坐标系形成的图像为特征曲线(ROC),对ROC曲线求取其线下面积即为AUC。
AUC值大于等于0.5且小于等于l,当AUC为0.5则代表与随机猜想效果相同。因此, AUC值通常应大于0.5。在这种情况下,AUC的值越大,则说明模型效果越好。本文的实验结果很好,各种类的AUC值都接近1,所以模型的性能非常可观。
本文使用随机森林模型,其实还有许多分类模型供大家选择,如:逻辑回归,决策树等等。欢迎大家学习和讨论。稿主是一位在某中外合办大学统计学专业就读的大三本科生~,如有错误的地方请大家指出,谢谢各位观看!