networkX构建图学习笔记

0.前言

本文章主要记录笔者在写毕业设计时的东西,便于以后回顾时能够快速明白自己当年写的是什么,同时也给予一些读者思路或灵感什么的。

因为笔者实力有限,可能内容会有部分错误或者有更好的方法却未使用,请不要多怪指责。

1.networkx

先来简单讲解一下networkx的构建图的一些基本用法

导库

1
import networkx as nx

无向图

创建空的图

1
G = nx.Graph()

添加节点

1
2
G.add_node('a')
G.add_node_from(['a','b'])

第一个添加的是一个一个的节点,节点可以是字符串也可以是数字。

第二个添加的是列表,即可以添加一个一个的节点,也可以将一个列表的节点添加进去。

如果想对节点添加一些属性,可以使用以下的方法(例子是添加用户名这个属性)

1
2
G.add_node('a',user_name='blue')
G.add_nodes_from([3], user_name='blue')

同样也可以对空的图添加属性

1
G=nx.Graph(day="Friday")

添加边

1
2
G.add_edge('a','b',user_name="blue")
G.add_edges_from([('a','b',{"user_name":"blue"})])

以上两种方法都是在a,b两个节点间建立一条边,后面的参数是添加边的属性。

第一种是一条边一条边的添加,第二种是可以一条一条或者一个列表地添加边。

查看节点属性

1
2
isCore = nx.get_node_attributes(G, 'user_name')
print(isCore['b'])

查看边属性

1
2
isCore = nx.get_edge_attributes(G,'user_name')
print(isCore)

给边添加权重

1
2
G.add_weighted_edges_from([('a','b',1)])
print(G.get_edge_data('a','b'))

其中get_edge_data()方法是用来查看边的属性的(权重的属性名为weight,如果添加了其他属性在里面,它会全部显示出来。)

其他的查看

1
2
3
print(G.number_of_edges())   #查看边的数量
print(G.nodes()) #查看G图的全部节点
print(G.edges()) #查看G图的全部边

其他一些函数

nx.degree(G)#计算图的密度,其值为边数m除以图中可能边数(即n(n-1)/2)

nx.degree_centrality(G)#节点度中心系数。通过节点的度表示节点在图中的重要性,默认情况下会进行归一化,其值表达为节点度d(u)除以n-1(其中n-1就是归一化使用的常量)。这里由于可能存在循环,所以该值可能大于1.

nx.closeness_centrality(G)#节点距离中心系数。通过距离来表示节点在图中的重要性,一般是指节点到其他节点的平均路径的倒数,这里还乘以了n-1。该值越大表示节点到其他节点的距离越近,即中心性越高。

nx.betweenness_centrality(G)#节点介数中心系数。在无向图中,该值表示为节点作占最短路径的个数除以((n-1)(n-2)/2);在有向图中,该值表达为节点作占最短路径个数除以((n-1)(n-2))。

nx.transitivity(G)#图或网络的传递性。即图或网络中,认识同一个节点的两个节点也可能认识双方,计算公式为3*图中三角形的个数/三元组个数(该三元组个数是有公共顶点的边对数,这样就好数了)。

nx.clustering(G)#图或网络中节点的聚类系数。计算公式为:节点u的两个邻居节点间的边数除以((d(u)(d(u)-1)/2)。

有向图

有向图的建立和添加跟无向图几乎一模一样,只要理解了什么是有向图和无向图,基本上这方面不成问题。唯一要注意的是有向图的建立跟无向图不一样,下面给出代码

1
G = nx.DiGraph()

画图

1
2
3
import matplotlib.pyplot as plt
nx.draw(G, pos=nx.circular_layout(G),with_labels=True)
plt.show()

2.通过数据生成无向图并添加权重

生成无向图和添加权重通过上面的介绍就可以实现了,唯一存在的问题是csv库的读取方法reader()存在无法重复循环的问题,例子如下

1
2
3
4
5
6
7
8
with open(filename, 'r', encoding='utf-8') as file:
next(file) #用于跳过第一行
fLine = csv.reader(file)
for i in fLine:
print("yes")
for j in fLine:
print("no")
file.close()

输出如下(假设除去第一行只有三行数据):

1
2
3
4
yes
no
no
no

之所以输出是这样,是因为这个reader()方法读取完文件的数据后就会自动关掉文件,导致无法进行第二次循环。

所以我们改用numpy库来提取数据

np库方法

1
2
3
with open(filename, 'r', encoding='utf-8') as file:
data2 = np.loadtxt(file, str, delimiter=",", skiprows=1) #参数为文件、支持str类型,以,为分隔符,跳过第一行
file.close()

PS:之所以不用python自带的readlines()等方法是因为提取出来的数据是字符串,要弄成列表形式还要进一步的处理,所以直接pass掉。

Graph Embedding学习笔记

前言

图是一个常见的数据结构,针对图的研究大致上可以分为以下三类

简单的图算法

这类算法研究简单的如生成树算法、最短路径算法发,复杂的如二分图匹配、费用流问题等等

概率图模型

这是将条件概率表达为图结构,并进一步挖掘,典型的有条件随机场等

概率图理论共分为三个部分,分别为概率图模型表示理论,概率图模型推理理论和概率图模型学习理论

基本的概率图模型包括贝叶斯网络、马尔可夫网络和隐马尔可夫网络。

基本的Graphical Model 可以大致分为两个类别:贝叶斯网络(Bayesian Network)和马尔可夫随机场(Markov Random Field),它们区别在于采用不同类型的图来表达变量之间的关系。【贝叶斯网络采用有向无环图(Directed Acyclic Graph)来表达因果关系,马尔可夫随机场则采用无向图(Undirected Graph)来表达变量间的相互作用】

图神经网络

这是用于研究图结构数据挖掘的问题,典型的有graph embedding,graph CNN等。

前言2

Embedding

什么是Embedding?

Embedding在数学上是一个函数,它是将一个高维抽象空间的点映射到低维的具体空间。因此它的意义就是将高维数据转换到低维利于算法进行处理,同时解决one-hot向量长度随样本的变化而变化,以及无法表示两个实体之间的相关性这一问题。(one-hot:独热编码,也叫一位有效码,主要采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效。one-hot编码是分类变量作为二进制向量的表示,它要求首先将分类值映射到整数值,然后每个整数值被表示为二进制向量,除了整数的索引外,它都是零值,它被标记为1)

最常见的embedding方法就是word2vec,根据语料库中单词的共现关系求出每个单词的embedding,常用的word2vec模型有cbowskip-gram两种。cbow根据山下问预测中心词,skip-gram根据中心词预测上下文。

Graph Embedding

Graph Embedding的中心思想是找到一种映射函数,该函数将网络中的每个节点转换为低维度的潜在表示

下面列表是graph embeding的几种常见分类

考虑网络结构 DeepWalk GraRep struc2vec
LINE node2vec GraphSAGE
考虑结构和其他信息 CENE CANE Trans-Net
DL GCN SDNE
GAN GraphGAN ANE

DeepWalk

DeepWalk 通过将节点视为单词并生成短随机游走作为句子来弥补网络嵌入和单词嵌入之间的差距,接着就可以通过将诸如Skip-gram 之类的神经语言模型应用于这些随机游走以获得网络嵌入。

它的优点是:

①按需生成随机游走

②可扩展的

③引入了深度学习图形的范例

下图展示了DeepWalk的过程

v2-6c548cc39af4400988d04ed1104bb3c2_r

​ DeepWalk的算法流程(引自阿里论文)

整个算法大致可以分为四步走

  1. 图a展示了原始的用户行为序列
  2. 图b基于这些用户行为序列构建了物品相关图,可以看出,物品A,B之间的边产生的原因就是因为用户U1先后购买了物品A和物品B,所以产生了一条由A到B的有向边。如果后续产生了多条相同的有向边,则有向边的权重被加强。在将所有用户行为序列都转换成物品相关图中的边之后,全局的物品相关图就建立起来了。
  3. 图c采用随机游走的方式随机选择起始点,重新产生物品序列。
  4. 图d最终将这些物品序列输入word2vec模型(也可以使用skip-gram模型),生成最终的物品Embedding向量。

以上步骤中核心的是第三步,其中唯一需要形式化定义的是随机游走的跳转概率,也就是到达节点vi后,下一步遍历vi的临接点vj的概率。如果物品的相关图是有向有权图,那么从节点vi跳转到节点vj的概率定义如下:

v2-c659f8c1dd22e4e646f4e454813cf9a2_1440w

其中N+(vi)是节点vi所有的出边集合,Mij是节点vi到节点vj边的权重。

如果物品相关图是无向无权重图,那么跳转概率将是上面公式的一个特例,即权重Mij将为常数1,且N+(vi)应是节点vi所有“边”的集合,而不是所有“出边”的集合。

随机游走的好处:

  • 并行化:随机游走是局部的,对于一个大的网络来说,可以同时在不同的顶点开始进行一定长度的随机游走,多个随机游走同时进行,可以减少采样的时间。
  • 适应性:可以适应网络局部的变化。网络的演化通常是局部的点和边的变化,这样的变化只会对部分随机游走路径产生影响,因此在网络的演化过程中不需要每一次都重新计算整个网络的随机游走。

Node2vec

理论

斯坦福大学在deepwalk的基础上更进一步,通过调整随机游走权重的方法使graph embedding的结果在网络的同质性结构性中进行权衡。

网络的同质性是指距离相近节点的embedding应该尽量相似,如下图所示,节点u与其相连的s1,s2,s3,s4的embedding表达是接近的,这就是同质性。

v2-147bb9aa6cb646c83680e93bcf016c4e_1440w

结构性是指结构上相似的节点的embedding应该尽量接近,如上图的s6和u两个节点都是各自局域网络的中心,从结构上来说,这就是结构上的相似,他们的embedding的表达也应该相似,而着就是结构性。

【看到大佬的一个直观解释:相同性的相似是指从u到s6的路径和从s2到s6的“距离”非常相近;而结构性相似是指节点u和节点s6的“地位作用”比较相似。换句话说,就是从北京去上海和从天津到上海的距离是非常相近的;而北上广深每天都有很多的飞机航班通往全国各地,但其他城市却没有这么多,所以北上广深的地位作用是非常相近的】

所以为了使Graph Embedding的结果能够表达网络的同质性,在随机游走的过程中,需要让游走的过程更倾向于DFS(深度优先搜索),因为对于两个距离比较近的节点,出现在相同上下文序列的几率比较高,因此近距离的节点容易学习出相似的embedding向量。

而对于BFS(宽度优先搜索)来说,对于两个结构性比较类似的节点,BFS构建两个节点在类似位置的上下文序列的概率更高,因此可以更好的学习到结构性;进一步假设,如果两个点有大量相同的邻居节点,那么w2v(word2vec)训练时,具有相同上下文的概率更高,embedding向量应该更接近;

而node2vec算法中,主要是通过节点间的跳转概率来控制BFS和DFS的倾向性的。

下图显示了node2vec算法从节点t跳转到节点v后,下一步从节点v跳转到周围个点的跳转概率

v2-20a6b345cfe45706b43db91a78ee5b69_1440w

其中p和q的定义论文作者给出的解释如下:

  • Return parameter pp:
    Return back to the previous node
  • In-out parameter qq:
    Moving outwards (DFS) vs. inwards (BFS)
    Intuitively, qq is the “ratio” of BFS vs. DFS

翻译一下就是p是返回参数,q是进出参数,q是BFS和DFS的比值

可能很多人看不懂这里说的是什么意思(实际上它的解释我也看得不是恒明白),下面来说明一下

当下一个节点x与前一个节点t和当前节点v等距时,$\alpha$=1; 当下一个节点xx是上一个节点时,$\alpha$=$\frac{1}{p}$;在其他情况下,α=$\frac{1}{q}$

从节点v跳转到下一个节点x的概率计算公式如下:

v2-61287731efe14d38a7084fa2f77ec3c1_1440w

其中$\omega_{vx}$是边vx的权重, $\alpha_{pq}(t,x)$的定义如下:

v2-481056c49b3619ff679fe10ee38c24c1_1440w

dtx指的是节点t到节点x的距离,参数p和q共同控制着随机游走的倾向性。p越小,随机游走回节点t的可能性越大,node2vec就更注重表达网络的同质性,q越小,则随机游走到远方节点的可能性越大,node2vec更注重表达网络的结构性,反之,当前节点更可能在附近节点游走。

代码解读与学习

安装库

node2vec需要用到gensim库

安装gensim库前需要安装numpy和scipy两个库

安装gensim库建议使用这个镜像源,其他的基本都会出现该死的爆红现象

1
pip install -i https://pypi.mirrors.ustc.edu.cn/simple gensim

最后在安装node2vec库就好了

代码使用学习

导库

1
2
3
import networkx as nx
import gensim
from node2vec import Node2Vec

这里需要用到三个库,第一个是生成图用的networkx库,第二个是用于自然语言的gensim库,第三个是node2vec算法所用的库

建图

1
G = nx.fast_gnp_random_graph(n=100, p=0.5)

我们先利用fast_gnp_random_graph()生成一个随机图,这个函数的用法在下面有解释

1
2
nx.fast_gnp_random_graph(n, p, seed=None, directed=False
#这里的n为节点数,p为边创建的概率,seed为随机数生成的种子(默认为无),directed为有向图,默认为False,如果是True则返回的是有向图

node2vec应用

1
node2vec = Node2Vec(G, dimensions=64, walk_length=30, num_walks=200, workers=1)

这行代码用于预计算概率并生成行走,其中按照学习文章的作者所说的,该方法如果在windows上运行的话建议workers=1

下图是Node2Vec()的总体流程图

2019050520411066

其中它的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def __init__(self, graph, dimensions=128, walk_length=80, num_walks=10, p=1, q=1, weight_key='weight', workers=1, sampling_strategy=None, quiet=False, temp_folder=None):

self.graph = graph
self.dimensions = dimensions
self.walk_length = walk_length
self.num_walks = num_walks
self.p = p
self.q = q
self.weight_key = weight_key
self.workers = workers
self.quiet = quiet
self.d_graph = defaultdict(dict)

if sampling_strategy is None:
self.sampling_strategy = {}
else:
self.sampling_strategy = sampling_strategy

self.temp_folder, self.require = None, None
if temp_folder:
if not os.path.isdir(temp_folder):
raise NotADirectoryError("temp_folder does not exist or is not a directory. ({})".format(temp_folder))

self.temp_folder = temp_folder
self.require = "sharedmem"

self._precompute_probabilities()
self.walks = self._generate_walks()

通过这个代码我们可以了解到它的输入参数:

  1. graph: 第1个位置的参数必须是 networkx 图。节点名必须都是整数或都是字符串。在输出模型上,它们始终是字符串。
  2. dimensions: 嵌入维度(默认值:128)
  3. walk_length: 每个路径的节点数(默认值:80)
  4. num_walks: 经过每个节点的次数(默认值:10)
  5. p: 返回超参数(默认值:1)# p 和 q 是决定采用DFS或者BFS的关键参数
  6. q: 输入输出参数(默认值:1)
  7. weight_key: 在加权图上,这是 权重属性的关键字(默认值:“weight”)。
  8. workers: 并行执行的工作者数目(默认值:1)
  9. sampling_strategy: 特定节点的采样策略, 支持设置节点特定的“q”、“p”、“num_walks”和“walk_length” 参数。请准确地使用这些关键字。如果未设置,将默认为对象初始化时传递的全局参数。
  10. quiet: 控制布尔值长度。(默认值:false)
  11. temp_folder: 指向文件夹的字符串路径,用于保存图形的共享内存副本 - 在算法执行过程中处理过大而无法放入内存的图时提供。
1
2
3
model = node2vec.fit(window=10, min_count=2, batch_words=1)
model.save('node2vec_test.model') # 保存训练好的模型到当前文件夹
new_model = gensim.models.Word2Vec.load('node2vec_test.model') # 调用模型

下面的node2vec.fit()的源码:

1
2
3
4
5
6
7
8
9
def fit(self, **skip_gram_params):

if 'workers' not in skip_gram_params:
skip_gram_params['workers'] = self.workers

if 'size' not in skip_gram_params:
skip_gram_params['size'] = self.dimensions

return gensim.models.Word2Vec(self.walks, **skip_gram_params)

学习笔记

web安全之机器学习入门学习笔记

机器学习概述(第三章)

基本概念

有监督学习

对具有概念标记(分类)的训练样本进行学习,因为这里的概念标记样本是已知的,所以训练样本的歧义性低。对这些训练集样本继续学习,通过对训练集样本以外的数据进行标记预测,就叫有监督学习(即有一个标准进行对比)

无监督学习

跟有监督学习相反,对没有概念标记(分类)的训练样本进行学习,以便发现训练样本集中的结构性知识。这里的训练样本的歧义性高,因为标记的都是未知的。

聚类是典型的无监督学习。

准确率与召回率

召回率和准确率是两个最基本的指标(在信息检索、分类、识别、翻译等领域里),召回率也叫查全率,准确率也叫查准率。

用二分问题来解释,一个实例实际是真的,且预测时也是真的,就叫真正类(TP),若预测时为假的,则为假负类(FN)。若实际是假的,而预测为真的,则叫假正类(FP),若预测为假,则为真负类(TN)

所以召回率可以表示为【TP/(TP+FN)】,而准确率可以表示为【TP/(TP+FP)】

各种数据集

KDD99数据

这是1999年举办的KDD竞赛时采用的数据集。原本是1998年美国国防部高级研究计划局在MIT林肯实验室进行的入侵检测项目的数据,后来哥伦比亚大学的Sal Stolfo教授和来自北卡罗莱纳州立大学的Wenke Lee教授采用数据挖掘技术对以上数据集进行特征分析和数据预处理,行程了一个新的数据集,于是就成了著名的KDD99数据集。

HTTP DATASET CSIC 2010

这是一个包含大量标注过的针对Web服务的36000歌正常请求以及25000个攻击请求,攻击类型包括sql注入、缓冲区溢出、信息泄露、文件包含、xss等被广泛用于WAF类产品的功能评测。

SEA数据集

简单地说就是一个被广泛用于内部伪装者威胁检测研究的数据集,是Schonlau等人公开的。

ADFA-LD数据集

澳大利亚国防学院对外发布的一套主机级入侵检测系统的数据集合,被广泛应用于入侵检测类产品的测试。数据集包括Linux和Windows。

Alexa域名数据

Alexa是一家专门发布网站世界排名的网站,这个数据是根据用户下载并安装了Alexa Tools Bar嵌入到IE、FireFox等浏览器,从而监控其访问的网站数据进行统计的,因此数据不具有绝对的权威性。但数据提供了包括综合排名、到访问量排名、页面访问量排名等多个评价指标信息,且尚没有而且也很难有更科学、合理的评价参考。

PS:他的数据只是提供全球排名TOP一百万的网站域名的下载,文件格式是CSV

Scikit-Learn数据集

这个数据集里面最常用的是iris数据集,这是一个存储了鸢尾属植物的萼片和花瓣的长宽数据。

MNIST数据集

一个入门的计算机视觉数据集,包含各种手写数字图片

Movie Review Data

包含1000条正面评论和1000负面评论的数据,被广泛应用于文本分类。

SpamBase数据集

入门级的垃圾邮件分类训练集

Ps:已经经过特征化的数据,对应的特征是统计的关键字以及特殊符号的词频,一共58个属性

Enron数据集

该公司已经破产(太惨了吧)

一般用于不同文件夹盆正常邮件和垃圾邮件

特征提取

数字型特征提取

数据型特征可以直接作为特征,但是对于一个多为的特征,某一个特征的取值范围特别大,很可能导致其他特征对结果的影响被忽略,这时候我们需要对数字型特征进行预处理

标准化
1
2
3
4
5
6
7
from sklearn import preprocessing
import numpy as np
X = np.array([[1., -1., 2.],
[2., 0., 0.,],
[0., 1., -1.]])
X_scaled = preprocessing.scale(X) #规范化,使用格式放在下面
print(X_scaled)
1
sklearn.preprocessing.scale(X, axis=0, with_mean=True, with_std=True, copy=True)

沿着某个轴标准化数据集,以均值为中心,以分量为单位方差。

参数 数据类型 意义
X {array-like, sparse matrix} 以此数据为中心缩放
axis int (0 by default) 沿着计算均值和标准差的轴。如果是0,独立的标准化每个特征,如果是1则标准化每个样本(即行)
with_mean boolean, True by default 如果是True,缩放之前先中心化数据
with_std boolean, True by default 如果是True,以单位方差法缩放数据(或者等价地,单位标准差)
copy boolean, optional, default True False:原地执行行标准化并避免复制(如果输入已经是一个numpy数组或者scipy.sparse CSC矩阵以及axis是1)

输出结果

1
2
3
[[0.  ..., -1.22..., 1.33...],
[1.22..., 0. ..., -0.26...],
[1.22..., 1.22..., -1.06...]]
正则化
1
2
3
4
5
X = [[1., -1., 2.],
[2., 0., 0.,],
[0., 1., -1.]]
X_normalized = preprocessing.normalize(X, norm='12')
print(X_normalized)
1
x_norm=np.linalg.norm(x, ord=None, axis=None, keepdims=False)

(1)x: 表示矩阵

(2)ord:范数的类型。可赋值1,2,none。默认情况下,求2范数,即平方之和再开方。

(3)axis:行向量处理或列向量处理。

axis=1表示按行向量处理,求多个行向量的范数

axis=0表示按列向量处理,求多个列向量的范数

axis=None表示矩阵范数。

(4)keepding:是否保持矩阵的二维特性

True表示保持矩阵的二维特性,False相反

输出结果

1
2
3
[[0.40..., -0.40..., 0.81...],
[1. ..., 0. ..., 0. ...],
[0. ..., 0.70..., -0.70...]]
归一化
1
2
3
4
5
6
X_train = np.array([[1., -1., 2.],
[2., 0., 0.,],
[0., 1., -1.]])
min_max_scaler = perprocessing.MinMaxScaler()
X_train_minmax = min_max_scaler.fit_transform(X_train)
print(X_train_minmax)

输出结果

1
2
3
[[0.5     , 0.     , 1.      ],
[1. , 0.5 , 0.33333333],
[0. , 1. , 0. ]]

文本型特征提取

本质上就是对单词做切分,不同的单词当作一个新的特征。

一本进行文本型特征提取有两个非常重要的模型

一个是词集模型,即单词构成的集合,集合中每个元素都只有一个,换言之词集中的每个单词都只有一个

另一个是词袋模型,即一个单词在该文档中出现的次数不止一次,那么就统计其出现的次数(频数)。

这两个模型本质上并没有什么区别,只是词袋在词集的基础上增加了频率的维度:词集只关注有和没有,词袋还要关注有几个。

K近邻算法(第五章)

k近邻算法的核心思想是:距离接近的事物具有相同属性的可能性要大于距离相对较远的。

KNN

knn的核心思想:如果一个样本在特征空间中的K个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上的样本的特性。

常用算法:

Brute Force

K-D Tree

Ball Tree

决策树和随机森林算法(第六章)

决策树表现了对象属性与对象值之间的一种映射关系

随机森林算法可以看成是一个加强版的决策树,他是用多个决策树组成一个森林,每个决策树之间没有任何的关联。在输入一个样本的时候,它会经过每一个决策树,看看哪个样本应该属于哪个分类或者哪个选项被选择的最多。

朴素贝叶斯算法(第七章)

朴素贝叶斯算法是基于贝叶斯定理与特征条件独立假设的分类方法。

通常包括以下算法:

高斯朴素贝叶斯

多项式朴素贝叶斯

伯努利朴素贝叶斯

逻辑回归算法(第八章)

逻辑回归也叫回归分析,他是通过描述自变量X和因变量Y之间的关系而从对因变量Y进行预测的(也可以说是自变量X对因变量Y的影响程度)。

自变量如果只有一个,我们就叫一元回归分析,如果有多个,就叫多元回归分析。

支持向量机算法(第九章)

简单地说就是在桌面上有一堆红蓝两色的小球,然后通过一条线把红蓝分开,让一边只有红色另一边只有蓝色。如果在二维上无法划分就上升到三维去划分,以此类推。

升维需要依靠核函数,SVM通过一个非线性映射,把样本空间映射到一个高纬乃至无穷维的特征空间中,是的在原来的样本空间中非线性可分问题转化为在特征空间中的线性可分问题。(就是升维和线性化)

所谓的升维,就是把样本向高纬空间做映射,一般情况下这种处理方法会增加计算的复杂性,甚至会引起“维数灾难”(维数灾难就是高维的数据过于复杂,导致分析和组织高维空间(通常有成百上千维)中的数据,因体积指数增加而遇到各种问题场景,它有一个特点:当维度增加时,空间的体积增加得很快,使得可用的数据变得稀疏)

于是,一个矛盾就出来了,升维会导致计算复杂,数据变得稀疏,而不升维,会因为处于低维而导致样本空间无法线性处理(有些样本可以在高维空间通过一个线性超平面实现线性划分或者回归)。然而SVM却巧妙地化解了这个矛盾:应用和函数的展开定理,就不需要知道非线性映射的显式表达式。由于是在高维特征空间中建立线性学习机,所以与线性模型相比,可以避免维数灾难的发生以及高维的计算复杂性的增加。

常用的核函数有以下几种:

线性核函数:K(x,y) = x*y

多项式核函数: K(x,y) = [(x*y)+1]^d

径向基函数: K(x,y) = exp(-|x-y|^2/d^2)

二层神经网络核函数:K(x,y) = tanh(a(x*y)+b)

PS:tanh为双曲正切

使用方法

导入库

1
2
3
import numpy as np
import matplotlib.pyplot as ply
from sklearn import svm

创建40个随机点

1
2
3
4
5
6
np.random.seed(0)
X = np.r_[np.random.randn(20, 2) - [2, 2], np.random.randn(20, 2) + [2, 2]]
Y = [0] * 20 + [1] * 20
#符合模型
clf = svm.SVC(kernel='linear')
clf.fit(X,Y)

构建超平面

1
2
3
4
5
6
7
8
9
w = clf.coef_[0]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - (clf.intercept_[0]) / w[1]
#绘制平行线到通过支撑的分离超平面
b = clf.support_vectors_[0]
yy_down = a * xx + (b[1] - a * b[0])
b = clf.support_vectors_[-1]
yy_up = a * xx + (b[1] - a * b[0])

调用matplotlib画图

1
2
3
4
5
6
7
plt.plot(xx, yy, 'k-')
plt.plot(xx, yy_down, 'k--')
plt.plot(xx, yy_up, 'k--')
plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=80, facecolors='none')
plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=cpl.cm.Paired)
plt.axis('tight')
plt.show()

K-Means与DBSCAN算法(第十章)

K-Means算法

中心思想:以空间中k个点为中心进行聚类,通过迭代的方法,组词更新各聚类中心的值,直至得到最好的聚类结果

基础使用方法

导库
1
2
3
4
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import K-Means
from sklearn.datasets import make_blobs
生成测试样本
1
2
3
n_samples = 1500
random_state = 170
X, Y = make_blobs(n_samples=n_samples, random_state=random_state)
进行聚类,指定聚类个数为3
1
Y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(X)
可视化结果
1
2
3
4
plt.subplot(221)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.title("hello word!")
plt.show()

DBSCAN算法

跟K-means不同,如果说前者是指定划分多少个聚类的话,那么这个就是只规定一个聚类里面有多少个东西,没有规定要划分多少个聚类。

它主要是将簇定义为密度相连的点的最大集合,能够把具有足够高密度的区域划分为簇,并课在噪声的空间数据库中发现任意形状的聚类。

基本用法

核心函数
1
2
3
4
5
6
7
DBSACN(eps=0.5,
min_samples=5,
metric='euclidean',
algorithm='auto',
leaf_size=30,
p=None,
n_jobs=1)

主要参数如下:

esp【同一聚类集合中两个样本的最大距离】

min_samples【同一聚类集合中最小样本数】

algorithm【算法,分为‘auto’,‘ball_tree’, ‘kd_tree’, ‘brute’】

leaf_size【使用Ball Tree或者cKDTree算法时叶子节点个数】

n_jobs【并发任务数】

导库
1
2
3
4
5
6
import numpy as np
from sklearn.cluster import DBSCAN
from sklearn import metrics
from sklearn.datasets.samples_generator import make_blobs
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
创建测试样本
1
2
3
centers = [[1, 1], [-1, -1], [1, -1]]
X, labels_true = make_blobs(n_samples=750, centers=centers, cluster_std=0.4, random_state=0)
X = StandardScaler().fit_transform(X)
运行算法,esp设计为0.3,最小样本数为10
1
2
3
4
db = DBSCAN(eso=0.3, min_samples=10).fit(X)
core_samples_mask = np.zeros_like(db.labels_, dtype=bool)
core_samples_mask[db.core_sample_indices_] = True
labels = db.labels_
设置可视化需要的数据
1
2
3
4
5
6
7
8
9
colors = plt.cm.Spectral(np.linspace(0, 1, len(unique_labels)))
for k , col in zip(unique_labels, colors):
if k == -1:
col = 'k'
class_member_mask = (labels == k)
xy = X[class_member_mask & core_samples_mask]
plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=col, markeredgecolor='k',
markersize=14)
xy = X[class_member_mask & ~core_samples_mask]
可视化展开
1
2
3
plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=col,
markeredecolor='k', markersize=6)
plt.show()

Apriori与FP-growth算法(第十一章)

Apriori算法

这是一个关联算法

它有三个基本概念:支持度、置信度、频繁K项集

Apriori算法是同时满足最小支持度阈值和最小置信度阈值的关联规则。使用频繁项集的先验知识,使用‘逐层搜索’的迭代方法。

支持度

既有A又有B的概率,它表现的是A和B两个时间相对整个数据集合同时发生的频繁程度。

置信度

在A发生的事件中同时发生B的概率P(AB)/p(A)

频繁K项集

满足最小支持度阈值的时间就称为频繁K项集

FP-growth算法

这是基于Apriori构建的算法,但采用了高级的数据结构减少了扫描次数,大大加快了算法速度。

它只需要对数据库进行两次扫描,而Apriori算法则是对于每个潜在的频繁项集都会扫描数据集判定给定模式是否频繁。

基本过程:

构建FP树

从FP树中挖掘频繁项集

隐式马尔可夫算法(第十二章)

一个连续的时间序列时间,他的状态由且仅由它前面的N歌时间决定,对应的事件序列可以成为N阶马尔可夫链。

神经网络(深度学习)

神经网络由输入层、隐藏层、输出层组成。

如果隐藏层只有一个,那么这个就是最简单的单层神经网络。如果隐藏层有多个,那就是多层感知机。

而深度学习就是多层感知机。

狭义的多层感知机要求必须是全连接的(所谓的全连接,就是每个隐藏层的任何一个节点,都与下一层隐藏层的全部节点连接)

常见的深度学习包括:

深度神经网络(DNN)

卷积神经网络(CNN)

循环神经网络(RNN)

Tensorflow编程模型

Tensor叫张量,即所谓的N维数组

Flow叫流,所谓基于数据流图的计算

所以Tensorflow为张量从流图的一段流动到另一端的计算过程。它将复杂的数据结构传输到人工智能神经网中进行分析和处理。

它有着四个基本组件:操作、张量、变量和会话

操作

把算法表示成一个个操作的叠加,可以清晰地看到数据之间地关系。

当数据流过操作节点的时候就可以对数据进行操作,一个操作可以有零个或多个输入,产生零个或多个输出。

张量

在计算图中,每个边就代表数据从一个操作流到另一个操作。这些数据就被表示为张量,一个张量可以看成多维的数组或者高维的矩阵

需要注意的是张量本身并没有保存任何值,仅仅提供了范文数值的一个借口,可以看成数值的一种引用。

变量

变量是计算图中可以改变的节点。

会话

在Tensorflow中所有的操作都必须在会话中执行,会话负责分配和管理各种资源。

学习笔记2

机器学习互联网业务安全实践

互联网业务安全简述(第一章)

现状

业务安全事件有着以下的特点:

效率高、范围广

高度产业链化

危害严重,社会影响较大

如何应对挑战

1.对互联网业务安全预警信息实施监控【这是进行互联网业务安全防护的先决条件】

2.提升业务安全防护技术【这是互联网业务安全防护的基石】

3.培养业务安全相关的专业技术人员【这是业务安全防护的核心】

机器学习入门(第二章)

相似性

范数

范数(norm)是一个函数,主要用于度量向量或者向量空间的大小和长度。

在泛函分析与计算数学中,它都扮演着特别重要的角色【比如在数值代数、研究数值方法的收敛性、稳定性及误差分析问题】。

例如在赋范性空间中,范数的定义需要满足三个条件:①非负性②齐次性③三角不等式

向量范数

定义:若V是数域P以上的线性空间,而且对于V的任一向量x,若实值函数||·||:$\R^n$→R满足如下条件:

(1)∀x∈$\R^n$,||X||≥0;如果x=0,则||x||=0

(2)∀$\alpha$∈R,x∈R,有||$\alpha$x||=|$\alpha$|||x||

(3)∀x,y∈$\R^n$,||x+y||≤||x||+||y||

则称||·||为向量范数,其中$\R^n$表示n维向量空间。

向量范数是对向量大小的一种度量,可以形象地理解为向量的长度

以下是几个有代表性的n阶向量范数

1.L1=|x1|+|x2|+……

这里的L1表示向量x各元素的绝对值之和

2.L2=$\sqrt{x_1^2+x_2^2+……}$​

L2表示欧氏空间中的点到原点的距离,也叫欧式范数或者弗罗贝尼乌斯范数

3.Lp=($(|x_1|^p+|x_2|^p+……)^\frac{1}{p}$

通过1、2、3可以看出L1和L2以及Lp是相同的形式。

4.L∞=lim( $\sum{(|p_i-q_i|^k)^\frac{1}{k}}$

L∞表示向量x的元素中绝对值的最大值,称为无穷范数,也是一致范数(可以理解为Lp意义下的范数的极限)

PS:可以这样理解,在三维空间里,如果p是∞的时候,它会表示成一个正方体;如果p为2,则是一个球;p=1时为一个锥形;o<p<1时为一个类似陀螺的形状;p=0时为一条线

2-1

矩阵范数

定义:设A为mXn矩阵,$||·||\alpha$是$R^m$上的向量范数,$||·|| \beta$是$R^n$上的向量范数,则定义矩阵范数为:

||A||=max||x|| $\beta$=1||Ax||$ \alpha$

矩阵范数具有与向量范数相似的性质,区别在于向量范数的性质包含在定义的条件中,而矩阵范数由于包含了向量范数的定义,因此它有如下的性质:

(1)||Ax||$\alpha$≤||A||·||X||$\beta$

(2)||$\lambda$A||=|$\lambda$|·||A||

(3)||A+B||≤||A||+||B||

(4)||AD||≤||A||·||D||

其中,A、B为mXn矩阵,D是nXp矩阵,$\lambda$为实数,X∈$R^n$

同样的,下面列出几个有代表性的n阶矩阵范数:

(1)||A1=maxj $\sum_{i=1}^m{|a_{ij}|}$,称为列范数

(2)||A||2= $\sqrt{\lambda A^HA}$,$\lambda A^H$A表示$A^H$A的绝对值的最大特征值,||A||2又称为谱范数

(3)||A||=maxi$\sum_{j=1}^n{|a_{ij}|}$,称为行范数

其中A=(aij)mxn

模型(第三章)

账户业务安全(第六章)

账户安全保障

对于用户来说,账户安全涉及用户个人隐私信息的安全、用户体验以及资金安全等方面

对于平台来说,账号安全涉及广告投放、流量购买、营销活动以及战略决策等方面

横向来看,账户安全主要从两个环节来保障,一个是账户注册环节,另一个是账户登录环节

纵向来看,维护账户安全的手段主要有网络层防护、数据层防护以及业务层防护,相应的手段有WAF、设备指纹、验证码、生物探针、数字证书、安全SDK等

这些防护手段从技术原理来看,可以分成两大类,一类是加密/解密,即判断账户的请求是否被篡改;第二类是人机识别,即甄别账户的请求是来自人来时来自机器的操作。

注册环节

一般来说,注册环节是账户安全的第一入口

因为互联网公司需要保证独立访客量(UV)的增长,所以会通过各种运营活动来吸引新用户(拉新)。这些运营活动最常见的就是注册新用户返回红包这类有返利的活动,而许多有心人士会通过建立虚假账户将这些返利取走。

一般来说,黑灰产是通过一下三种方式进行注册账号的

1.机器注册:通过软件自动化大批量进行注册,这种手段主要涉及三个方面:账号注册软件、打码和解码平台以及IP地址切换器。

2.半人工注册:通过软件加人工手动操作的方式,来提升人工注册的效率,相当于使用软件来辅助人工注册。

3.人工注册:通过大量兼职人员手动注册账号,这种方式效率最低,但安全性最高。

注册方式 效率 安全性
机器注册
半人工注册
人工注册

应对方法:

1.梳理各个注册渠道的入口,加强对注册数据的监控,如果某个注册渠道的数据波动较大,就说明可能存在问题

2.留存好日志数据,将其作为数据分析的依据,依靠大数据技术来识别垃圾账号注册的蛛丝马迹

3.在注册过程中采取安全防护措施,如验证码、语音验证、短信上行验证等

4.监控外部黑灰产的数据

登录环节

登录环节进行业务安全防控的方法大体可以分为三类:

1.基础安全技术:常见的基础安全技术手段有数字证书、安全控件、虚拟机和模拟器检测、数据加密/解密等

2.人机识别技术:主要依托于生物探针技术来实现(通过登录环节收集到的数据【包括但不限于基础网络数据、用户操作数据等】来分析当前行为是否是机器人的行为)

3.安全验证技术:常见的手段主要有验证码(数字、图形、计算题等各种形式)、滑块、短信上行/下行验证等。

PS:所谓的上行和下行就是你发和你收的意思

聚类算法在账户安全中的应用

特征主体的聚集性是业务安全中最常利用的特性之一。

比如:同一个IP地址注册大量的账号,或者同一台设备注册大量的账号,这两种行为都可以归结为在单一维度下存在高度聚集性,从业务安全的角度可以认为该聚集性是有问题的。

K-Means算法

这是一个非常基础的聚类算法,其时间复杂度与数据规模线性相关,计算量小,适用于大规模的数据。

如何让这些点(指的是平面上距离相近的点)自主归类?书本给了一个例子:

假设现在有K个类别,将每个点与这些类别的代表(比如中心点)做相似度判断,相似度较高的点被归为一类。

那么如何进行相似度判断

在自然语言处理中可以使用TF-IDF(Term Frequency-Inverse Document Frequency)作为点的表示,使用余弦值作为衡量相似度的指标,或者直接使用欧氏距离作为衡量相似度的指标。

对于不同的数据,假设空间和维度可能需要选择不同的衡量指标,甚至可以使用信息论中的互信息(Mutual Information,MI)、信息距离交换(Variation of Information Distance)、KL散度(Kullback-Leibler divergence)等作为相似度的衡量指标。

于是问题又来了,如何选择同一个类别的代表方式*****?**

理论上来说,这些点的中心点通常就是聚类的中心。选择中心点的方式也有多种,最基本的方式是使用点集向量的均值作为中心点,这些中心点也就是聚类的中心。不过这样的聚类中心并不一定是存在的数据或者有意义的数据。

除此之外,我们还可以使用几何中心(如果有凸包快速计算几何中心的方法的话),或者使用最靠近聚类中心的有意义的点(这样做是为了让中心点不再是凭空产生多余的数据),这样处理出来的聚类中心就是真是存在的。

K-Means算法基础步骤

1.在原始数据中初始化K个聚类中心

2.分别计算每个对象与这K个聚类中心的距离,并根据每个对象与聚类中心的最短距离为相应对象重新划分类别

3.重新计算每个聚类的中心

4.计算标准测度函数。当满足一定条件,如函数收敛时,算法终止;如果不满足条件则返回步骤3

K-Means算法的时间复杂度时O(nkt),其中n为数据量,k为选取得聚类中心得个数,t是迭代得次数。

它是一种无监督学习方法,以k为参数,把n个对象分为k簇,使得簇内具有较高的相似度,而簇间的相似度则较低。一般以簇的中心为聚类中心,也叫质心。它也是一种典型的逐点迭代动态聚类的算法,所有对象元素按照某一规则聚到某一类后,最终会重新计算类的中心。

K-Means的一个主要问题是聚类的稳固性。由于迭代次序、中心点、距离函数等都有多种不同的选择,所以歌词迭代产生的聚类中心往往会有偏差。为了增加K-Means的稳固性,前人也做了很多尝试,如将各聚类中心之间的距离最大化,采用更能反应模型假设空间距离意义的测度函数(兰德系数、杰卡德相似系数、海明距离、最小匹配距离、互信息)

高斯混合模型(GMM)

这是一种应用很广泛的算法。它不仅能在给定聚类数时计算出样本点的类别,还能计算出每个类别下的样本分布。

高斯混合模型作为期望最大化(简称EM)算法的一种特例,有助于理解EM算法。

D维高斯分布

N(X|$\mu$,$\Sigma$)=$\frac{1}{(2Π)^2}$$\frac{1}{|\Sigma|^\frac{1}{2}}$exp{-$\frac{1}{2}$(x-$\mu$)T $\Sigma$-1(x-$\mu$)}

其中,$\mu$是D维的均值向量,$\Sigma$是DXD的协方差矩阵,|$\Sigma$|则表示$\Sigma$的行列式

所以高斯混合模型可以表示为以下这个式子:

P(x)=$ \sum_{k=1}^k$$Π_k$N(x|$\mu$k,$\Sigma_k$)

高斯混合模型的物理意义:空间种的样本点(向量)以不同的概率隶属于多个高斯分布。

假设Z是K维空间向量,且Z中的元素只有1个为1,其他的皆为0,这样Z就有K个状态了,而且Z中的元素满足$\Sigma_k$$Z_k$=1,那么$Z_k$表示任意样本点属于第k个高斯分布的概率,Z也可以看作是高斯混合模型的隐变量。

因此在计算样本点的后验概率时,需要先确定Z,再确定样本点在该高斯模型中的概率,即P(x,Z)由边缘分布P(Z)和条件分布P(x|Z)相乘而得。P(Z)的边缘概率为高斯模型中的混合系数$Πk$,即p($Z_k$=1)=$Π_k$,易知0≤$Π_k$,$ \sum{k=1}^k$$Πk$=1,所以也可以写成P(Z)=$\prod{k=1}^{k}$$Π_k^{Zk}$

所以高斯混合模型的分部也可以写成这样:

P(X)=$\sum_{Z}$P(Z)P(X|Z)=$\prod_{k=1}^{k}$N(X|$\mu_k$, $\Sigma_k$)

其中,每一个$X_n$的观测值都有一个对应的隐变量$Z_n$

OPTICS算法和DBSCAN算法

OPTICS算法

OPTICS算法是一种基于密度的聚类算法,目标是将空间中的数据安扎哦密度愤怒不进行聚类,跟DBSCAN算法背后的思想十分类似。

但不同的是,OPTICS算法可以获得不同密度的聚类,换句话说就是我们可以通过这个算法获得任意密度的聚类(原因是OPTICS算法输出的样本是一个有序队列的样本,从这个队列中可以获得任意密度的聚类)

OPTICS算法的输入参数比较简单,包括半径$\varepsilon$和最少点树MinPts。在这两个参数的基础上,我们可以定义算法中的一些核心概念。

1.核心点:如果一个点的半径为$\varepsilon$,领域内包含的点的数量不少于最少点书,则该点为核心点,其数学描述如下:

$N_\varepsilon$(P)≥MinPts

2.核心距离:在核心点的定义基础上可以引出核心距离的定义:对于核心点,距离其第$MinPts_{th}$d近的点与其之间的距离。

数学描述为:

coreDist(P)=$\begin{cases}UNDEFINED,,,ifN(P)≤MinPts\MinPts_{th}Distance in N(P),,,else\\end{cases}$

3.可达距离:对于核心点P,O到P的科大距离定义为O到P的距离或者P的核心距离

数学描述如下:

reachDist(O,P)=$\begin{cases}UNDEFINED,,,if N(P)≤MinPts\max(coreDist(p), dist(O,P)),,,else\\end{cases}$

4.直接密度可达:如果P为核心点,且P到O的距离小于半径,那么O到P就是直接密度可达的

OPTICS算法的难点在于维护核心点的直接密度可达点的有序列表

以下是算法中计算有序列表的过程

输入:数据样本$\Omega$,给定半径$\varepsilon$和最小点数MinPts。

初始化:所有点的可达距离和核心距离初始化为MAX

步骤

(1)建立两个队列:有序队列列(核心点及该核心点的直接密度可达点)和结果队列(存储输出的样本及处理次序)

(2)如果D中数据全部处理完,则算法结束;否则,从D中选择一个未处理且为核心点对象的点,将该核心点放入结果队列,将该核心点的直接密度可达点放入有序队列,并将这些直接密度可达点按可达距离升序排列

(3)如果有序队列为空,则回到步骤2,否则从有序队列中取出第一个点,如果该店不再结果队列中,则将该点存入结果队列,然后:

①判断该点是否为核心点,若不是则回到步骤3;如果是的话,则进行下一步

②找到该核心点的所有直接密度可达点,将这些点放入有序队列,并且将有序队列中的点按照可达距离重新排序。如果该点已经在有序队列中且新的可达距离较短,则更新该点的可达距离。

(4)重复步骤3,直到有序队列为空

(5)算法结束

输出结果:给定半径$\varepsilon$和最少点MinPts时,输出核心点的直接idu可达点的有序列表。

OPTICS算法中计算样本最终类别的过程

对给定的结果队列,执行以下操作:

(1)从结果队列中按顺序去除样本点,如果该点的可达距离不大于给定半径$\varepsilon$,则该点属于当前类别,否则执行步骤(2)

(2)如果该点的核心距离大于给定半径$\varepsilon$,则该点为噪声点,可以忽略;否则,该点属于新的聚类,跳至步骤1

(3)若已经遍历完结果队列,则算法结束。

DBSCAN算法

这个算法属于OPTICS算法中的一种特殊情况,OPTICS算法主要是解决了DBSCAN算法对输入参数敏感的问题。

DBSCAN算法跟OPTICS算法差不多,不同的在于DBSCAN算法中有样本被分为直接密度可达和密度可达这两种情况

1.直接(密度)可达:如果P为核心点,那么其周围半径$\varepsilon$的领域内的点都是从P直接(密度)可达的。

2.(密度)可达:对于点Q,如果存在$p_1$,$p_2$,……,$p_n$且$p_1$=$p_2$,……,$p_{n-1}$=$p_n$,$p_n$=Q,即$p_1$到$p_n$都是直接(密度)可达的,那么Q对于$p_1$(密度)可达。

3.噪声:如果一个点对于其他所有点都不可达,那么这个点就是噪声,也可以称为异常点。

DBSCAN算法

输入:数据样本集D,给定半径$\varepsilon$和最少点书MinPts

初始化:将所有点设置为未访问

步骤

(1)建立neighbor队列

(2)如果D中数据已全部处理完,则算法结束;否则从D中选择一个未处理的点,标记为已访问,获得其所有直接密度可达点。如果这个点为非核心点,则标记为噪声,重复步骤2,直到获得核心点,生成新的类别,进入步骤3

(3)将当前核心点放入该类别,将其直接密度可达点放入neighbor队列,并遍历该队列,如果neighbor队列全部遍历完则回到步骤2

①如果该点已经访问过,则进入步骤2,否则将其标志为已访问,然后计算获得该点的所有密度可达点,如果这个点也为核心点,则将该点的所有直接密度可达点放入neighbor队列

②如果该点不属于任何类别,则放入当前类别

(4)算法结束

输出结果:给定半径$\varepsilon$和最少点数MinPts时,数据样本集D的聚类结果

数据处理或提取特征笔记

0.前言

本文章主要记录笔者在写毕业设计时的东西,便于以后回顾时能够快速明白自己当年写的是什么,同时也给予一些读者思路或灵感什么的。

因为笔者实力有限,可能内容会有部分错误或者有更好的方法却未使用,请不要多怪指责。

1.数据生成

因为本次毕设所需要做的作品是人工智能方面的东西,需要用到大量的数据去跑。但是经过笔者一个星期的查询(查询了360实验室、微软的研究院、阿里和腾讯的研究地方)都没找到适用的信息,最后只能自己生成数据

因为需要的是垃圾账号的数据,也就是一个账号的用户名、注册ip、注册邮箱等等,所以直接上github找了个工具一键生成。

2.数据写入

为了方便后续的操作和整理,我将数据写入到csv文件中

写入csv的核心方法就是writerow()这个方法

这个方法会按照你输入的参数的数量,一行写入多少个参数,每个参数之间会以,间隔

1
2
3
4
5
6
with open(filename, 'w',newline="") as csvfile:
writer = csv.writer(csvfile)
writer.writerow(["index", "user_name", "user_email", "user_ip", "user_phone"])
for i in range(num):
writer.writerow([i+1, user(), email(), ip(), phone()])
csvfile.close()

3.数据处理

3.1user_name

对于用户名的处理,我是按照《机器学习互联网业务安全实践》一书里面的处理方法进行处理的。

我们先构建两个池,一个是数字池,一个是字母池

1
2
numPool = u'0123456789'
strPool = u'abcdefghijklmnopqrstuvwxyz'

将传入的用户名(就是字符串)移除字符串头尾的空格或换行符,然后再将字符串的大写字母全部转换为小写字母

1
element = inputFileName.strip().lower()

之后就是利用for循环对每一个字符(数字)进行统计。

返回的内容是一个类似字典一样的东西。这里看对输出的要求做调整。

1
2
3
4
5
6
7
8
9
for c in element:
if c in numPool:
i_num += 1
elif c in strPool:
i_cha += 1
else:
i_other += 1
pattern = getPattern(i_num, i_cha, i_other)
#num:{0},char:{1},zhongwen:{2},sum:{3},num&char:{4},pattern:{5}

代码中的getPattern()是用来统计字数的,如果存在一个数字或者一个字母,就返回1,都存在就返回2,以此类推。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if i_num and i_cha and i_other:
return 0
elif i_num and i_cha:
return 1
elif i_num and i_other:
return 2
elif i_cha and i_other:
return 3
elif i_num:
return 4
elif i_cha:
return 5
else:
return 6

3.2user_ip

ip的处理也比较简单。

因为我们需要比对的是两个用户注册是不是同一个ip地址段,所以我们需要提取ip的前三个段。

1
ip1 = re.search(r'((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){2}', Filename)

正则理解:

我们直接用正则匹配就好了。

3.3user_email

email的处理是提取它的后缀名

依旧使用正则匹配

1
a = re.search(r'@([-\w]{1,63}\.)*[-\w]{1,63}', filename)

正则理解:

@([-\w]{1,63}.):匹配从@开始到.号(第一个)结束的任意字符

*[-\w]{1,63}:匹配前面的子表达式零次或多次

然后除去@符号就好了

1
2
3
b = list(a.group())
b.pop(0)
b = ''.join(b)

3.4写入新的文件

将上述处理好的数据重新写入一个新的csv文件里

1
2
3
4
5
6
7
with open(filename2, 'w', newline="")as file2:
writer = csv.writer(file2)
writer.writerow(['index', 'user_name', 'user_email', 'user_ip', 'user_phone'])
next(fLine)
for i in fLine:
writer.writerow([i[0], generateNameFeatureFromFile(i[1]), getemailfeature(i[2]), getipfeature(i[3]), i[4]])
file2.close()

关于某手游的拆包

关于某手游的拆包

前言

前段时间想弄live2d,看完别人提供的模型都感觉一般般,不是很好。后来在玩手游时想起该游戏有live2d的皮肤,要不弄个下来玩玩,于是就有了这次这篇文章

(本文方法所提取的东西仅用于学习研究,不用于任何商业用途)

(本人提取立绘仅出于学习目的,不用做商业用途)

Read More