博主前言
本篇博客是对Kaggle上的基于机器学习对恶意代码检测的源码的设计思路进行解析,里面的解析,是提炼写代码人解决问题的方案与精髓,仅供学习,此外,里面的解析难免有不当的之处,敬请读者斧正
摘要
要想检测恶意代码,首先我们必须对其进行特征提取,但是恶意代码的特征向量的维度是非常高的,在计算机中处理起来,计算速度会非常的慢,但是也不必担心,能够检测出恶意代码是否恶意,影响较大的仅仅是几个特征,为此,在进行分类学习之前我们需要对其进行数据预处理,编写这一段代码的作者,采用预先剔除无关影响的特征向量,留下影响较大的特征向量!已达到分类准确的目的,本篇博客是基于机器学习恶意代码检测之数据预处理的第三种处理方法
案例分析(3)
## 导入必要的第三方库
# 数据分析函数库
import numpy as np
import pandas as pd
# 绘图库
import matplotlib.pyplot as plt
import seaborn as sns
# 机器学习算法库
import lightgbm as lgb
# 模型选择库中k折交叉验证的函数库
from sklearn.model_selection import KFold
# 忽略警告错误的函数库
import warnings
# 垃圾回收的函数库
import gc
# 关于运行时间的函数库
import time
import sys
import datetime
# 导入进度条的函数库
from tqdm import tqdm
from sklearn.metrics import mean_squared_error
# 导入评估方法的库
from sklearn import metrics
warnings.simplefilter(action='ignore', category=FutureWarning)
## 导入数据分析的绘图第三方库(又是一个数据可视化绘图库)
# 初始化初始化绘图类对象
from plotly.offline import init_notebook_mode, iplot
# 引入绘图对象
import plotly.graph_objs as go
# 引入绘图工具
from plotly import tools
# 将绘图对象初始化
init_notebook_mode(connected=True)
# 将采集的数据进行分析
pd.set_option('display.max_columns', 500)
## 获取数据,明确它们的数据类型
dtypes = {
'MachineIdentifier': 'category',
'ProductName': 'category',
'EngineVersion': 'category',
'AppVersion': 'category',
'AvSigVersion': 'category',
'IsBeta': 'int8',
'RtpStateBitfield': 'float16',
'IsSxsPassiveMode': 'int8',
'DefaultBrowsersIdentifier': 'float16',
'AVProductStatesIdentifier': 'float32',
'AVProductsInstalled': 'float16',
'AVProductsEnabled': 'float16',
'HasTpm': 'int8',
'CountryIdentifier': 'int16',
'CityIdentifier': 'float32',
'OrganizationIdentifier': 'float16',
'GeoNameIdentifier': 'float16',
'LocaleEnglishNameIdentifier': 'int8',
'Platform': 'category',
'Processor': 'category',
'OsVer': 'category',
'OsBuild': 'int16',
'OsSuite': 'int16',
'OsPlatformSubRelease': 'category',
'OsBuildLab': 'category',
'SkuEdition': 'category',
'IsProtected': 'float16',
'AutoSampleOptIn': 'int8',
'PuaMode': 'category',
'SMode': 'float16',
'IeVerIdentifier': 'float16',
'SmartScreen': 'category',
'Firewall': 'float16',
'UacLuaenable': 'float32',
'Census_MDC2FormFactor': 'category',
'Census_DeviceFamily': 'category',
'Census_OEMNameIdentifier': 'float16',
'Census_OEMModelIdentifier': 'float32',
'Census_ProcessorCoreCount': 'float16',
'Census_ProcessorManufacturerIdentifier': 'float16',
'Census_ProcessorModelIdentifier': 'float16',
'Census_ProcessorClass': 'category',
'Census_PrimaryDiskTotalCapacity': 'float32',
'Census_PrimaryDiskTypeName': 'category',
'Census_SystemVolumeTotalCapacity': 'float32',
'Census_HasOpticalDiskDrive': 'int8',
'Census_TotalPhysicalRAM': 'float32',
'Census_ChassisTypeName': 'category',
'Census_InternalPrimaryDiagonalDisplaySizeInInches': 'float16',
'Census_InternalPrimaryDisplayResolutionHorizontal': 'float16',
'Census_InternalPrimaryDisplayResolutionVertical': 'float16',
'Census_PowerPlatformRoleName': 'category',
'Census_InternalBatteryType': 'category',
'Census_InternalBatteryNumberOfCharges': 'float32',
'Census_OSVersion': 'category',
'Census_OSArchitecture': 'category',
'Census_OSBranch': 'category',
'Census_OSBuildNumber': 'int16',
'Census_OSBuildRevision': 'int32',
'Census_OSEdition': 'category',
'Census_OSSkuName': 'category',
'Census_OSInstallTypeName': 'category',
'Census_OSInstallLanguageIdentifier': 'float16',
'Census_OSUILocaleIdentifier': 'int16',
'Census_OSWUAutoUpdateOptionsName': 'category',
'Census_IsPortableOperatingSystem': 'int8',
'Census_GenuineStateName': 'category',
'Census_ActivationChannel': 'category',
'Census_IsFlightingInternal': 'float16',
'Census_IsFlightsDisabled': 'float16',
'Census_FlightRing': 'category',
'Census_ThresholdOptIn': 'float16',
'Census_FirmwareManufacturerIdentifier': 'float16',
'Census_FirmwareVersionIdentifier': 'float32',
'Census_IsSecureBootEnabled': 'int8',
'Census_IsWIMBootEnabled': 'float16',
'Census_IsVirtualDevice': 'float16',
'Census_IsTouchEnabled': 'int8',
'Census_IsPenCapable': 'int8',
'Census_IsAlwaysOnAlwaysConnectedCapable': 'float16',
'Wdft_IsGamer': 'float16',
'Wdft_RegionIdentifier': 'float16',
'HasDetections': 'int8'
}
- 第1步:我们将所有的特征都提取出来,并分析统计它们的数据类型,便于选取特征
# 将数据类型为数值类的归为一类,是“字符串型”的归为一类
# 所有的数值类型
numerics = ['int8', 'int16', 'int32', 'int64', 'float16', 'float32', 'float64']
# 在numerics的列表中匹配特征中所包含的数据类型
# 数值类型
numerical_columns = [c for c,v in dtypes.items() if v in numerics]
# “字符串类型”
categorical_columns = [c for c,v in dtypes.items() if v not in numerics]
接下来:为了防止数据过大,我们限制仅读取前4,000,000行
# 限制仅读取4000000行
nrows = 4000000
# 归并所有的数据类型
retained_columns = numerical_columns + categorical_columns
# 读取训练集的文件
train = pd.read_csv('../input/train.csv',nrows = nrows,usecols = retained_columns,dtype = dtypes)
# 测试集将MachineIdentifier特征加上,删去目标值
retained_columns += ['MachineIdentifier']
retained_columns.remove('HasDetections')
# 读取测试集的文件
test = pd.read_csv('../input/test.csv',usecols = retained_columns,dtype = dtypes)
实际上,在数值变量中许多对应于标识符。 在当前数据集中,真正的数值变量实际上很少见。 下面,根据数据描述,我列出了真正数值的变量。
true_numerical_columns =
[
'Census_ProcessorCoreCount',
'Census_PrimaryDiskTotalCapacity',
'Census_SystemVolumeTotalCapacity',
'Census_TotalPhysicalRAM',
'Census_InternalPrimaryDiagonalDisplaySizeInInches',
'Census_InternalPrimaryDisplayResolutionHorizontal',
'Census_InternalPrimaryDisplayResolutionVertical',
'Census_InternalBatteryNumberOfCharges'
]
找出只有两种可能取值的特征
binary_variables = [c for c in train.columns if train[c].nunique() == 2]
最后确认一次“字符串型”的特征
categorical_columns = [c for c in train.columns if (c not in true_numerical_columns) & (c not in binary_variables)]
现在进行将数据分类的统计
# 各种变量
variables =
{
'categorical_columns': len(categorical_columns),
'binary_variables': len(binary_variables),
'true_numerical_columns': len(true_numerical_columns)
}
# 绘制饼状图
pie_trace = go.Pie(labels=list(variables.keys()), values=list(variables.values()))
# 饼状图的标题
layout = dict(title= "Variable types", height=400, width=800)
# 绘制饼状图
fig = dict(data=[pie_trace], layout=layout)
iplot(fig)
- 第2步:特征工程
对于具有大基数的变量,有效编码包括根据频率对类别进行排序,然后将这些变量视为数字
# 这是需要编码的特征变量:原则在各种特征可能取值种数中,挑选出前7中,即种数的基数较大,需要编码以便遍历时减小算力
frequency_encoded_variables =
[
'Census_OEMModelIdentifier',
'CityIdentifier',
'Census_FirmwareVersionIdentifier',
'AvSigVersion',
'Census_ProcessorModelIdentifier',
'Census_OEMNameIdentifier',
'DefaultBrowsersIdentifier'
]
for variable in tqdm(frequency_encoded_variables):
# 将每一个要编码的特征变量编码后一一对应成字典形式
freq_enc_dict = frequency_encoding(variable)
# 知识补充:map是Python中的内置函数类似于映射(将规定的值映射过去,通常在字典中使用),get()函数是返回字典里面的键的值,第二个参数如果要找的键不在集合中,就返回默认的,这里可以规定(代码中规定了nan即缺失值)
train[variable] = train[variable].map(lambda x: freq_enc_dict.get(x, np.nan))
test[variable] = test[variable].map(lambda x: freq_enc_dict.get(x, np.nan))
# 将对应的特征变量从变量的列表中删除 (目的:节省内存)
categorical_columns.remove(variable)
现在要进行打标签
indexer = {}
for col in tqdm(categorical_columns):
if col == 'MachineIdentifier': continue
_, indexer[col] = pd.factorize(train[col])
# factorize函数是一个返回值为元组的函数,第一维是自然索引0-(n-1),第二维是标签索引即同一个特征的不同取值打上不同的标签
for col in tqdm(categorical_columns):
if col == 'MachineIdentifier':
continue
# 训练集获取标签
train[col] = indexer[col].get_indexer(train[col])
# 测试集获取标签
test[col] = indexer[col].get_indexer(test[col])
将这一个特征矩阵降为目的是减少算力
# 将HasDetections纳入目标值列表中,以便测试时进行比较
target = train['HasDetections']
# 将特征矩阵中的目标值列删除
del train['HasDetections']
到此就是预处理的方法
归纳总结:
(1)首先是将每一个特征的数据类型进行分类,这里将它们分成,数值型,字符串型,特征可能取值种树为2,随后将它们的分布用饼状图的方式统计出来
(2)除此之外,还要统计一下所有特征变量可能取值的总数,并因此排序,挑选种数多的进行编码
(3)最后将目标值列删除,减少遍历的次数,即减小算力