西湖论剑网络安全技能大赛-大数据分析赛道-异常告警检测赛题-top6方案及代码
---- root
---- addition (文件夹下存放附加题结果文件)
---- data (文件下存放数据集,缺失,未经主办方允许暂不上传)
---- finalA (文件夹下存放决赛A结果文件)
---- finalB (文件夹下预测决赛B数据的预测代码以及必要文件)
---- predict_cide
---- feature_encoder (文件夹下存放特征工程必要文件)
---- model_pkl (文件夹下存放保存的模型文件)
---- main_predict.py (决赛B的模型预测代码文件)
---- processCode (文件夹下存放训练代码)
---- addition_code (附加题模型训练以及预测代码)
---- train_code (决赛A/B的模型训练代码)
该题目延续初赛题目,决赛提供更多数据。
-
数据清洗
destGeoAddress、srcGeoAddress、srcGeoCity、srcGeoLatitude、srcGeoLongitude这些字段全空。
accessAgent、transProtocol、name这些字段全为统一值,其中accessAgent字段全为HTTP,transProtocol字段全为TCP,name字段全为HTTP请求访问。
对于以上字段是对模型的训练无用的,因此将其删掉。
srcPort字段的值过于分散,训练集与测试集的数据共37094条数据,而srcPort字段的类别有19836个。对模型的训练无用,并且还有可能引入噪声,将其删掉。
-
特征工程
在特征工程方面,并没有做太多特征,将特征区分为类别型特征以及数值型特征,对类别型特征进行字符‘Nan’,然后直接labelencoder编码。
由于提交次数宝贵,因此,使用了一种大家普遍使用但也上分显著的方式:对字符序列按照ascii码排序,根据编码顺序进行编码,模型有所提升。这种方式虽然普通,但是我们有理由相信排序后的字符序列,靠的越近的,内容越相同。通过这种编码,我们将内容近似的靠在一起,而内容相差很大的,自然就相离的远些,进而提高模型的准确率。
由于按主办方要求,训练集和测试集不能碰面,因此在做labelencoder编码时需要一个文件保存额外信息来保证测试集和训练集的数据一致性。将每个做labelencoder编码的特征保存一个.csv文件,其中包括编码前、编码后、是否为众数等信息。
在对测试集特征处理的过程中,考虑到实际情况,有可能发生测试集出现的值而未在训练集出现,如果不做处理,模型会error报错。因此,为了提高模型鲁棒性,我们对这些值进行特殊处理。在工业界中,一般的处理方法,如果训练集有缺省值,则当作缺省值处理,如果没有缺省值,则当作众数处理。然而,在本此业务场景中,这种方式效果不佳,因此,我们探索了一种新的处理方式。由于我们在训练集特征工程的时候,labelencode编码后直接喂入模型训练,因此特征字段的顺序也被模型作为特性学习了,为了保证训练集和测试集的特征一致性,我们在对测试集做特征工程的时候,对于测试集出现而训练集没有出现的字段,通过二分查找法,找到与其最相似的字段,将该字段的编码值作为这个字段的编码值。
使用过滤法的特征筛选方法,做特征筛选后得到特征为模型训练使用到的特征。
-
模型
简单的使用了lgbm模型,并未进行模型调参,5折交叉验证。
(PS: 由于初赛的前期,一发入魂,第一周就直接晋级决赛。后面就没再投入太多时间到这里来,所以我们的特征、参数都比较简单。这也导致了我们决赛的时候A/B题拉跨。由于附加题权重极大,因此在决赛那天,我们并未投入时间到A/B中,而是押宝了附加题。不过很明显我们押对了,附加题分数排名top3,也依靠着附加题把我们从rank8拉到了rank6,拉到了奖杯的边缘,上台领了个奖。嘻嘻/
附加题是一个聚类问题,很遗憾之前一直没做过聚类问题,只是简单的用过k-means和DB处理一些特征。由于决赛只有九分还是八发机会呢,咳咳,忘记了,所以我们商量后决定直接莽k-means,简单撸的baseline能到7分呢,然后删除了requestUrl,因为他和requesUrlQuer特别像,删除后竟然到了9分。我们认为requestBody理应是一个很重要的特征,因此对其作了分箱处理:先将该字段根据值进行排序,然后进行不等长分箱操作。最后使用轮廓系数选择了K=3。emmm,就这样,比较简单。