前言
接着前面三篇学习笔记《约会对象魅力程度分类》、《使用sklearn中的KNN算法》和《KNN手写识别系统》,本节记录使用K近邻算法检测异常操作,主要参考《Web安全之机器学习》 。
转载请注明出处:http://blog.youkuaiyun.com/rosetta
使用K近邻算法检测异常操作之一
实验数据及情况
实验数据在Schonlau个人网站中:http://www.schonlau.net/
训练数据包含50个用户的操作日志(网站上对应红框处“Masquerade Data(zip File)”)和一个标签文件label.txt(网站上对应的红框处“WIndows ascii file”)
在本机解压后是这样子的:
实验数据一共收集了50个用户的操作命令(在理解代码时,只先考虑1个用户的即可),每个用户命令为15000条,前5000条是正常数据(这里隐含的一层意思是,我不需要特意指定标签了,你在代码中把我们全设置成0就可以了(本次实验就0表示正常操作;1表示异常操作)),后10000条随机包含了异常操作。
为了方便操作,会把数据集的每100个命令作为一个操作序列,所以15000条数据实际上看作150条,而前50条都是正常的,那么只有后面的100条需要标记,所以lable.txt中只有100条,而不是150条。在代码中使用KNN算法时,会把训练数据的label的前50条自动补上0,后100条从lable.txt中读取,这样就组合出了代码中实际的lable是150条的,和数据的条目能对应上了。
注意下本次实验样本数据的标签放在label.txt中,要以列方向去看,比如User1样本的标签对应第0列(因为加载到python list中是以0开始算的),User3就是第2列了。
另外在训练数据的时候,怎么把每组的100条数据清洗成易理解的数据?本实验是这么做的(针对1个用户来说):先统计15000条数据中最频繁使用的50个命令(后续称全局TOP50)和最不频繁使用的50个命令(后续称LOW50),然后统计每个100条数据中不重复命令的个数,及最频繁使用的前10个命令和是不频繁使用的10个命令,拿前10和后10分别和TOP50 LOW50取交集,生成一条数据的特征list:[无重复命令个数,和TOP50交集个数,和LOW50交集个数],生成这样的特征一共150条。
代码中的特征变量由user_cmd_feature list表示。
并生成150条对应的lables,从下图代码可知,前50条因为都是正常数据,所以赋值为0,后100条从lable.txt中读取
代码中的标签用y表示。
这些数据出来以后就好办了,取150条数据的前N条数据用来做训练数据,后150-N条数据做测试数据,然后和之前的学习内容都是类似的了。本实例的KNN核心代码就是如下4句。
代码中的训练数据用:x_train和y_train表示,一个是特征,另一个是特征对应的标签
测试数据用x_test和y_test表示,算法预测的结果用y_predict表示。
注意
这个实验的结果是很坑爹的,因为通过预测的结果都是0,而用于测试的数据其标签0多,1少,所以导致后续的结果看起来正确率很高。我试了其它的几个User样本,也是类似的,没见过预测的结果中有1的情况。
即使如此,从本实验中还是学到了很多东西,比如如何从原始数据转换成KNN能理解的标量数据等。
实验代码
本代码原始文件是《Web安全之机器学习》书中的,本人加了些注释而已。
# -*- coding:utf-8 -*-
import numpy as np
from nltk.probability import FreqDist
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report
from sklearn import metrics
#N姑且叫做训练数据,实际上就是已知的带标签的数据条目数。
N=100
def load_user_cmd(filename):
cmd_list=[]
dist_max=[]
dist_min=[]
dist=[]
with open(filename) as f:
i=0
x=[]
for line in f:
line=line.strip('\n')
x.append(line)
dist.append(line)
i+=1
if i == 100:
cmd_list.append(x)
x=[]
i=0
fdist = list(FreqDist(dist).keys())
dist_max=set(fdist[0:50])
dist_min = set(fdist[-50:])
return cmd_list,dist_max,dist_min
#cmd_list包含150组数据,每组100个命令,所以一共是15000个命令。
#dist_max 最常用的50个命令
#dist_min 最不常用的50个命令
def get_user_cmd_feature(user_cmd_list,dist_max,dist_min):
user_cmd_feature=[]
for cmd_block in user_cmd_list:
f1=len(set(cmd_block))#当前分块(100个数据中),不重要的数据个数
fdist = list(FreqDist(cmd_block).keys())#这100个数据中频繁程度排序。FreqDist为nltk中的库,nltk是NLP(自然语言处理)工具包。
f2=fdist[0:10]#最频繁的10个命令
f3=fdist[-10:]#最不频繁的10个命令
f2 = len(set(f2) & set(dist_max))#这100个命令中最频繁的10个命令和15000个命令中最频繁的前50个的交集的长。。
f3=len(set(f3)&set(dist_min)) #这100个命令中最不频繁的10个命令和15000个命令中最不频繁的前50个的交集的长度
x=[f1,f2,f3]
user_cmd_feature.append(x)
return user_cmd_feature
def get_label(filename,index=0):
x=[]
with open(filename) as f:
for line in f:
line=line.strip('\n')
x.append( int(line.split()[index]))
return x
if __name__ == '__main__':
user_cmd_list,user_cmd_dist_max,user_cmd_dist_min=load_user_cmd("./data/MasqueradeDat/User3")
#user_cmd_list 150个大小的list,list中的每个成员又是一个存放100个字符串(linux操作命令)的list.
#user_cmd_dist_max 15000个命令中最频繁使用的50个命令
#user_cmd_dist_min 15000个命令中最不频繁使用的50个命令
user_cmd_feature=get_user_cmd_feature(user_cmd_list,user_cmd_dist_max,user_cmd_dist_min)
#user_cmd_feature存放的是150个大小的List,list中的每个成员也是list,里面的list长度为3,记录100个记录分组中的不重复命令个数,和50个最频繁命令交集的个数,和50个最不频繁命令交集的个数
labels=get_label("./data/MasqueradeDat/label.txt",2) #取标签的第2列,因为从0开始,所以实际上是label.txt的第3列。一共100行,为什么是100行而不是150行?因为前面5000条(50行)都是正常数据,默认为0就是,就不用类型了,
# 后面10000(100行)条是随机包含有异常操作。
y=[0]*50+labels
#y为150个大小的list,前50个为正常数据,值为0, 后100个就是从label.txt中读出来的某一列,哪一列由get_label第2个参数决定。
#KNN中其实没什么训练集概念,用这个概念反而不容易理解,其它就是一个已知带标签的样本数据,当有新数据到来的时候和这些有标签的数据的属性做一个最近邻计算。
#算出距离最近的前k项,并统计这k项中最多的项属于哪类,那么新数据就属于这一类。
x_train=user_cmd_feature[0:N] #取前N项数据的特征用作样本
y_train=y[0:N] #取前N项数据对应的标签。这个主要是用于当新数据和已知样本匹配上后,返回这些已知样本的标签。
x_test=user_cmd_feature[N:150] #后50项用来测试
y_test=y[N:150] #测试数据实际上是知道真实的标签结果的,这个y_test就是真实结果,它用来和通过分类器预测的结果做对比。
neigh = KNeighborsClassifier(n_neighbors=3)
neigh.fit(x_train, y_train)#就是输入已知的条目属性,和该条目录对应的标签。
y_predict=neigh.predict(x_test)#然后输入测试数据,和已知条目属性做距离运算,返回预测结果。
#这个预测结果都是0,没法玩。。
score=np.mean(y_test==y_predict)*100#然后把测试结果和真实结果对比,算出错误率。
#print y
#print y_train
print(y_test)#打印测试集已经知标签
print(y_predict)#打印使用KNN算法预测后的标签。
print(score)
# print(classification_report(y_test, y_predict)) #这两句是sklearn中的东西,不知道啥意思,不影响KNN算法的学习,后续再看吧。
# print(metrics.confusion_matrix(y_test, y_predict))
如有疑问之处欢迎加我微信交流,请备注“优快云博客”
如有疑问之处欢迎加我微信交流,共同进步!请备注“优快云博客”
1714



被折叠的 条评论
为什么被折叠?



