继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

KDD CUP99数据集的knn算法检测

慕森王
关注TA
已关注
手记 407
粉丝 107
获赞 550

一.背景介绍

KDD是数据挖掘与知识发现(Data Mining and Knowledge Discovery)的简称,KDD CUP是由ACM(Association for Computing Machiner)的 SIGKDD(Special Interest Group on Knowledge Discovery and Data Mining)组织的年度竞赛。”KDD CUP 99 dataset ”就是KDD竞赛在1999年举行时采用的数据集。

1998年美国国防部高级规划署(DARPA)在MIT林肯实验室进行了一项入侵检测评估项目。林肯实验室建立了模拟美国空军局域网的一个网络环境,收集了9周时间的 TCPdump(*) 网络连接和系统审计数据,仿真各种用户类型、各种不同的网络流量和攻击手段,使它就像一个真实的网络环境。这些TCPdump采集的原始数据被分为两个部分:7周时间的训练数据 (**) 大概包含5,000,000多个网络连接记录,剩下的2周时间的测试数据大概包含2,000,000个网络连接记录。

一个网络连接定义为在某个时间内从开始到结束的TCP数据包序列,并且在这段时间内,数据在预定义的协议下(如TCP、UDP)从源IP地址到目的IP地址的传递。每个网络连接被标记为正常(normal)或异常(attack),异常类型被细分为4大类共39种攻击类型,其中22种攻击类型出现在训练集中,另有17种未知攻击类型出现在测试集中。

kddcup99数据的主要标识为下图所示:


这些标识都是出现在最后一段,来作为区分正常访问与攻击的标志。

接着来说knn算法吧。

二.KNN算法原理

1.核心思想:kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。

2.算法介绍:

最简单最初级的分类器是将全部的训练数据所对应的类别都记录下来,当测试对象的属性和某个训练对象的属性完全匹配时,便可以对其进行分类。但是怎么可能所有测试对象都会找到与之完全匹配的训练对象呢,其次就是存在一个测试对象同时与多个训练对象匹配,导致一个训练对象被分到了多个类的问题,基于这些问题呢,就产生了KNN。

     KNN是通过测量不同特征值之间的距离进行分类。它的的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。K通常是不大于20的整数。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。

     下面通过一个简单的例子说明一下:如下图,绿色圆要被决定赋予哪个类,是红色三角形还是蓝色四方形?如果K=3,由于红色三角形所占比例为2/3,绿色圆将被赋予红色三角形那个类,如果K=5,由于蓝色四方形比例为3/5,因此绿色圆被赋予蓝色四方形类。



由此也说明了KNN算法的结果很大程度取决于K的选择。

     在KNN中,通过计算对象间距离来作为各个对象之间的非相似性指标,避免了对象之间的匹配问题,在这里距离一般使用欧氏距离或曼哈顿距离。欧氏距离就是坐标系中的点之间的距离,通过维数递增依次类推。


接下来对KNN算法的思想总结一下:就是在训练集中数据和标签已知的情况下,输入测试数据,将测试数据的特征与训练集中对应的特征进行相互比较,找到训练集中与之最为相似的前K个数据,则该测试数据对应的类别就是K个数据中出现次数最多的那个分类,其算法的描述为:

1)计算测试数据与各个训练数据之间的距离;

2)按照距离的递增关系进行排序;

3)选取距离最小的K个点;

4)确定前K个点所在类别的出现频率;

5)返回前K个点中出现频率最高的类别作为测试数据的预测分类。


三.代码实现


#!user/bin/env python#-*- coding utf-8 -*-# author:LiRuikun# coding=utf-8from __future__ import divisionimport numpy as npimport matplotlib.pyplot as pltdef classify(input_vct, data_set):
    data_set_size = data_set.shape[0]
    diff_mat = np.tile(input_vct, (data_set_size, 1)) - data_set  # 扩充input_vct到与data_set同型并相减    sq_diff_mat = diff_mat**2  # 矩阵中每个元素都平方    distance = sq_diff_mat.sum(axis=1)**0.5  # 每行相加求和并开平方根    mindistance=distance.min(axis=0)
    x=list(distance.reshape(data_set_size))    for i in range(len(x)):        if x[i]==mindistance:
            k=i            break    my_matrix = np.loadtxt(open("training.csv", "r",encoding='utf-8'), delimiter=",", skiprows=0)
    label=my_matrix[k][-1]    return label
#返回分类结果

def file2mat(test_filename, para_num):    """    将表格存入矩阵,test_filename为表格路径,para_num为存入矩阵的列数    返回目标矩阵,和矩阵每一行数据的类别    """    fr = open(test_filename)    lines = fr.readlines()    line_nums = len(lines)    result_mat = np.zeros((line_nums, para_num))  # 创建line_nums行,para_num列的矩阵    class_label = []    for i in range(line_nums):        line = lines[i].strip()        item_mat = line.split(',')        result_mat[i, :] = item_mat[0: para_num]        class_label.append(item_mat[-1])  # 表格中最后一列正常1异常2的分类存入class_label    fr.close()    return result_mat, class_labeldef roc(data_set):    normal = 0    data_set_size = data_set.shape[1]    roc_rate = np.zeros((2, data_set_size))    for i in range(data_set_size):        if data_set[2][i] == 1:            normal += 1    abnormal = data_set_size - normal    max_dis = data_set[1].max()    for j in range(1000):        threshold = max_dis / 1000 * j        normal1 = 0        abnormal1 = 0        for k in range(data_set_size):            if data_set[1][k] > threshold and data_set[2][k] == 1:                normal1 += 1            if data_set[1][k] > threshold and data_set[2][k] == 2:                abnormal1 += 1        roc_rate[0][j] = normal1 / normal  # 阈值以上正常点/全体正常的点        roc_rate[1][j] = abnormal1 / abnormal  # 阈值以上异常点/全体异常点    return roc_ratedef test(training_filename, test_filename):    training_mat, training_label = file2mat(training_filename, 32)    test_mat, test_label = file2mat(test_filename, 32)    test_size = test_mat.shape[0]    errorcount=0.0    for i in range(test_size):        classifierResult = classify(test_mat[i], training_mat)        print("the classifier came back with: %d, the real answer is: %d" % (int(classifierResult), int(test_label[i])))        if (int(classifierResult) != int(test_label[i])):            errorcount += 1.0    print("Total errors:%d" % errorcount)    #计算错误数    print("The total accuracy rate is %f" % (1.0 - errorcount/float(test_size)))if __name__ == "__main__":    test('training.csv', 'test.csv')

四.结果展示

之所以分类正确率太低,因为选取的训练集中正常的数据占到了99%。

由于训练样本集中绝大多数都是正常数据,因此我们选择k=1,即认为离测试点最近的点,测试点与之相同,认为对结果影响不大。由此可省略大量的计算。但有一个缺点就是训练集中未知入侵太少,而测试集中未知入侵太多,因此误判率可能较高。如本次实验中,训练集中正常数据占99%,而测试集中异常约占一半,且大多数异常数据在训练集中未出现。可见knn这种被动学习的机制需要大量的学习数据作支撑。


向训练集中加入测试集的数据重新测试,发现结果如下:


由于加入了测试集中的数据来供学习,此时正确率便提高了很多。

五.总结


KNN算法的优点:

1、思想简单,理论成熟,既可以用来做分类也可以用来做回归; 
2、可用于非线性分类; 
3、训练时间复杂度为O(n); 
4、准确度高,对数据没有假设,对outlier不敏感;

缺点: 
1、计算量大;(如果维度过高,又采用加权的分类的话,会非常慢的) 
2、样本不平衡问题(即有些类别的样本数量很多,而其它样本的数量很少); 
3、需要大量的内存;

原文出处

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP