-
-
[原创]python_mmdt:从1到2--实现基于KNN的机器学习恶意代码分类器(三)
-
发表于: 2021-2-3 19:00 7147
-
首先,我们一起简单回顾三个基本概念。
机器学习是人工智能的一个分支。人工智能的研究历史有着一条从以“推理”为重点,到以“知识”为重点,再到以“学习”为重点的自然、清晰的脉络。显然,机器学习是实现人工智能的一个途径,即以机器学习为手段解决人工智能中的问题。机器学习在近30多年已发展为一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、计算复杂性理论等多门学科。机器学习理论主要是设计和分析一些让计算机可以自动“学习”的算法。机器学习算法是一类从数据中自动分析获得规律,并利用规律对未知数据进行预测的算法。-- wikipedia
如上所诉,机器学习的本质是一种算法,这种算法由数据分析习得。当数据量充足时,机器学习方法所能得到的结果,可无限逼近于事物的本质面貌。
监督学习(英语:Supervised learning),又叫有监督学习,监督式学习,是机器学习的一种方法,可以由训练资料中学到或建立一个模式(函数/learning model),并依此模式推测新的实例。训练资料是由输入物件(通常是向量)和预期输出所组成。函数的输出可以是一个连续的值(称为回归分析),或是预测一个分类标签(称作分类)。-- wikipedia
如上所诉,监督学习有三要素:(特征向量训练集,算法/模型,预测)。通过机器学习算法分析处理有标签的训练集,生成模型,利用模型处理无标签数据,输出预测结果。
最近邻居法(k-NN算法,又译K-近邻算法)是一种用于分类和回归的非参数统计方法。在这两种情况下,输入包含特征空间(Feature Space)中的k个最接近的训练样本。
最近邻居法采用向量空间模型来分类,概念为相同类别的案例,彼此的相似度高,而可以借由计算与已知类别案例之相似度,来评估未知类别案例可能的分类。-- wikipedia
如上所诉,k-NN算法的核心思想是:一个样本与数据集中的k个样本最相似,如果这k个样本中的大多数属于某一个类别,则该样本也属于这个类别。
结合上文介绍,要在恶意代码检测场景中应用机器学习,至少需要准备两样东西:
利用python_mmdt
工具,我们处理一批已知标签的样本,生成对应的mmdt_hash
值,mmdt_hash
的每一个字节都是特征向量的一个维度。将这些值保存下来,既可作为有标签的训练集
。(mmdt_hash
的详细介绍,见之前两篇文章)
提到机器学习,自然而然地会让人想到k-NN算法。k-NN算法具有明确的目标,清晰的流程,可读的结果,几乎可以认为是最简单有效的机器学习算法。k-NN算法通过计算两个特征向量之间的距离,评估两个特征向量之间的关联:距离越小,关联越大;距离越大,关联越小。
容易得出,mmdt_hash
+ k-NN = machine_learning,mmdt_hash
结合k-NN算法可作为某种机器学习应用。
k-NN核心思想:一个样本与数据集中的k个样本最相似,如果这k个样本中的大多数属于某一个类别,则该样本也属于这个类别。其中,通过距离来衡量相似度,距离越小,相似度越高;距离越大,相似度越低。而距离的度量,通常采用欧式距离。
k-NN算法流程如下:
关键点两个:
...
def
gen_knn_features(
self
):
data_list
=
[]
label_list
=
[]
# self.datas是已知特征库
for
data
in
self
.datas:
tmp
=
data.split(
':'
)
main_hash
=
tmp[
1
]
main_values
=
[]
# 将字符串类型的mmdt_hash转成单条特征向量
for
i
in
range
(
0
,
len
(main_hash),
2
):
main_values.append(
int
(main_hash[i:i
+
2
],
16
))
# 保存knn需要的特征向量及标签索引
data_list.append(main_values)
label_list.append(
int
(tmp[
2
]))
return
data_list, label_list
...
...
def
gen_knn_features(
self
):
data_list
=
[]
label_list
=
[]
# self.datas是已知特征库
for
data
in
self
.datas:
tmp
=
data.split(
':'
)
main_hash
=
tmp[
1
]
main_values
=
[]
# 将字符串类型的mmdt_hash转成单条特征向量
for
i
in
range
(
0
,
len
(main_hash),
2
):
main_values.append(
int
(main_hash[i:i
+
2
],
16
))
# 保存knn需要的特征向量及标签索引
data_list.append(main_values)
label_list.append(
int
(tmp[
2
]))
return
data_list, label_list
...
...
def
knn_classify(
self
, md, dlt):
# 将mmdt_hash转为特征向量
def
gen_knn_data(data):
tmp
=
data.split(
':'
)
main_hash
=
tmp[
1
]
main_values
=
[]
for
i
in
range
(
0
,
len
(main_hash),
2
):
main_values.append(
int
(main_hash[i:i
+
2
],
16
))
return
main_values
# 保存knn训练集和对应索引标签集
datas
=
self
.build_datas
labels
=
self
.build_labels
train_datas
=
np.array(datas)
t_data
=
gen_knn_data(md)
rowSize
=
train_datas.shape[
0
]
# 1.扩展未知特征标签维度,同时分别计算与knn特征向量集合的每个维度的差值,先平方求和再开方,即为欧式距离
diff
=
np.tile(t_data, (rowSize,
1
))
-
train_datas
sqr_diff
=
diff
*
*
2
sqr_diff_sum
=
sqr_diff.
sum
(axis
=
1
)
distances
=
sqr_diff_sum
*
*
0.5
# 2. 对距离排序
sort_distance
=
distances.argsort()
# 3. 使用最近一个邻居
matched
=
sort_distance[
0
]
# 4. 使用最近一个邻居的标签作为判定标签
label_index
=
labels[matched]
sim
=
1.0
-
distances[matched]
/
1020.0
# 5. 判定相似度是否满足指定条件
if
sim > dlt:
if
self
.labels:
label
=
self
.labels[label_index]
else
:
label
=
'match_%d'
%
label_index
return
sim, label
return
0.0
,
'unknown'
...
...
def
knn_classify(
self
, md, dlt):
# 将mmdt_hash转为特征向量
def
gen_knn_data(data):
tmp
=
data.split(
':'
)
main_hash
=
tmp[
1
]
main_values
=
[]
for
i
in
range
(
0
,
len
(main_hash),
2
):
main_values.append(
int
(main_hash[i:i
+
2
],
16
))
return
main_values
# 保存knn训练集和对应索引标签集
datas
=
self
.build_datas
labels
=
self
.build_labels
train_datas
=
np.array(datas)
t_data
=
gen_knn_data(md)
rowSize
=
train_datas.shape[
0
]
# 1.扩展未知特征标签维度,同时分别计算与knn特征向量集合的每个维度的差值,先平方求和再开方,即为欧式距离
diff
=
np.tile(t_data, (rowSize,
1
))
-
train_datas
sqr_diff
=
diff
*
*
2
sqr_diff_sum
=
sqr_diff.
sum
(axis
=
1
)
distances
=
sqr_diff_sum
*
*
0.5
# 2. 对距离排序