【新人赛】阿里云恶意程序检测 -- 实践记录10.20 - 数据预处理 / 训练数据分析 / TF-IDF模型调参
Colab连接与数据预处理
Colab连接方法见上一篇博客
数据预处理:
import pandas as pd
import pickle
import numpy as np
# 训练数据和测试数据路径
train_path = './security_train.csv'
test_path = './security_test.csv'
# 将csv格式的训练数据处理为txt文本,只包含文件标签和api序列
def read_train_file(path):
labels = [] # 文件标签,0-正常/1-勒索病毒/ ... /7-木马程序
files = [] # api序列,文件调用的一系列API名称
data = pd.read_csv(path)
# for data in data1:
group_fileid = data.groupby('file_id') # 根据fileid分组数据
for file_name, file_group in group_fileid:
print(file_name)
file_labels = file_group['label'].values[0]
result = file_group.sort_values(['tid', 'index'], ascending=True) # 根据tid, index升序排列
api_sequence = ' '.join(result['api']) # 生成api序列
labels.append(file_labels)
files.append(api_sequence)
print("labels length: ", len(labels))
with open(path.split('/')[-1] + ".txt", 'w') as f:
for i in range(len(labels)):
f.write(str(labels[i]) + ' ' + files[i] + '\n')
# 将txt文本格式转为pkl序列化文件
# 这种格式读取时依然是结构化数据,而非字符串
def load_train2h5py(path="security_train.csv.txt"):
labels = []
files = []
with open(path) as f:
for i in f.readlines():
i = i.strip('\n')
labels.append(i[0])
files.append(i[2:])
labels = np.asarray(labels)
print(labels.shape)
with open("security_train.csv.pkl", 'wb') as f:
pickle.dump(labels, f)
pickle.dump(files, f)
# 将csv格式的训练数据处理为txt文本,只包含文件编号和api序列
def read_test_file(path):
names = []
files = []
data = pd.read_csv(path)
# for data in data1:
group_fileid = data.groupby('file_id')
for file_name, file_group in group_fileid:
print(file_name)
result = file_group.sort_values(['tid', 'index'], ascending=True)
api_sequence = ' '.join(result['api'])
names.append(file_name)
files.append(api_sequence)
print("names length: ", len(names))
with open("security_test.csv.pkl", 'wb') as f:
pickle.dump(names, f)
pickle.dump(files, f)
print("read train file.....")
read_train_file(train_path)
load_train2h5py()
print("read test file......")
read_test_file(test_path)
训练数据分析
import pandas as pd
train_path = './security_train.csv'
test_path = './security_test.csv'
df = pd.read_csv(train_path)
df_test = pd.read_csv(test_path)
查看行列索引
print(df.columns)
print(df.index)
Index(['file_id', 'label', 'api', 'tid', 'index'], dtype='object')
RangeIndex(start=0, stop=89806693, step=1)
文件label统计:
df = df.drop(['api', 'tid', 'index'], axis=1)
df = df.drop_duplicates()
df['label'].value_counts() / df.label.count()
结果如下,可见训练数据中除了正常文件外,感染型病毒是最多的。
0 0.358465
5 0.308850
7 0.107079
2 0.086124
3 0.059048
6 0.037085
1 0.036149
4 0.007201
Name: label, dtype: float64
文件调用的api统计
df.api.value_counts()
头尾数据展示,可见LdrGetProcedureAddress这个api调用次数最多:
统计文档频率:(文档频率求倒数,再求log,就是逆文本频率idf)
file_sum = 13887 # 文件总数,数据预处理中已求出
df = df.drop(['label', 'tid', 'index'], axis=1)
df = df.drop_duplicates()
df['api'].value_counts() / file_sum
头尾数据展示,可见NtClose,LdrGetProcedureAddress,LdrGetDllHandle等在每个文档中几乎都出现。
对比一下测试数据的文档频率,可以看出来,文档频率较大的api还是差不多这几个,所以训练数据和测试数据api的分布总体上差不多。
统计每个文件有多少个线程调用,以及该线程调用api的次数,看看文件运行状况
groupid = df.groupby('file_id')
groupid['tid'].value_counts()
头尾数据展示,可见运行此文件的线程不止一个:
统计每次调用该api的文件类型,一般都是什么类型的文件会调用此api
groupapi = df.groupby('api')
groupapi['label'].value_counts()
头尾数据展示,可以看到这些API会被哪种类型的文件更多地调用,有一些规律性,
TF-IDF模型训练代码
import pickle
import numpy as np
import xgboost as xgb
from sklearn.model_selection import StratifiedKFold
from sklearn.feature_extraction.text import TfidfVectorizer
with open("security_train.csv.pkl", "rb") as f:
labels = pickle.load(f)
files = pickle.load(f)
with open("security_test.csv.pkl", "rb") as f:
file_names = pickle.load(f)
outfiles = pickle.load(f)
tf-idf特征抽取,TfidfVectorizer参数解释:
ngram_range: 要提取的n-gram的n-values的下限和上限范围,[min_n, max_n]
min_df: 忽略低于给出阈值的文档频率的词条。max_df: 忽略高于给出阈值的文档频率的词条。
int 类型时表示一个词在文档中出现的次数。
float 类型时表示词出现的文档数与语料库文档数的百分比。
print("start tfidf...")
vectorizer = TfidfVectorizer(ngram_range=(1, 1), min_df=1, max_df=1.0) # 此处参数可以调
fit(): 根据参数规则进行操作,比如滤除停用词等,拟合原始数据,生成文档中有价值的词汇表
transform(): 使用符合fit的词汇表或提供给构造函数的词汇表,从原始文本文档中提取词频,转换成词频矩阵
train_features = vectorizer.fit_transform(files)
print("train_features fit transform")
out_features = vectorizer.transform(outfiles)
print("out_features transform")
k折交叉切分,分层采样,StratifiedKFold参数解析:
n_splits:折叠次数,默认为3,至少为2。
shuffle: 是否在每次分割之前打乱顺序。
random_state:随机种子,在shuffle==True时使用,默认使用np.random。
meta_train = np.zeros(shape=(len(files), 8))
meta_test = np.zeros(shape=(len(outfiles), 8))
skf = StratifiedKFold(n_splits=2, random_state=4, shuffle=True)
xgboost 是一种集成学习方法,通过构建多棵决策树来实现分类和回归任务。
XGBoost参数解析:
eta [default=0.3, alias: learning_rate] 学习率
max_depth [default=6] 树的最大深度,可以用来防止过拟合,典型值是3-10
colsample_bytree [default=1] 列采样率,也就是特征采样率
subsample [default=1] 构建每棵树对样本的采样率,如果设置成0.5,XGBoost会随机选择一半的样本作为训练集
objective[默认reg:linear] 损失函数,multi:softprob:和softmax一样,但是返回的是每个数据属于各个类别的概率
num_class(softmax分类的个数)
eval_metric 对于有效数据的度量方法,mlogloss 多分类logloss损失函数
silent [default=0] 取0时表示打印出运行时信息,取1时表示以缄默方式运行,不打印运行时信息
for i, (tr_ind, te_ind) in enumerate(skf.split(train_features, labels)):
X_train, X_train_label = train_features[tr_ind], labels[tr_ind]
X_val, X_val_label = train_features[te_ind], labels[te_ind]
print('FOLD: {}'.format(str(i)))
print(len(te_ind), len(tr_ind))
dtrain = xgb.DMatrix(X_train, label=X_train_label)
dtest = xgb.DMatrix(X_val, X_val_label)
dout = xgb.DMatrix(out_features)
param = {'max_depth': 6, 'eta': 0.1, 'eval_metric': 'mlogloss', 'silent': 1, 'objective': 'multi:softprob',
'num_class': 8, 'subsample': 0.8, 'colsample_bytree': 0.85}
evallist = [(dtrain, 'train'), (dtest, 'val')] # 测试 , (dtrain, 'train')
num_round = 300 # 循环次数
bst = xgb.train(param, dtrain, num_round, evallist, early_stopping_rounds=50)
pred_val = bst.predict(dtest)
pred_test = bst.predict(dout)
meta_train[te_ind] = pred_val
meta_test += pred_test
meta_test /= 2.0
TF-IDF调参过程
训练目标:
看一下n-gram,n取多少,训练得到的结果最好。(每次修改ngram_range参数,其他参数的设置见上述代码,暂不做修改)
ngram_range=(1, 1),使用1-gram:
print(train_features.shape)
print(out_features.shape)
(13887, 295)
(12955, 295)
训练得到的结果如下:
FOLD 1: train-mlogloss:0.101924 val-mlogloss:0.405779
FOLD 2: train-mlogloss:0.105662 val-mlogloss:0.406391
平均:train-mlogloss: 0.103793 val-mlogloss: 0.406085
修改参数ngram_range=(1, 2):
print(train_features.shape)
print(out_features.shape)
(13887, 20542)
(12955, 20542)
训练得到的结果如下:
FOLD 1: train-mlogloss:0.077268 val-mlogloss:0.34466
FOLD 2: train-mlogloss:0.075055 val-mlogloss:0.348921
平均:train-mlogloss: 0.0761615 val-mlogloss: 0.3467905
效果优于1-gram。
修改参数ngram_range=(1, 3):
print(train_features.shape)
print(out_features.shape)
(13887, 180858)
(12955, 180858)
训练得到的结果如下:
FOLD 1: train-mlogloss:0.070912 val-mlogloss:0.338498
FOLD 2: train-mlogloss:0.070977 val-mlogloss:0.344922
平均:train-mlogloss: 0.0709445 val-mlogloss: 0.34171
比2-gram稍好。
修改参数ngram_range=(1, 4):
print(train_features.shape)
print(out_features.shape)
(13887, 647361)
(12955, 647361)
训练得到的结果如下:
FOLD 1: train-mlogloss:0.068388 val-mlogloss:0.335232
FOLD 2: train-mlogloss:0.068232 val-mlogloss:0.33844
平均:train-mlogloss: 0.06831 val-mlogloss: 0.336836
比3-gram稍好。
修改参数ngram_range=(1, 5):
print(train_features.shape)
print(out_features.shape)
(13887, 1512641)
(12955, 1512641)
训练得到的结果如下:
FOLD 1: train-mlogloss:0.066721 val-mlogloss:0.336091
FOLD 2: train-mlogloss:0.065707 val-mlogloss:0.339242
平均:train-mlogloss: 0.066214 val-mlogloss: 0.3376665
比4-gram的要差。
修改参数ngram_range=(1, 6):
print(train_features.shape)
print(out_features.shape)
(13887, 2787688)
(12955, 2787688)
训练得到的结果如下:
FOLD 1: train-mlogloss:0.068417 val-mlogloss:0.334676
FOLD 2: train-mlogloss:0.069143 val-mlogloss:0.340957
平均:train-mlogloss: 0.06878 val-mlogloss: 0.3378165
比5-gram还要更差一点,不仅在验证集上表现不好,在训练集上表现也更差。
由测试集和验证集可知,n=4时预测效果最好。
提交线上:
n=3, logloss=0.528974
n=4, logloss=0.522686
n=5, logloss=0.526627
同样也是n=4时效果最佳。
实践心得
关于此问题下TF-IDF的效果没有N-gram好的原因:(就是TfidfVectorizer跑的效果不如CountVectorizer)
百度过来的解释:
在本质上IDF是一种试图抑制噪音的加权,并且单纯地认为文本频率小的单词就越重要,文本频率大的单词就越无用。这对于大部分文本信息,并不是完全正确的。IDF的简单结构并不能使提取的关键词,十分有效地反映单词的重要程度和特征词的分布情况,使其无法很好地完成对权值调整的功能。尤其是在同类语料库中,这一方法有很大弊端,往往一些同类文本的关键词被掩盖。例如:语料库D中教育类文章偏多,而文本j是一篇属于教育类的文章,那么教育类相关的词语的IDF值将会偏小,使提取文本关键词的召回率更低。
TF-IDF的优点是实现简单,相对容易理解。但是,TFIDF算法提取关键词的缺点也很明显,严重依赖语料库,需要选取质量较高且和所处理文本相符的语料库进行训练。另外,对于IDF来说,它本身是一种试图抑制噪声的加权,本身倾向于文本中频率小的词,这使得TF-IDF算法的精度不高。TF-IDF算法还有一个缺点就是不能反应词的位置信息,在对关键词进行提取的时候,词的位置信息,例如文本的标题、文本的首句和尾句等含有较重要的信息,应该赋予较高的权重。
学长说的:
NLP任务本质是词非常多,可能上万,但是我们这个任务API总数只有几百个。(所以这个问题因为数据的特殊性,所以和一般的NLP问题采用的方法不一样)
组会总结
1)考虑到实际应用的情况下,尽量做单模型。
2)要考虑问题的物理意义,不能一味地堆算法。
3)哪些地方用哪个技术,对应的技术能不能用?会不会产生什么问题?比如文本分类长度如果特别长的话有些模型可能用不了。考虑计算资源/预训练模型等。
【新人赛】阿里云恶意程序检测 -- 实践记录10.20 - 数据预处理 / 训练数据分析 / TF-IDF模型调参的更多相关文章
- 【新人赛】阿里云恶意程序检测 -- 实践记录10.13 - Google Colab连接 / 数据简单查看 / 模型训练
1. 比赛介绍 比赛地址:阿里云恶意程序检测新人赛 这个比赛和已结束的第三届阿里云安全算法挑战赛赛题类似,是一个开放的长期赛. 2. 前期准备 因为训练数据量比较大,本地CPU跑不起来,所以决定用Go ...
- 【新人赛】阿里云恶意程序检测 -- 实践记录10.27 - TF-IDF模型调参 / 数据可视化
TF-IDF模型调参 1. 调TfidfVectorizer的参数 ngram_range, min_df, max_df: 上一篇博客调了ngram_range这个参数,得出了ngram_range ...
- 【新人赛】阿里云恶意程序检测 -- 实践记录11.10 - XGBoost学习 / 代码阅读、调参经验总结
XGBoost学习: 集成学习将多个弱学习器结合起来,优势互补,可以达到强学习器的效果.要想得到最好的集成效果,这些弱学习器应当"好而不同". 根据个体学习器的生成方法,集成学习方 ...
- 【新人赛】阿里云恶意程序检测 -- 实践记录 11.24 - word2vec模型 + xgboost
使用word2vec训练词向量 使用word2vec无监督学习训练词向量,输入的是训练数据和测试数据,输出的是每个词的词向量,总共三百个词左右. 求和:然后再将每行数据中的每个词的词向量加和,得到每行 ...
- 【新人赛】阿里云恶意程序检测 -- 实践记录11.3 - n-gram模型调参
主要工作 本周主要是跑了下n-gram模型,并调了下参数.大概看了几篇论文,有几个处理方法不错,准备下周代码实现一下. xgboost参数设置为: param = {'max_depth': 6, ' ...
- 阿里云小程序云应用环境DIY,延长3倍免费期
阿里云清明节前刚刚推出了小程序云应用扶持计划一期活动 (活动链接见文章底部).假期研究了下以后,发觉不太给力.基本上就是给了2个月的免费测试环境,和平均2个月的基础版生产环境.而如果选用标准版生产环境 ...
- Android手机安全软件的恶意程序检测靠谱吗--LBE安全大师、腾讯手机管家、360手机卫士恶意软件检测方法研究
转载请注明出处,谢谢. Android系统开放,各大论坛活跃,应用程序分发渠道广泛,这也就为恶意软件的传播提供了良好的环境.好在手机上安装了安全软件,是否能有效的检测出恶意软件呢?下边针对LBE安全大 ...
- 阿里云centos安装docker-engine实践
近日在阿里云ECS服务器(centos系统)中安装docker,参考官方指南 https://docs.docker.com/engine/installation/linux/centos/ 大概 ...
- 阿里云HBase全新发布X-Pack 赋能轻量级大数据平台
一.八年双十一,造就国内最大最专业HBase技术团队 阿里巴巴集团早在2010开始研究并把HBase投入生产环境使用,从最初的淘宝历史交易记录,到蚂蚁安全风控数据存储.持续8年的投入,历经8年双十一锻 ...
随机推荐
- nginx配置文件的通用语法介绍
nginx的配置文件是ascii文本文件. 比如http{ }这种的是指令块,include mime.types: 这种是指令,include是指令,mime.types指令的参数,指令和参数之 ...
- CassandraAppender - distributed logging,分布式软件logback-appender
农历年最后一场scala-meetup听刘颖分享专业软件开发经验,大受启发.突然意识到一直以来都没有完全按照任何标准的开发规范做事.诚然,在做技术调研和学习的过程中不会对规范操作有什么严格要求,一旦技 ...
- js算法题
//较Low,看到的大神 帮补充 1.给定一个数组:,定义一个函数获取数组中所有的奇数,返回一个新数组:var arr1=[1,3,4,5,6,7,8,3,4,2,3,6]; function ...
- Django运行方式及处理流程总结(转发)
之前在网上看过一些介绍Django处理请求的流程和Django源码结构的文章,觉得了解一下这些内容对开发Django项目还是很有帮助的.所以,我按照自己的逻辑总结了一下Django项目的运行方式和对R ...
- Java类的加载过程与ClassLoader的理解及测试
当程序准备运行某个类,但该类还未被加载到内存中时,会经过以下三个步骤进行类的加载: 类的加载(Load)→类的连接(Link)→类的初始化(Initialize) 加载:类经过javac.exe编译的 ...
- mysql中大数据表alter增加字段报错:"1034 Incorrect key file for table 'table_name'; try to repair it"
mysql中大数据表alter增加字段报错:"1034 Incorrect key file for table 'table_name'; try to repair it" 现 ...
- [Python]获取字典所有值
方法一:Key Value 直接获取 databases = {1: 'Student', 2: 'School'} for k,v in databases.items(): print(k,v) ...
- java方法参数传递方式只有----值传递!
在通常的说法中,方法参数的传递分为两种,值传递和引用传递,值传递是指将实际参数复制一份传递到方法中, 在方法中的改动将不会影响到实际参数本身,而引用传递则是指传递的是实际参数本身,在方法中的改动将会影 ...
- linux系统初装
一.linux系统安装 VMware workstation是一个虚拟机软件,它的主要作用是在原有操作系统(windows或linux)下,虚拟出一台电脑,你可以在这台虚拟电脑上安装不同的操作系统,进 ...
- Javascript 基础学习(三)js 的原始类型和声明变量
java的基本数据类型一共有 byte short int long float double char boolean js中定义变量使用关键字 var js的原始类型(五个) String: 字符 ...