做网站开公司做英文行程的网站

当前位置: 首页 > news >正文

做网站开公司,做英文行程的网站,机床回收网站建设,哪些网站做的比较炫目录 一、数据探索1.1 数据说明1.2 训练集数据探索1.2.1 数据特征类型1.2.2 数据分布1.2.3 缺失值1.2.4 异常值1.2.5 标签分布探索 1.3 测试集探索1.3.1 数据信息1.3.2 缺失值1.3.3 数据分布1.3.4 异常值 1.4 数据集联合分析1.4.1 file_id 分析1.4.2 API 分析 二、特征工程与基… 目录 一、数据探索1.1 数据说明1.2 训练集数据探索1.2.1 数据特征类型1.2.2 数据分布1.2.3 缺失值1.2.4 异常值1.2.5 标签分布探索 1.3 测试集探索1.3.1 数据信息1.3.2 缺失值1.3.3 数据分布1.3.4 异常值 1.4 数据集联合分析1.4.1 file_id 分析1.4.2 API 分析 二、特征工程与基线模型2.1 特征工程基础部分2.2 基线模型2.2.1 数据读取2.2.2 特征工程2.2.3 基线构建2.3.4 特征重要性分析2.3.5 模型测试 三、高阶数据探索3.1 数据读取3.2 多变量交叉探索 四、特征工程进阶与方案优化4.1 特征工程基础部分1导入工具包读取数据2内存管理3基础特征工程建造4特征获取 4.2 特征工程进阶部分1每个 API 调用线程 tid 的次数2每个 API 调用不同线程 tid 的次数3特征获取 4.3 基于 LightGBM 的模型验证1获取标签2训练集与测试集的构建将之前提取的特征与新生成的特征进行合并3评估指标构建4模型采用 5 折交叉验证方式 4.4 模型结果分析4.5 模型测试 ​Hi大家好我是半亩花海。 阿里云作为国内最大的云服务提供商每天都面临着网络上海量的恶意攻击。恶意软件是一种被设计用来对目标计算机造成破坏或者占用目标计算机资源的软件传统的恶意软件包括蠕虫、木马等。本项目来源于“阿里云天池”的“学习赛”的赛题针对恶意软件检测的现实场景而提出应用机器学习相关模型实现阿里云安全恶意程序的检测在一定程度上提高泛化能力提升对恶意样本的识别率。数据集来自阿里云安全恶意程序检测_数据集-阿里云天池 (aliyun.com)。 一、数据探索 1.1 数据说明 本项目提供的数据来自经过沙箱程序模拟运行后的 API 指令序列全为 Windows 二进制可执行程序经过脱敏处理样本数据均来自互联网其中恶意文件的类型有感染型病毒、木马程序、挖矿程序、DDoS木马、勒索病毒等数据总计 6 亿条。 1训练数据调用记录近 9000 万次文件 1 万多个以文件编号汇总字段描述如表所示 字段类型解释field_idbigint文件编号labelbigint文件标签apistring文件调用的 API 名称tidbigint调用 API 的线程编号indexstring线程中 API 调用的顺序编号 其中文件标签有 8 种0-正常 / 1-勒索病毒 / 2-挖矿程序 / 3-DDoS 木马 / 4-蠕虫病毒 / 5-感染型病毒 / 6-后门程序 / 7-木马程序。 注意 ① 一个文件调用的 API 数量有可能很多对于一个 tid 中调用超过 5000 个 API 的文件我们进行了截断按照顺序保留了每个 tid 前 5000 个 API 的记录。 ② 不同线程 tid 之间没有顺序关系同一个 tid 中的 index 由小到大代表调用的先后顺序关系。 ③ index 是单个文件在沙箱执行时的全局顺序由于沙箱执行时间有精度限制因此在同一个index 上会出现同线程或者不同线程都在多次执行 API 的情况其可以保证与 tid 内部的顺序相同但不保证连续。 2测试数据调用记录近 8000 万次文件 1 万多个。除了没有 label 字段数据格式与 训练数据一致。 1.2 训练集数据探索 1.2.1 数据特征类型

导入相关应用包

import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt# 忽略警告信息 import warnings warnings.filterwarnings(ignore)%matplotlib inline# 读取数据 path ./security_data/ train pd.read_csv(path security_train.csv) # 训练集 test pd.read_csv(path security_test.csv) # 测试集用 DataFrame.info() 函数查看训练集的大小、数据类型等信息。 train.info()从运行结果可以看出 数据中有 4 个 int64 类型file_id, label, tid, index的数据和 1 个 object 类型的数据api整个数据集的大小为 3.3 GB数据一共有 89806693 条记录 用 DataFrame.head() 函数查看训练集的头几行数据。 train.head()用 DataFrame.describe() 函数查看训练集的统计信息。 1.2.2 数据分布 使用箱线图查看单个变量的分布情况。下面以训练集为例取前10000条数据绘制“tid”变量的箱线图代码和运行结果如下 sns.boxplot(xtrain.iloc[:10000][tid])用 nunique() 函数查看训练集中变量取值的分布。 train.nunique()由运行结果可知file_id 的含有的信息如下 13887 个不同的值8 种不同的 labe295 个不同的 API2782 个不同的 tid5001 个不同的 index 1.2.3 缺失值 查看训练集数据的缺失情况。 train.isnull().sum()从运行结果看数据不存在缺失的情况。 1.2.4 异常值 分析训练集“index”特征 train[index].describe()“index”特征的最小值为 0最大值为 5000刚好是 5001 个值看不出异常值。 分析训练集的“tid”特征 train[tid].describe()“tid”特征的最小值为 100最大值为 20896因为这个字段表示的是线程所以我们目前也没办法判断是否有异常值。 1.2.5 标签分布探索 统计标签取值的分布情况。 “label”对应的含义如下表所示 值分类0正常1勒索病毒2挖矿程序3DDoS 木马4蠕虫病毒5感染型病毒6后门程序7木马程序 train[label].value_counts()由标签分布可以发现训练集中一共有 16375107 个正常文件(label0)2254561 个勒索病毒(label1)9693969 个挖矿程序(label2)8117585 个DDoS木马(label3)663815 个虫病毒(label4)33033543 个感染型病毒(label5)4586578 个后门程序(label6)15081535 个木马程序(label7)。 为了直观化我们可以通过条型图看数据的大小同时用饼图看数据的比例代码和结果如下 plt.figure(figsize(12, 4), dpi150) train[label].value_counts().sort_index().plot(kind bar)plt.figure(figsize(4, 4), dpi150) train[label].value_counts().sort_index().plot(kind pie)1.3 测试集探索 1.3.1 数据信息 用 DataFrame.head() 函数查看测试集的头几行数据。 test.head()用 DataFrame.info() 函数查看测试集的大小、数据类型等信息。 test.info()从运行结果可以看出 数据中有 3 个 int64 类型file_id, tid, index的数据和 1 个 object 类型的数据api整个数据集的大小为 2.4 GB数据一共有 79288375 条记录 1.3.2 缺失值 查看测试集数据的缺失情况。 test.isnull().sum()可知数据不存在缺失的情况。 1.3.3 数据分布 查看测试集中变量取值的分布。 sns.boxplot(xtest.iloc[:10000][tid])test.nunique()由运行结果可知file_id 的含有的信息如下 12955 个不同的值298 个不同的 API2047 个不同的 tid5001 个不同的 index 1.3.4 异常值 查看测试集的“index”特征 test[index].describe()由结果可知“index”特征的最小值为 0最大值为 5000刚好是 5001 个值看不出任何异常的情况。 查看测试集的“tid”特征 test[tid].describe()由结果可知“tid”特征的最小值为 100最大值为 9196因为这个字段表示的是线程所以目前也没办法判断是否有异常值。 1.4 数据集联合分析 1.4.1 file_id 分析 对比分析 “fleid” 变量在训练集和测试集中分布的重合情况 train_fileids train[file_id].unique() test_fileids test[file_id].unique()len(set(train_fileids) - set(test_fileids)) 运行结果表明有 932 个训练文件是测试文件中没有的。 len(set(test_fileids) - set(train_fileids)) 运行结果表明测试文件中有的文件在训练文件中都有。 我们发现训练数据集和测试数据集的 file_id 存在交叉也就是说 file_id 在训练集和测试集不是完全无交集的这个时候不能直接合并需要进行其他的处理来区分训练集和测试集。 1.4.2 API 分析 对比分析 “API” 变量在训练集和测试集中分布的重合情况 train_apis train[api].unique() test_apis test[api].unique()set(test_apis) - set(train_apis)运行结果表明测试集中有 6 个 API 未出现在训练集中分别是 reateDirectoryExWInternetGetConnectedStateExA,MessageBoxTimeoutW, NtCreateUserProcess, NtDeleteFile,TaskDialog。 set(train_apis) - set(test_apis)运行结果表明训练集中有 3 个 API 未出现在测试集中分别是 EncryptMessageRtlCompressBuffer 和 WSASendTo。 二、特征工程与基线模型 2.1 特征工程基础部分 import numpy as np import pandas as pd from tqdm import tqdm class _Data_Preprocess:def init(self):self.int8_max np.iinfo(np.int8).maxself.int8_min np.iinfo(np.int8).minself.int16_max np.iinfo(np.int16).maxself.int16_min np.iinfo(np.int16).minself.int32_max np.iinfo(np.int32).maxself.int32_min np.iinfo(np.int32).minself.int64_max np.iinfo(np.int64).maxself.int64_min np.iinfo(np.int64).minself.float16_max np.finfo(np.float16).maxself.float16_min np.finfo(np.float16).minself.float32_max np.finfo(np.float32).maxself.float32_min np.finfo(np.float32).minself.float64_max np.finfo(np.float64).maxself.float64_min np.finfo(np.float64).mindef _get_type(self, min_val, max_val, types):if types int:if max_val self.int8_max and min_val self.int8_min:return np.int8elif max_val self.int16_max max_val and min_val self.int16_min:return np.int16elif max_val self.int32_max and min_val self.int32_min:return np.int32return Noneelif types float:if max_val self.float16_max and min_val self.float16_min:return np.float16if max_val self.float32_max and min_val self.float32_min:return np.float32if max_val self.float64_max and min_val self.float64_min:return np.float64return Nonedef _memory_process(self, df):init_memory df.memory_usage().sum() / 1024 ** 2 / 1024print(Original data occupies {} GB memory..format(init_memory))df_cols df.columnsfor col in tqdm_notebook(df_cols):try:if float in str(df[col].dtypes):max_val df[col].max()min_val df[col].min()trans_types self._get_type(min_val, max_val, float)if trans_types is not None:df[col] df[col].astype(trans_types)elif int in str(df[col].dtypes):max_val df[col].max()min_val df[col].min()trans_types self._get_type(min_val, max_val, int)if trans_types is not None:df[col] df[col].astype(trans_types)except:print( Can not do any process for column, {}..format(col)) afterprocess_memory df.memory_usage().sum() / 1024 ** 2 / 1024print(After processing, the data occupies {} GB memory..format(afterprocess_memory))return df2.2 基线模型 2.2.1 数据读取 import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as pltimport lightgbm as lgb from sklearn.model_selection import train_test_split from sklearn.preprocessing import OneHotEncoderimport warnings warnings.filterwarnings(ignore) %matplotlib inlinepath ./security_data/ train pd.read_csv(path security_train.csv) test pd.read_csv(path security_test.csv)train.head()2.2.2 特征工程 1利用 count() 函数和 nunique() 函数生成特征反映样本调用 apitidindex 的频率信息。 def simple_sts_features(df):simple_fea pd.DataFrame()simple_fea[file_id] df[file_id].unique()simple_fea simple_fea.sort_values(file_id)df_grp df.groupby(file_id)simple_fea[file_id_api_count] df_grp[api].count().valuessimple_fea[file_id_api_nunique] df_grp[api].nunique().valuessimple_fea[file_id_tid_count] df_grp[tid].count().valuessimple_fea[file_id_tid_nunique] df_grp[tid].nunique().valuessimple_fea[file_id_index_count] df_grp[index].count().valuessimple_fea[file_id_index_nunique] df_grp[index].nunique().valuesreturn simple_fea2利用 mean() 函数、min() 函数、std() 函数、max() 函数生成特征tidindex 可认为是数值特征可提取对应的统计特征。 def simple_numerical_sts_features(df):simple_numerical_fea pd.DataFrame()simple_numerical_fea[file_id] df[file_id].unique()simple_numerical_fea simple_numerical_fea.sort_values(file_id)df_grp df.groupby(file_id)simple_numerical_fea[file_id_tid_mean] df_grp[tid].mean().valuessimple_numerical_fea[file_id_tid_min] df_grp[tid].min().valuessimple_numerical_fea[file_id_tid_std] df_grp[tid].std().valuessimple_numerical_fea[file_id_tid_max] df_grp[tid].max().valuessimple_numerical_fea[file_id_index_mean] df_grp[index].mean().valuessimple_numerical_fea[file_id_index_min] df_grp[index].min().valuessimple_numerical_fea[file_id_index_std] df_grp[index].std().valuessimple_numerical_fea[file_id_index_max] df_grp[index].max().valuesreturn simple_numerical_fea3利用定义的特征生成函数并生成训练集和测试集的统计特征。 反映样本调用 apitidindex 的频率信息的统计特征。 %%time simple_train_fea1 simple_sts_features(train)CPU times: total: 37 s Wall time: 37.1 s %%time simple_test_fea1 simple_sts_features(test)CPU times: total: 32.5 s Wall time: 32.6 s 反映 tidindex 等数值特征的统计特征。 %%time simple_train_fea2 simple_numerical_sts_features(train)CPU times: total: 6.14 s Wall time: 6.15 s %%time simple_test_fea2 simple_numerical_sts_features(test)CPU times: total: 5.38 s Wall time: 5.42 s 2.2.3 基线构建 获取标签 train_label train[[file_id,label]].drop_duplicates(subset [file_id,label], keep first) test_submit test[[file_id]].drop_duplicates(subset [file_id], keep first)训练集和测试集的构建

训练集测试集构建

train_data train_label.merge(simple_train_fea1, on file_id, howleft) train_data train_data.merge(simple_train_fea2, on file_id, howleft)test_submit test_submit.merge(simple_test_fea1, on file_id, howleft) test_submit test_submit.merge(simple_test_fea2, on file_id, howleft)因为本赛题给出的指标和传统的指标略有不同所以需要自己写评估指标这样方便对比线下与线上的差距以判断是否过拟合、是否出现线上线下不一致的问题等。 关于 LGB 的自定义评估指标的书写可以参考 LightGBM 的文档。以下为赛题的模型评估函数 def lgblogloss(preds,data):labels data.getlabel() classes np.unique(labels_) predsprob []for i in range(len(classes)):predsprob.append(preds[i*len(labels):(i1) * len(labels_)] )predsprob np.vstack(preds_prob) loss []for i in range(predsprob.shape[1]): # 样本个数sum_ 0for j in range(predsprob.shape[0]): #类别个数pred predsprob[j,i] # 第i个样本预测为第j类的概率if j labels[i]:sum np.log(pred)else:sum_ np.log(1 - pred)loss.append(sum_) return loss is: ,-1 * (np.sum(loss) / predsprob.shape[1]),False线下验证。因为数据与时间的相关性并不是非常大所以此处我们用传统的 5 折交叉验证来构建线下验证集。

模型验证

train_features [col for col in train_data.columns if col not in [label,file_id]] train_label label使用 5 折交叉验证采用 LightGBM 模型代码和运行结果如下 %%time from sklearn.model_selection import StratifiedKFold,KFold params {task:train, num_leaves: 255,objective: multiclass,num_class: 8,min_data_in_leaf: 50,learning_rate: 0.05,feature_fraction: 0.85,bagging_fraction: 0.85,bagging_freq: 5, max_bin: 128,random_state: 100, verbose: 50,early_stopping_rounds: 100} folds KFold(n_splits5, shuffleTrue, random_state15) oof np.zeros(len(train))predictres 0 models [] for fold, (trn_idx, val_idx) in enumerate(folds.split(traindata)):print(fold n°{}.format(fold))trn_data lgb.Dataset(train_data.iloc[trn_idx][train_features], labeltrain_data.iloc[trn_idx][train_label].values)val_data lgb.Dataset(train_data.iloc[val_idx][train_features], labeltrain_data.iloc[val_idx][train_label].values) clf lgb.train(params, trn_data, num_boost_round2000,valid_sets[trn_data,val_data], fevallgb_logloss) models.append(clf)2.3.4 特征重要性分析 通过特征重要性分析可以看到在当前指标显示的成绩下影响因子最高的特征因素从而更好地理解题目同时在此基础上进行特征工程的延伸。相应的代码和可视化结果如下 feature_importance pd.DataFrame() feature_importance[fea_name] train_features feature_importance[fea_imp] clf.feature_importance() feature_importance feature_importance.sort_values(fea_imp,ascending False)plt.figure(figsize[20, 10,]) sns.barplot(x feature_importance[fea_name], y feature_importance[fea_imp]) #sns.barplot(x fea_name,y fea_imp, data feature_importance)由运行结果可以看出 1API 的调用次数和 API 的调用类别数是最重要的两个特征即不同的病毒常常会调用不同的 API而且由于有些病毒需要复制自身的原因因此调用 API 的次数会明显比其他不同类别的病毒多。2第三到第五强的都是线程统计特征这也较为容易理解因为木马等病毒经常需要通过线程监听一些内容所以在线程等使用上会表现的略有不同。 2.3.5 模型测试 至此通过前期的数据探索分析和基础的特征工程我们已经得到了一个可以线上提交的基线模型。此处我们采用 LightGBM 进行 5 折交叉验证,也就是用上面训练的 5 个 LightGBM 分别对测试集进行预测然后将所有预测结果的均值作为最终结果。其预测结果并不能 100% 超过单折全量数据的 LightGBM但是大多数还是不错的建议将此作为 Baseline 方法的候选方法。 pred_res 0 fold 5 for model in models:pred_res model.predict(test_submit[train_features]) * 1.0 / foldtest_submit[prob0] 0 test_submit[prob1] 0 test_submit[prob2] 0 test_submit[prob3] 0 test_submit[prob4] 0 test_submit[prob5] 0 test_submit[prob6] 0 test_submit[prob7] 0test_submit[[prob0,prob1,prob2,prob3,prob4,prob5,prob6,prob7]] pred_res test_submit[[file_id,prob0,prob1,prob2,prob3,prob4,prob5,prob6,prob7]].to_csv(baseline.csv,index None)三、高阶数据探索 3.1 数据读取 import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt %matplotlib inline### 数据读取 path ./security_data/ train pd.read_csv(path security_train.csv) test pd.read_csv(path security_test.csv)3.2 多变量交叉探索 1通过统计特征 file_id_cnt分析 变量 file_id 和 api 之间的关系。 train_analysis train[[file_id,label]].drop_duplicates(subset [fileid,label], keep last)dic train[file_id].value_counts().to_dict() train_analysis[file_id_cnt] train_analysis[fileid].map(dic).values train_analysis[file_id_cnt].value_counts()可以看到文件调用 API 次数出现最多的是 5001 次。 sns.distplot(train_analysis[file_id_cnt])print(There are {} data are below 10000.format(np.sum(train_analysis[file_id_cnt] 1e / train_analysis.shape[0]))There are 0.8012529704039749 data are below 10000 我们也发现API 调用次数的 80% 都集中在 10000 次以下。 2为了便于分析变量 file_id_cnt 与 label 的关系将数据按 file_id_cnt 变量即 API 调用次数取值划分为 16 个区间。

file_id_cnt label 分析

def file_id_cnt_cut(x):if x 15000:return x // 1e3else:return 15 train_analysis[file_id_cnt_cut] train_analysis[file_id_cnt].map(file_id_cnt_cut).values然后随机选取 4 个区间进行查看代码及运行结果如下所示。 plt.figure(figsize[16,20]) plt.subplot(321) train_analysis[train_analysis[file_id_cnt_cut] 0][label].value_counts().sort_index().plot(kind bar) plt.title(file_id_cnt_cut 0) plt.xlabel(label) plt.ylabel(label_number)plt.subplot(322) train_analysis[train_analysis[file_id_cnt_cut] 1][label].value_counts().sort_index().plot(kind bar) plt.title(file_id_cnt_cut 1) plt.xlabel(label) plt.ylabel(label_number)plt.subplot(323) train_analysis[train_analysis[file_id_cnt_cut] 14][label].value_counts().sort_index().plot(kind bar) plt.title(file_id_cnt_cut 14) plt.xlabel(label) plt.ylabel(label_number)plt.subplot(324) train_analysis[train_analysis[file_id_cnt_cut] 15][label].value_counts().sort_index().plot(kind bar) plt.title(file_id_cnt_cut 15) plt.xlabel(label) plt.ylabel(label_number)plt.subplot(313) train_analysis[label].value_counts().sort_index().plot(kind bar) plt.title(All Data) plt.xlabel(label) plt.ylabel(label_number) 从图中可以看到当 API 调用次数越多时该 API 是第五类病毒感染型病毒的可能性就越大。 用分簇散点图查看 label 下file_id_cnt的分布由于绘制分簇散点图比较耗时因此我们采用 1000 个样本点。 plt.figure(figsize[16, 10]) sns.swarmplot(x train_analysis.iloc[:1000][label], y train_analysis.iloc[:1000][file_id_cnt])从图中得到以下结论从频次上看第 5 类病毒调用 API 的次数最多从调用峰值上看第 2 类和 7 类病毒有时能调用 150000 次的 API。 3首先通过文件调用 API 的类别数 file_id_api_nunique分析变量 fileid 和 API 的关系。 dic train.groupby(file_id)[api].nunique().to_dict() train_analysis[file_id_api_nunique] train_analysis[fileid].map(dic).values sns.distplot(train_analysis[file_id_api_nunique]) train_analysis[file_id_api_nunique].describe()文件调用 API 的类别数绝大部分都在 100 以内最少的是 1 个最多的是 170 个。 然后分析变量 file_id_api_nunique 和 label 的关系。 train_analysis.loc[train_analysis.file_id_api_nunique 100][label].value_counts().sort_index().plot(kind bar) plt.title(File with api nunique 100) plt.xlabel(label) plt.ylabel(label_number) 从图中可以发现第 5 类病毒调用不同 API 的次数是最多的。在上面的分析中我们也发现第 5 类病毒调用 API 的次数最多调用不同 API 的次数多也是可以理解的。 plt.figure(figsize[16, 10]) sns.boxplot(x train_analysis[label], y train_analysis[file_id_api_nunique])从图中得到以下结论第 3 类病毒调用不同 API 的次数相对较多第 2 类病毒调用不同 API 的次数最少第 467 类病毒的离群点较少第 1 类病毒的离群点最多第 3 类病毒的离群点主要在下方第 0 类和第 5 类的离群点则集中在上方。 4首先通过 file_id_index_nunique 和 file_id_index_max 两个统计特征分析变量 fileid 和 index 之间的关系。有个奇怪的现象我们发现调用 API 顺序编号的两个边缘0 和 5001的样本数是最多的因此可以单独看一下这两个点的 label 分布。 dic train.groupby(file_id)[index].nunique().to_dict() train_analysis[file_id_index_nunique] train_analysis[fileid].map(dic).valuestrain_analysis[file_id_index_nunique].describe()sns.distplot(train_analysis[file_id_indexnunique]) dic train.groupby(file_id)[index].max().to_dict() train_analysis[file_id_index_max] train_analysis[fileid].map(dic).values sns.distplot(train_analysis[file_id_index_max]) 从图中可以看出文件调用 index 有两个极端一个是在 1 附近另一个是在 5000 附近。 然后分析变量 file_id_index_nunique 和 file_id_index_max 与 label 的关系。 plt.figure(figsize[16,8]) plt.subplot(121) train_analysis.loc[train_analysis.file_id_index_nunique 1][label].value_counts().sort_index().plot(kind bar) plt.title(File with index nunique 1) plt.xlabel(label) plt.ylabel(label_number) plt.subplot(122) train_analysis.loc[train_analysis.file_id_index_nunique 5001][label].value_counts().sort_index().plot(kind bar) plt.title(File with index nunique 5001) plt.xlabel(label) plt.ylabel(label_number) 从图中可以发现在文件顺序编号只有一个时文件的标签只会是 0正常、2挖矿程序或 5感染型病毒而不会是其他病毒而且最大概率可能是 5对于顺序次数大于 5000 个的文件其和上面调用 API 次数很大时类似。 还可以通过绘制小提琴图、分类散点图分析代码和结果如下 plt.figure(figsize[16,10]) sns.violinplot(x train_analysis[label], y train_analysis[file_id_api_nunique])plt.figure(figsize[16,10]) sns.violinplot(x train_analysis[label], y train_analysis[file_id_index_max])plt.figure(figsize[16,10]) sns.stripplot(x train_analysis[label], y train_analysis[file_id_index_max])从图中得到的结论第 3 类病毒调用不同 index 次数的平均值最大第 2 类病毒调用不同 index 次数的平均值最小第 567 类病毒调用不同 index 次数的平均值相似。 5首先通过 file_id_tid_nunique和 file_id_tid_max 两个统计特征分析变量 fileid 和 tid 之间的关系。 dic train.groupby(file_id)[tid].nunique().to_dict() train_analysis[file_id_tid_nunique] train_analysis[fileid].map(dic).values train_analysis[file_id_tid_nunique].describe()sns.distplot(train_analysis[file_id_tidnunique]) dic train.groupby(file_id)[tid].max().to_dict() train_analysis[file_id_tid_max] train_analysis[fileid].map(dic).values train_analysis[file_id_tid_max].describe()sns.distplot(train_analysis[file_id_tid_max]) 然后分析变量 file_id_tid_nunique 和 file_id_tid_max 与 label 的关系。 plt.figure(figsize[16,8]) plt.subplot(121) train_analysis.loc[train_analysis.file_id_tid_nunique 5][label].value_counts().sort_index().plot(kind bar) plt.title(File with tid nunique 5) plt.xlabel(label) plt.ylabel(label_number) plt.subplot(122) train_analysis.loc[train_analysis.file_id_tid_nunique 20][label].value_counts().sort_index().plot(kind bar) plt.title(File with tid nunique 20) plt.xlabel(label) plt.ylabel(label_number) 其中0正常文件1勒索病毒2挖矿程序3DDoS 木马4蠕虫病毒5感染型病毒6后门程序7木马程序。 还可以通过箱线图和小提琴图进一步分析。 plt.figure(figsize[12,8]) sns.boxplot(x train_analysis[label], y train_analysis[file_id_tid_nunique])plt.figure(figsize[12,8]) sns.violinplot(x train_analysis[label], y train_analysis[file_id_tid_nunique])分析 file_id 和 tid 的 max 特征我们将 tid 最大值大于 3000 的数据和整体比较发现分布差异并不是非常大。 plt.figure(figsize[16,8]) plt.subplot(121) train_analysis.loc[train_analysis.file_id_tid_max 3000][label].value_counts().sort_index().plot(kind bar) plt.title(File with tid max 3000) plt.xlabel(label) plt.ylabel(label_number) plt.subplot(122) train_analysis[label].value_counts().sort_index().plot(kind bar) plt.title(All Data) plt.xlabel(label) plt.ylabel(label_number) 从图中得出的结论所有文件调用的线程都相对较少第 7 类病毒调用的线程数的范围最大第 0 类3 类和 4 类调用的不同线程数类似。 6分析变量 API 与 label 的关系代码及运行结果如下 train[api_label] train[api] _ train[label].astype(str) dic_ train[api_label].value_counts().to_dict()df_api_label pd.DataFrame.fromdict(dic,orient index).reset_index() df_api_label.columns [api_label, api_label_count]df_api_label[label] df_api_label[apilabel].apply(lambda x:int(x.split()[-1]))labels df_api_label[label].unique() for label in range(8):print(* * 50, label,* * 50)print(df_api_label.loc[df_api_label.label label].sort_values(api_label_count).iloc[-5:][[api_label,api_label_count]])print(* * 103)从结果可以得到以下结论LdrGetProcedureAddress所有病毒和正常文件都是调用比较多的第 5 类病毒Thread32Next 调用得较多第 6 类和 7 类病毒NtDelayExecution 调用得较多第 2 类和 7 类病毒Process32NextW 调用得较多。 四、特征工程进阶与方案优化 在快速 Baseline 的基础上通过对多变量的交叉分析可以增加新的 pivot 特征迭代优化一般新的模型。 4.1 特征工程基础部分 1导入工具包读取数据 import pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as pltimport lightgbm as lgb from sklearn.model_selection import train_test_split from sklearn.preprocessing import OneHotEncoderfrom tqdm import tqdm_notebookimport warnings warnings.filterwarnings(ignore) %matplotlib inline### 数据读取 path ./security_data/ train pd.read_csv(path security_train.csv) test pd.read_csv(path security_test.csv)2内存管理

内存管理

import numpy as np import pandas as pd from tqdm import tqdm class _Data_Preprocess:def init(self):self.int8_max np.iinfo(np.int8).maxself.int8_min np.iinfo(np.int8).minself.int16_max np.iinfo(np.int16).maxself.int16_min np.iinfo(np.int16).minself.int32_max np.iinfo(np.int32).maxself.int32_min np.iinfo(np.int32).minself.int64_max np.iinfo(np.int64).maxself.int64_min np.iinfo(np.int64).minself.float16_max np.finfo(np.float16).maxself.float16_min np.finfo(np.float16).minself.float32_max np.finfo(np.float32).maxself.float32_min np.finfo(np.float32).minself.float64_max np.finfo(np.float64).maxself.float64_min np.finfo(np.float64).mindef _get_type(self, min_val, max_val, types):if types int:if max_val self.int8_max and min_val self.int8_min:return np.int8elif max_val self.int16_max max_val and min_val self.int16_min:return np.int16elif max_val self.int32_max and min_val self.int32_min:return np.int32return Noneelif types float:if max_val self.float16_max and min_val self.float16_min:return np.float16if max_val self.float32_max and min_val self.float32_min:return np.float32if max_val self.float64_max and min_val self.float64_min:return np.float64return Nonedef _memory_process(self, df):init_memory df.memory_usage().sum() / 1024 ** 2 / 1024print(Original data occupies {} GB memory..format(init_memory))df_cols df.columnsfor col in tqdm_notebook(df_cols):try:if float in str(df[col].dtypes):max_val df[col].max()min_val df[col].min()trans_types self._get_type(min_val, max_val, float)if trans_types is not None:df[col] df[col].astype(trans_types)elif int in str(df[col].dtypes):max_val df[col].max()min_val df[col].min()trans_types self._get_type(min_val, max_val, int)if trans_types is not None:df[col] df[col].astype(trans_types)except:print( Can not do any process for column, {}..format(col)) afterprocess_memory df.memory_usage().sum() / 1024 ** 2 / 1024print(After processing, the data occupies {} GB memory..format(afterprocess_memory))return dfmemory_process _Data_Preprocess()3基础特征工程建造 def simple_sts_features(df):simple_fea pd.DataFrame()simple_fea[file_id] df[file_id].unique()simple_fea simple_fea.sort_values(file_id)df_grp df.groupby(file_id)simple_fea[file_id_api_count] df_grp[api].count().valuessimple_fea[file_id_api_nunique] df_grp[api].nunique().valuessimple_fea[file_id_tid_count] df_grp[tid].count().valuessimple_fea[file_id_tid_nunique] df_grp[tid].nunique().valuessimple_fea[file_id_index_count] df_grp[index].count().valuessimple_fea[file_id_index_nunique] df_grp[index].nunique().valuesreturn simple_feadef simple_numerical_sts_features(df):simple_numerical_fea pd.DataFrame()simple_numerical_fea[file_id] df[file_id].unique()simple_numerical_fea simple_numerical_fea.sort_values(file_id)df_grp df.groupby(file_id)simple_numerical_fea[file_id_tid_mean] df_grp[tid].mean().valuessimple_numerical_fea[file_id_tid_min] df_grp[tid].min().valuessimple_numerical_fea[file_id_tid_std] df_grp[tid].std().valuessimple_numerical_fea[file_id_tid_max] df_grp[tid].max().valuessimple_numerical_fea[file_id_index_mean] df_grp[index].mean().valuessimple_numerical_fea[file_id_index_min] df_grp[index].min().valuessimple_numerical_fea[file_id_index_std] df_grp[index].std().valuessimple_numerical_fea[file_id_index_max] df_grp[index].max().valuesreturn simple_numerical_fea4特征获取 %%time simple_train_fea1 simple_sts_features(train)CPU times: total: 37.2 s Wall time: 37.4 s %%time simple_test_fea1 simple_sts_features(test)CPU times: total: 31.4 s Wall time: 31.5 s %%time simple_train_fea2 simple_numerical_sts_features(train)CPU times: total: 5.95 s Wall time: 6.02 s %%time simple_test_fea2 simple_numerical_sts_features(test)CPU times: total: 5.28 s Wall time: 5.32 s 4.2 特征工程进阶部分 1每个 API 调用线程 tid 的次数 def api_pivot_count_features(df):tmp df.groupby([file_id,api])[tid].count().to_frame(api_tid_count).reset_index()tmp_pivot pd.pivot_table(data tmp, index file_id, columnsapi, valuesapi_tid_count, fill_value0)tmp_pivot.columns [tmp_pivot.columns.names[0] pivot str(col) for col in tmp_pivot.columns]tmp_pivot.reset_index(inplace True)tmp_pivot memory_process._memory_process(tmp_pivot)return tmp_pivot 2每个 API 调用不同线程 tid 的次数 def api_pivot_nunique_features(df):tmp df.groupby([file_id,api])[tid].nunique().to_frame(api_tid_nunique).reset_index()tmp_pivot pd.pivot_table(data tmp, index file_id, columnsapi, valuesapi_tid_nunique, fill_value0)tmp_pivot.columns [tmp_pivot.columns.names[0] pivot str(col) for col in tmp_pivot.columns]tmp_pivot.reset_index(inplace True)tmp_pivot memory_process._memory_process(tmp_pivot)return tmp_pivot 3特征获取 %%time simple_train_fea3 api_pivot_count_features(train)%%time simple_test_fea3 api_pivot_count_features(test)%%time simple_train_fea4 api_pivot_count_features(train)%%time simple_test_fea4 api_pivot_count_features(test)4.3 基于 LightGBM 的模型验证 1获取标签 train_label train[[file_id,label]].drop_duplicates(subset [file_id,label], keep first) test_submit test[[file_id]].drop_duplicates(subset [file_id], keep first)2训练集与测试集的构建将之前提取的特征与新生成的特征进行合并 train_data train_label.merge(simple_train_fea1, on file_id, howleft) train_data train_data.merge(simple_train_fea2, on file_id, howleft) train_data train_data.merge(simple_train_fea3, on file_id, howleft) train_data train_data.merge(simple_train_fea4, on file_id, howleft)test_submit test_submit.merge(simple_test_fea1, on file_id, howleft) test_submit test_submit.merge(simple_test_fea2, on file_id, howleft) test_submit test_submit.merge(simple_test_fea3, on file_id, howleft) test_submit test_submit.merge(simple_test_fea4, on file_id, howleft)3评估指标构建 分数采用 logloss 计算公式如下 logloss  1 N ∑ j N ∑ i M [ y i j log ⁡ ( P i j ) ( 1 − y i j ) log ⁡ ( 1 − P i j ) ] \text { logloss }\frac{1}{N} \sum_j^N \sumi^M\left[y{i j} \log \left(P{i j}\right)\left(1-y{i j}\right) \log \left(1-P{i j}\right)\right]  logloss N1​j∑N​i∑M​[yij​log(Pij​)(1−yij​)log(1−Pij​)] 其中M 代表分类数N 代表测试集样本数 y i j {y}{ij} yij​ 为代表第 i 个样本是否为类别 j1为是0为否 P i j {P}_{ij} Pij​ 代表选手提交的第 i 个样本被预测为类别 j 的概率最终公布的 logloss 保留小数点后 6 位。 需特别注意log 对于小于 1 的数是非常敏感的。比如 log0.1 和 log0.000001 的单个样本的误差为 10 左右而 1og0.99 和 1og0.95 的单个误差为 0.1 左右。 logloss 和 AUC 的区别AUC 只在乎把正样本排到前面的能力logloss 更加注重评估的准确性。如果给预测值乘以一个倍数则 AUC 不会变但是 logloss 会变。

评估指标构建

def lgblogloss(preds,data):labels data.getlabel() classes np.unique(labels_) predsprob []for i in range(len(classes)):predsprob.append(preds[i*len(labels):(i1) * len(labels_)] )predsprob np.vstack(preds_prob) loss []for i in range(predsprob.shape[1]): sum_ 0for j in range(predsprob.shape[0]): pred predsprob[j,i] if j labels[i]:sum np.log(pred)else:sum_ np.log(1 - pred)loss.append(sum_) return loss is: ,-1 * (np.sum(loss) / predsprob.shape[1]),False4模型采用 5 折交叉验证方式 train_features [col for col in train_data.columns if col not in [label,file_id]] train_label label%%time from sklearn.model_selection import StratifiedKFold,KFold params {task:train, num_leaves: 255,objective: multiclass,num_class: 8,min_data_in_leaf: 50,learning_rate: 0.05,feature_fraction: 0.85,bagging_fraction: 0.85,bagging_freq: 5, max_bin:128,random_state:100,verbose: 50,early_stopping_rounds: 100} folds KFold(n_splits5, shuffleTrue, random_state15) oof np.zeros(len(train))predictres 0 models [] for fold, (trn_idx, val_idx) in enumerate(folds.split(traindata)):print(fold n°{}.format(fold))trn_data lgb.Dataset(train_data.iloc[trn_idx][train_features], labeltrain_data.iloc[trn_idx][train_label].values)val_data lgb.Dataset(train_data.iloc[val_idx][train_features], labeltrain_data.iloc[val_idx][train_label].values) clf lgb.train(params, trn_data, num_boost_round2000,valid_sets[trn_data,val_data], fevallgb_logloss) models.append(clf)4.4 模型结果分析 特征相关性分析 计算特征之间的相关性系数并用热力图可视化显示。 这里采样 10000个 样本观察其中 20 个特征的线性相关性。 plt.figure(figsize[10,8]) sns.heatmap(train_data.iloc[:10000, 1:21].corr())通过查看特征变量与 label 的相关性我们也可以再次验证之前数据探索 EDA 部分的结论每个文件调用 API 的次数与病毒类型是强相关的。 特征重要性分析的代码和结果如下

特征重要性分析

feature_importance pd.DataFrame() feature_importance[fea_name] train_features feature_importance[fea_imp] clf.feature_importance() feature_importance feature_importance.sort_values(fea_imp,ascending False)feature_importance.sort_values(fea_imp, ascending False)我们把 LightGBM 的特征重要性进行排序并输出同样也可以再次验证之前 EDA 部分的结论每个文件调用 API 的次数与病毒类型是强相关的。 plt.figure(figsize[20, 10,]) plt.figure(figsize[20, 10,]) sns.barplot(x feature_importance.iloc[:10][fea_name], y feature_importance.iloc[:10][fea_imp])plt.figure(figsize[20, 10,]) sns.barplot(x feature_importance[fea_name], y feature_importance[fea_imp])对特征的重要性分析也再一次验证了我们的想法 API 的调用次数及 API 的调用类别数是最重要的两个特征也就是说不同的病毒常常会调用不同的 API而且因为有些病毒需要复制自身的原因调用 API 的次数会非常多第三到第五强的都是线程统计特征这也较为容易理解因为木马等病毒经常需要通过线程监听一些内容所以在线程数量的使用上也会表现的略不相同。 树模型绘制。我们把 LightGBM 的树模型依次输出并结合绘制的树模型进行业务的理解。 ax lgb.plot_tree(clf, tree_index1, figsize(20, 8), show_info[split_gain]) plt.show()4.5 模型测试 此处我们采用 LightGBM 模型进行 5 折交叉验证取预测均值作为最终结果。 LightGBM 模型进行 5 折交叉验证的预测并不能 100% 超过单折全量数据的 LightGBM但是在大多数时候取得的效果还是不错的建议将此作为 Baseline 方法的候选。 pred_res 0 flod 5 for model in models:pred_res model.predict(test_submit[train_features]) * 1.0 / flodtest_submit[prob0] 0 test_submit[prob1] 0 test_submit[prob2] 0 test_submit[prob3] 0 test_submit[prob4] 0 test_submit[prob5] 0 test_submit[prob6] 0 test_submit[prob7] 0test_submit[[prob0,prob1,prob2,prob3,prob4,prob5,prob6,prob7]] pred_res test_submit[[file_id,prob0,prob1,prob2,prob3,prob4,prob5,prob6,prob7]].to_csv(baseline2.csv,index None)最后这里有点小报错但我一直不能很好地解决尝试多次暂罢大家可以多多交流学习