每个程序员都应该知道的 40 个算法(二)
原文:
zh.annas-archive.org/md5/8ddea683d78e7bd756401ec665273969
译者:飞龙
第五章:图算法
有一类计算问题最好以图的术语来表示。这类问题可以使用一类称为图算法的算法来解决。例如,图算法可以用于在数据的图形表示中高效搜索值。为了高效工作,这些算法首先需要发现图的结构。它们还需要找到正确的策略来跟随图的边以读取顶点中存储的数据。由于图算法需要搜索值才能工作,因此高效的搜索策略是设计高效图算法的核心。使用图算法是在复杂的相互关联的数据结构中搜索信息的最有效方式之一。在当今的大数据、社交媒体和分布式数据时代,这些技术变得越来越重要和有用。
在本章中,我们将首先介绍图算法背后的基本概念。然后,我们将介绍网络分析理论的基础知识。接下来,我们将看看可以用来遍历图的各种技术。最后,我们将看一个案例研究,展示图算法如何用于欺诈检测。
在本章中,我们将介绍以下概念:
-
表示图的不同方式
-
引入网络理论分析
-
理解图的遍历
-
案例研究:欺诈分析
-
在我们的问题空间中建立邻域的技术
在本章结束时,您将对图是什么以及如何使用它们来表示相互关联的数据结构并从直接或间接关系的实体中挖掘信息有很好的理解,以及如何使用它们来解决一些复杂的现实世界问题。
图的表示
图是一种以顶点和边的形式表示数据的结构。图表示为aGraph
= (𝓥, 𝓔),其中𝓥表示一组顶点,𝓔表示一组边。注意aGraph
有|𝓥|个顶点和|𝓔|条边。
一个顶点,𝓋 ∈ 𝓥,表示现实世界的对象,如人、计算机或活动。一条边,𝓋 ∈ 𝓔,连接网络中的两个顶点:
e(𝓋[1], 𝓋[2]) | e ∈ 𝓔 & 𝓋[i] ∈ 𝓥
前面的方程表明,在图中,所有边属于一个集合𝓔,所有顶点属于一个集合𝓥。
一条边连接两个顶点,因此代表它们之间的关系。例如,它可以代表以下关系:
-
人与人之间的友谊
-
一个人在 LinkedIn 上连接了一个朋友
-
一个集群中两个节点的物理连接
-
一个人参加研究会议
在本章中,我们将使用networkx
Python 包来表示图。让我们尝试使用 Python 中的networtx
包创建一个简单的图。首先,让我们尝试创建一个空图aGraph
,没有顶点或节点:
import networkx as nx
G = nx.Graph()
让我们添加一个单个顶点:
G.add_node("Mike")
我们还可以使用列表添加一堆顶点:
G.add_nodes_from(["Amine", "Wassim", "Nick"])
我们还可以在现有的顶点之间添加一条边,如下所示:
G.add_edge("Mike", "Amine")
现在让我们打印边和顶点:
请注意,如果我们添加一条边,这也会导致添加相关的顶点,如果它们尚不存在,如下所示:
G.add_edge("Amine","Imran")
如果我们打印节点列表,我们将看到以下输出:
请注意,对已经存在的顶点进行添加的请求会被静默忽略。请求的忽略或接受取决于我们创建的图的类型。
图的类型
图可以分为四种类型,即以下四种:
-
无向图
-
有向图
-
无向多重图
-
有向多重图
现在让我们逐个详细查看每一个。
无向图
在大多数情况下,图的组成节点之间表示的关系可以被认为是无方向的。这种关系不对关系施加任何顺序。这样的边被称为无向边,结果图被称为无向图。以下是一个无向图的示例:
一些无向关系的例子如下:
-
迈克和阿敏(迈克和阿敏互相认识)。
-
节点 A 和节点 B 相连(这是一种点对点的连接)。
有向图
图中节点之间的关系具有某种方向感的图被称为有向图。以下是一个有向图的示例:
一些有向关系的例子如下:
-
迈克和他的房子(迈克住在一所房子里,但他的房子不住在迈克里)。
-
约翰管理保罗(约翰是保罗的经理)。
无向多重图
有时,节点之间有多种关系。在这种情况下,可以有多条边连接相同的两个节点。这种图称为多重图,在同一节点上允许多条*行边。我们必须明确指出一个特定的图是否是多重图。*行边可以表示节点之间的不同类型的关系。
以下图显示了一个多重图:
多向关系的一个例子是迈克和约翰既是同学又是同事。
有向多重图
如果多重图中的节点之间存在方向关系,则称为有向多重图:
有向多重图的一个例子是迈克在办公室向约翰汇报,并且约翰教迈克 Python 编程语言。
特殊类型的边
边将图的各个顶点连接在一起,并表示它们之间的关系。除了简单的边,它们还可以是以下特殊类型:
-
自边:有时,特定的顶点可以与自己有关系。例如,约翰把钱从他的商业账户转到他的个人账户。这种特殊关系可以用自导向边来表示。
-
超边:有时,多个顶点由同一条边连接。连接多个顶点以表示这种关系的边被称为超边。例如,假设迈克、约翰和莎拉三人一起参与一个特定项目。
具有一个或多个超边的图被称为超图。
这里显示了自边和超边图的图示:
请注意,一个特定的图可以有多种特殊类型的边节点。这意味着一个特定的图可以同时具有自边和超边。
自我中心网络
特定顶点m的直接邻域可能包含足够重要的信息,以进行对节点的决定性分析。自我中心,或者称为 egonet,就是基于这个想法的。特定顶点m的 egonet 包括所有直接连接到m的顶点以及节点m本身。节点m被称为自我,与之连接的一跳邻居被称为替代者。
特定节点 3 的自我网络在以下图中显示:
请注意,egonet 代表一度邻域。这个概念可以扩展到 n 度邻域,包括所有 n 跳离感兴趣的顶点的顶点。
社交网络分析
社交网络分析(SNA)是图论的重要应用之一。如果满足以下条件,网络图分析被认为是社交网络分析:
-
图的顶点代表人。
-
它们之间的边代表着它们之间的社会关系,如友谊、共同爱好、血缘关系、性关系、厌恶等等。
-
我们通过图分析试图回答的商业问题具有很强的社会方面。
人类行为在 SNA 中得到反映,并且在进行 SNA 时应始终牢记。通过在图中绘制人际关系,SNA 可以深入了解人际互动,这有助于我们理解他们的行为。
通过在每个个体周围创建邻域,并根据其社会关系分析个体的行为,您可以产生有趣的,有时令人惊讶的见解。基于个体的个人工作职能对个体进行分析的替代方法只能提供有限的见解。
因此,SNA 可以用于以下方面:
-
理解用户在社交媒体*台上的行为,如 Facebook、Twitter 或 LinkedIn
-
理解欺诈
-
理解社会的犯罪行为
LinkedIn 在 SNA 相关的新技术的研究和开发方面做出了很大贡献。事实上,LinkedIn 可以被认为是该领域许多算法的先驱。
因此,由于社交网络的固有分布和相互连接的架构,SNA 是图论最强大的用例之一。另一种抽象图的方法是将其视为网络,并应用设计用于网络的算法。这整个领域被称为网络分析理论,我们将在下面讨论。
介绍网络分析理论
我们知道,互连的数据可以表示为网络。在网络分析理论中,我们研究了开发用于探索和分析表示为网络的数据的方法的细节。让我们在本节中看一些网络分析理论的重要方面。
首先,注意网络中的一个顶点充当基本单元。网络是一个由顶点相互连接而成的网络,其中每个连接代表着调查对象之间的关系。在解决问题的背景下,量化网络中顶点的有用性和重要性是很重要的。有各种技术可以帮助我们量化重要性。
让我们看一些网络分析理论中使用的重要概念。
理解最短路径
路径是起始节点和结束节点之间的节点序列,路径上没有节点出现两次。路径代表了所选起始和结束顶点之间的路线。它将是一组连接起始顶点和结束顶点的顶点p。在p中没有重复的顶点。
路径的长度是通过计算组成边来计算的。在所有选项中,具有最小长度的路径称为最短路径。最短路径的计算在图论算法中被广泛使用,但并不总是直接计算。有不同的算法可以用来找到起始节点和结束节点之间的最短路径。其中一个最流行的算法是Dijkstra 算法,它在 20 世纪 50 年代末出版。它可以计算图中的最短路径。它可以被全球定位系统(GPS)设备用来计算源和目的地之间的最小距离。Dijkstra 算法也用于网络路由算法。
谷歌和苹果之间存在一场争夺,他们要设计出最佳的谷歌地图和苹果地图的最短距离算法。他们面临的挑战是使算法足够快,可以在几秒内计算出最短路径。
在本章后面,我们将讨论广度优先搜索(BFS)算法,它可以修改为迪杰斯特拉算法。BFS 假设在给定图中遍历每条路径的成本相同。对于迪杰斯特拉算法,遍历图的成本可能不同,需要将其纳入修改 BFS 为迪杰斯特拉算法。
正如所示,迪杰斯特拉算法是一种计算最短路径的单源算法。如果我们想解决所有最短路径对,那么可以使用弗洛伊德-沃舍尔算法。
创建邻域
为了图算法的关键节点周围创建邻域的策略至关重要。创建邻域的方法基于选择与感兴趣的顶点直接关联的方法。创建邻域的一种方法是选择一个k阶策略,该策略选择与感兴趣的顶点相距k跳的顶点。
让我们看看创建邻域的各种标准。
三角形
在图论中,找到彼此连接良好的顶点对于分析很重要。一种技术是尝试识别三角形,在网络中,三角形是由三个直接相连的节点组成的子图。
让我们看看欺诈检测的用例,我们在本章末尾也将其用作案例研究。如果节点m的 egonet 包括三个顶点,包括顶点m,那么这个 egonet 就是一个三角形。顶点m将是 ego,而两个连接的顶点将是 alter,比如顶点A和顶点B。如果两个 alter 都是已知的欺诈案例,我们可以安全地宣布顶点m也是欺诈的。如果其中一个 alter 涉及欺诈,我们无法得出结论性证据,但我们需要进一步调查欺诈证据。
密度
让我们首先定义一个完全连接的网络。我们称每个顶点直接连接到每个其他顶点的图为完全连接的网络。
如果我们有一个完全连接的网络N,那么网络中的边数可以表示如下:
现在,这就是密度发挥作用的地方。密度测量观察到的边的数量与最大边数的比值,如果Edges****[Observed]是我们想要观察的边的数量。它可以表述如下:
请注意,对于三角形,网络的密度为1
,这代表了最高可能的连接网络。
理解中心性度量
有不同的度量方法来理解图或子图中特定顶点的中心性。例如,它们可以量化社交网络中一个人的重要性,或者城市中建筑物的重要性。
以下中心性度量在图分析中被广泛使用:
-
度
-
介数
-
紧密度
-
特征向量
让我们详细讨论它们。
度
顶点连接的边的数量称为其度。它可以指示特定顶点的连接情况以及其在网络中快速传播消息的能力。
让我们考虑aGraph
= (𝓥, 𝓔),其中𝓥表示顶点集合,𝓔表示边集合。回想一下,aGraph
有|𝓥|个顶点和|𝓔|条边。如果我们将节点的度除以(|𝓥|-1),则称为度中心性:
现在,让我们看一个具体的例子。考虑以下图:
现在,在上述图中,顶点 C 的度为 4。其度中心性可以计算如下:
介数
介数是图中的中心性度量。在社交媒体的背景下,它将量化一个人在子群中参与通信的概率。对于计算机网络,介数将量化在顶点故障的情况下对图节点之间通信的负面影响。
要计算aGraph
中顶点a的介数,按照以下步骤进行:
-
计算
aGraph
中每对顶点之间的最短路径。让我们用来表示这一点。
-
从
,计算通过顶点a的最短路径数量。让我们用
来表示这一点。
-
使用
来计算介数。
公*和亲*
让我们拿一个图g。图g中顶点a的公*性被定义为顶点a到其他顶点的距离之和。请注意,特定顶点的中心性量化了它与所有其他顶点的总距离。
公*性的对立面是亲*度。
特征向量中心性
特征向量中心性给出了图中所有顶点的分数,衡量它们在网络中的重要性。该分数将是特定节点与整个网络中其他重要节点的连接性的指标。当谷歌创建了PageRank 算法时,该算法为互联网上的每个网页分配一个分数(以表达其重要性),这个想法就是源自特征向量中心性度量。
使用 Python 计算中心性度量
让我们创建一个网络,然后尝试计算其中心性度量。以下代码块说明了这一点:
import networkx as nx
import matplotlib.pyplot as plt
vertices = range(1,10)
edges = [(7,2), (2,3), (7,4), (4,5), (7,3), (7,5), (1,6),(1,7),(2,8),(2,9)]
G = nx.Graph()
G.add_nodes_from(vertices)
G.add_edges_from(edges)
nx.draw(G, with_labels=True,node_color='y',node_size=800)
这段代码生成的图如下所示:
到目前为止,我们已经研究了不同的中心性度量。让我们为前面的例子计算这些度量:
请注意,中心性的度量应该给出图或子图中特定顶点的中心性度量。从图中看,标记为 7 的顶点似乎具有最中心的位置。顶点 7 在中心性的四个度量中具有最高值,因此反映了它在这个上下文中的重要性。
现在让我们看看如何从图中检索信息。图是复杂的数据结构,存储了大量的信息,既在顶点中又在边中。让我们看一些可以用来有效地遍历图以从中收集信息以回答查询的策略。
理解图遍历
要利用图,需要从中挖掘信息。图遍历被定义为用于确保以有序方式访问每个顶点和边的策略。努力确保每个顶点和边都被访问一次,不多不少。广义上讲,可以有两种不同的遍历图的方式来搜索其中的数据。按广度进行称为广度优先搜索(BFS),按深度进行称为深度优先搜索(DFS)。让我们依次看一下它们。
广度优先搜索
当我们处理aGraph
时,如果存在层次或邻域级别的概念,BFS 效果最好。例如,当 LinkedIn 中一个人的联系被表示为图时,有一级联系,然后有二级联系,这直接对应于层次。
BFS 算法从根顶点开始,探索邻居顶点,然后移动到下一个邻居级别并重复这个过程。
让我们看一个 BFS 算法。为此,让我们首先考虑以下无向图:
让我们从计算每个顶点的直接邻居开始,并将其存储在一个称为邻接表的列表中。在 Python 中,我们可以使用字典数据结构来存储它:
graph={ 'Amin' : {'Wasim', 'Nick', 'Mike'},
'Wasim' : {'Imran', 'Amin'},
'Imran' : {'Wasim','Faras'},
'Faras' : {'Imran'},
'Mike' : {'Amin'},
'Nick' : {'Amin'}}
为了在 Python 中实现它,我们按照以下步骤进行。
我们将首先解释初始化,然后是主循环。
初始化
我们将使用两种数据结构:
-
visited
:包含所有已经被访问的顶点。最初,它将是空的。 -
queue
:包含我们希望在下一次迭代中访问的所有顶点。
主循环
接下来,我们将实现主循环。它将一直循环,直到队列中没有一个元素。对于队列中的每个节点,如果它已经被访问过,那么它就会访问它的邻居。
我们可以在 Python 中实现这个主循环,如下所示:
- 首先,我们从队列中弹出第一个节点,并将其选择为此次迭代的当前节点。
node = queue.pop(0)
- 然后,我们检查节点是否不在已访问列表中。如果不在,我们将其添加到已访问节点的列表中,并使用邻居来表示其直接连接的节点
visited.append(node)
neighbours = graph[node]
- 现在我们将节点的邻居添加到队列中:
for neighbour in neighbours:
queue.append(neighbour)
-
主循环完成后,将返回包含所有遍历节点的
visited
数据结构。 -
完整的代码,包括初始化和主循环,如下所示:
让我们来看看使用 BFS 定义的图的详尽搜索遍历模式。为了访问所有节点,遍历模式如下图所示。可以观察到,在执行过程中,它始终保持两种数据结构:
-
已访问:包含所有已经被访问的节点
-
队列:包含尚未被访问的节点
算法的工作原理如下:
-
它从第一个节点开始,也就是第一级上唯一的节点 Amin。
-
然后,它移动到第二级,并依次访问所有三个节点 Wasim、Nick 和 Mike。
-
然后,它移动到第三级和第四级,每个级别只有一个节点,Imran 和 Faras。
一旦所有节点都被访问,它们将被添加到已访问的数据结构中,迭代就会停止:
现在,让我们尝试使用 BFS 从这个图中找到特定的人。让我们指定我们正在搜索的数据,并观察结果:
现在让我们来看看深度优先搜索算法。
深度优先搜索
DFS 是 BFS 的替代方法,用于从图中搜索数据。将 DFS 与 BFS 区分开的因素是,在从根顶点开始后,算法会逐个沿着每条唯一的路径尽可能深入。对于每条路径,一旦成功到达最终深度,它就会标记所有与该路径相关的顶点为已访问。完成路径后,算法会回溯。如果它能找到另一条从根节点开始但尚未被访问的路径,算法会重复之前的过程。算法会在新分支中不断移动,直到所有分支都被访问。
请注意,图可能具有循环方法。如前所述,我们使用布尔标志来跟踪已处理的顶点,以避免在循环中迭代。
为了实现 DFS,我们将使用一个栈数据结构,这在第二章中已经详细讨论过,算法中使用的数据结构。请记住,栈是基于后进先出(LIFO)原则的。这与队列相反,队列用于 BFS,它基于先进先出(FIFO)原则。
以下代码用于 DFS:
def dfs(graph, start, visited=None):
if visited is None:
visited = set()
visited.add(start)
print(start)
for next in graph[start] - visited:
dfs(graph, next, visited)
return visited
让我们再次使用以下代码来测试先前定义的dfs
函数:
graph={ 'Amin' : {'Wasim', 'Nick', 'Mike'},
'Wasim' : {'Imran', 'Amin'},
'Imran' : {'Wasim','Faras'},
'Faras' : {'Imran'},
'Mike' :{'Amin'},
'Nick' :{'Amin'}}
如果我们运行这个算法,输出将如下所示:
让我们使用 DFS 方法来查看这个图的详尽遍历模式:
-
迭代从顶部节点 Amin 开始。
-
然后,它移动到第二级,Wasim。从那里,它向下一级移动,直到达到末端,即 Imran 和 Fares 节点。
-
完成第一个完整分支后,它回溯然后到达第二级访问 Nick 和 Mike。
遍历模式如下图所示:
请注意,DFS 也可以用于树。
现在,让我们看一个案例研究,解释了本章迄今为止讨论的概念如何用于解决现实世界的问题。
案例研究 - 欺诈分析
让我们看看如何使用 SNA 来检测欺诈。人类是社会动物,人的行为据说受到周围的人的影响。同质性一词被创造出来代表他们的社交网络对一个人的影响。扩展这个概念,同质网络是一群人,他们由于某些共同因素而可能与彼此关联;例如,具有相同的起源或爱好,是同一个团伙或同一个大学的一部分,或其他因素的组合。
如果我们想在同质网络中分析欺诈,我们可以利用调查对象与网络中其他人之间的关系,这些人已经仔细计算了他们参与欺诈的风险。有时因为某人的公司而标记一个人也被称为因陋就寡。
为了理解这个过程,让我们首先看一个简单的案例。为此,让我们使用一个具有九个顶点和八条边的网络。在这个网络中,有四个顶点是已知的欺诈案例,并被分类为fraud (F)。剩下的五个人中有五个没有欺诈相关历史,被分类为non-fraud (NF)。
我们将编写以下步骤的代码来生成这个图表:
- 让我们导入我们需要的包:
import networkx as nx
import matplotlib.pyplot as plt
- 定义
vertices
和edges
的数据结构:
vertices = range(1,10)
edges= [(7,2), (2,3), (7,4), (4,5), (7,3), (7,5), (1,6),(1,7),(2,8),(2,9)]
- 让我们首先实例化图表:
G = nx.Graph()
- 现在,让我们绘制图表:
G.add_nodes_from(vertices)
G.add_edges_from(edges)
pos=nx.spring_layout(G)
- 让我们定义 NF 节点:
nx.draw_networkx_nodes( G,pos,
nodelist=[1,4,3,8,9],
with_labels=True,
node_color='g',
node_size=1300)
- 现在,让我们创建已知涉及欺诈的节点:
nx.draw_networkx_nodes(G,pos,
nodelist=[2,5,6,7],
with_labels=True,
node_color='r',
node_size=1300)
- 让我们为节点创建标签:
nx.draw_networkx_edges(G,pos,edges,width=3,alpha=0.5,edge_color='b') labels={} labels[1]=r'1 NF' labels[2]=r'2 F' labels[3]=r'3 NF' labels[4]=r'4 NF' labels[5]=r'5 F' labels[6]=r'6 F' labels[7]=r'7 F' labels[8]=r'8 NF' labels[9]=r'9 NF'
nx.draw_networkx_labels(G,pos,labels,font_size=16)
一旦前面的代码运行,它将显示出一个这样的图:
请注意,我们已经进行了详细的分析,将每个节点分类为图或非图。假设我们在网络中添加另一个名为q的顶点,如下图所示。我们对这个人没有先前的信息,也不知道这个人是否涉及欺诈。我们希望根据他们与社交网络中现有成员的联系来将这个人分类为NF或F:
我们已经设计了两种方法来对代表节点q的新人进行分类,分为F或NF:
-
使用一种不使用中心性指标和有关欺诈类型的附加信息的简单方法
-
使用了一个名为“瞭望塔”的方法,这是一种先进的技术,利用了现有节点的中心性指标,以及有关欺诈类型的其他信息
我们将详细讨论每种方法。
进行简单的欺诈分析
欺诈分析的简单技术是基于这样一个假设:在一个网络中,一个人的行为受到他们所连接的人的影响。在一个网络中,如果两个顶点与彼此相关联,那么它们更有可能具有相似的行为。
基于这一假设,我们设计了一种简单的技术。如果我们想找到某个节点a属于F的概率,概率表示为P(F/q),计算如下:
让我们将这应用到前面的图中,其中Neighborhood[n]代表顶点n的邻域,w(n, nj)代表n和n**j之间连接的权重。此外,degree[q]是节点q的度。然后,概率计算如下:
根据这个分析,这个人涉及欺诈的可能性为 67%。我们需要设定一个阈值。如果阈值为 30%,那么这个人就高于阈值,我们可以安全地标记他们为 F。
请注意,这个过程需要针对网络中的每个新节点重复进行。
现在,让我们看一种进行欺诈分析的高级方法。
介绍了瞭望塔欺诈分析方法
之前的简单欺诈分析技术有以下两个限制:
-
它不评估社交网络中每个顶点的重要性。与涉及欺诈的中心的联系可能与与一个远离的孤立个人的关系有不同的含义。
-
当在现有网络中将某人标记为已知的欺诈案例时,我们不考虑犯罪的严重程度。
瞭望塔欺诈分析方法解决了这两个限制。首先,让我们看一些概念。
评分负面结果
如果一个人已知涉及欺诈,我们说与这个人相关联的是一个负面结果。并非每个负面结果的严重程度或严肃程度都相同。一个已知冒充另一个人的人将会有一个更严重类型的负面结果与他们相关联,而不仅仅是试图以创新的方式使用过期的 20 美元礼品卡使其有效的人。
从 1 到 10 的评分中,我们对各种负面结果进行如下评分:
负面结果 | 负面结果分数 |
---|---|
冒充 | 10 |
涉及信用卡盗窃 | 8 |
假支票提交 | 7 |
犯罪记录 | 6 |
无记录 | 0 |
请注意,这些分数将基于我们对欺诈案例及其在历史数据中的影响的分析。
怀疑程度
怀疑程度(DOS)量化了我们对一个人可能涉及欺诈的程度。DOS 值为 0 意味着这是一个低风险的人,DOS 值为 9 意味着这是一个高风险的人。
对历史数据的分析显示,专业的欺诈者在他们的社交网络中拥有重要的地位。为了纳入这一点,首先我们计算网络中每个顶点的四个中心度指标。然后我们取这些顶点的*均值。这反映了该特定人在网络中的重要性。
如果与一个顶点相关联的人涉及欺诈,我们将使用前面表格中显示的预先确定的值对这个人进行评分,以反映犯罪的严重程度。
最后,我们将中心度指标的*均值和负面结果分数相乘,得到 DOS 的值。我们通过将其除以网络中 DOS 的最大值来标准化 DOS。
现在,让我们计算前一个网络中每个九个节点的 DOS:
节点 1 | 节点 2 | 节点 3 | 节点 4 | 节点 5 | 节点 6 | 节点 7 | 节点 8 | 节点 9 | |
---|---|---|---|---|---|---|---|---|---|
中心度度 | 0.25 | 0.5 | 0.25 | 0.25 | 0.25 | 0.13 | 0.63 | 0.13 | 0.13 |
中介中心度 | 0.25 | 0.47 | 0 | 0 | 0 | 0 | 0.71 | 0 | 0 |
接*中心度 | 0.5 | 0.61 | 0.53 | 0.47 | 0.47 | 0.34 | 0.72 | 0.4 | 0.4 |
特征向量 | 0.24 | 0.45 | 0.36 | 0.32 | 0.32 | 0.08 | 0.59 | 0.16 | 0.16 |
中心度指标的*均值 | 0.31 | 0.51 | 0.29 | 0.26 | 0.26 | 0.14 | 0.66 | 0.17 | 0.17 |
负面结果分数 | 0 | 6 | 0 | 0 | 7 | 8 | 10 | 0 | 0 |
DOS | 0 | 3 | 0 | 0 | 1.82 | 1.1 | 6.625 | 0 | 0 |
标准化 DOS | 0 | 0.47 | 0 | 0 | 0.27 | 0.17 | 1 | 0 | 0 |
下图显示了每个节点及其标准化 DOS:
为了计算已添加的新节点的 DOS,我们将使用以下公式:
使用相关数值,我们将按如下计算 DOS:
这将指示与系统中添加的新节点相关的欺诈风险。这意味着在 0 到 1 的范围内,这个人的 DOS 值为 0.42。我们可以为 DOS 创建不同的风险区间,如下所示:
DOS 的值 | 风险分类 |
---|---|
DOS = 0 | 无风险 |
0<DOS<=0.10 | 低风险 |
0.10<DOS<=0.3 | 中等风险 |
DOS>0.3 | 高风险 |
根据这些标准,可以看出新个体是高风险人员,应该被标记。
通常,在进行这种分析时不涉及时间维度。但现在,有一些先进的技术可以在图的增长随时间推移时进行分析。这使研究人员能够观察网络演化时顶点之间的关系。尽管图的时间序列分析会使问题的复杂性增加许多倍,但它可能会提供对欺诈证据的额外见解,否则是不可能的。
总结
在本章中,我们了解了基于图的算法。经过本章的学习,我希望我们能够使用不同的技术来表示、搜索和处理以图形表示的数据。我们还开发了能够计算两个顶点之间的最短距离并在问题空间中构建邻域的技能。这些知识应该帮助我们使用图论来解决诸如欺诈检测之类的问题。
在下一章中,我们将专注于不同的无监督机器学习算法。本章讨论的许多用例技术与无监督学习算法相辅相成,这将在下一章中详细讨论。在数据集中找到欺诈证据就是这样的用例示例。
第二部分:机器学习算法
本节详细解释了不同类型的机器学习算法,如无监督机器学习算法和传统监督学习算法,并介绍了自然语言处理算法。本节以介绍推荐引擎结束。包括在本节中的章节有:
-
第六章,无监督机器学习算法
-
第七章,传统监督学习算法
-
第八章,神经网络算法
-
第九章,自然语言处理算法
-
第十章,推荐引擎
第六章:无监督机器学习算法
本章是关于无监督机器学习算法的。本章以介绍无监督学习技术开始。然后,我们将学习两种聚类算法:k 均值聚类和层次聚类算法。接下来的部分将介绍一种降维算法,当我们有大量输入变量时可能会很有效。接下来的部分展示了无监督学习如何用于异常检测。最后,我们将看看最强大的无监督学习技术之一,关联规则挖掘。本节还解释了从关联规则挖掘中发现的模式如何代表跨交易中各种数据元素之间的有趣关系,这可以帮助我们进行基于数据的决策。
在本章结束时,读者应该能够理解无监督学习如何用于解决一些现实世界的问题。读者将了解目前用于无监督学习的基本算法和方法论。
在本章中,我们将涵盖以下主题:
-
无监督学习
-
聚类算法
-
降维
-
异常检测算法
-
关联规则挖掘
介绍无监督学习
无监督学习的最简单定义是,它是通过发现和利用数据的固有模式来为非结构化数据提供某种结构的过程。如果数据不是由某种随机过程产生的,它在其多维问题空间中的数据元素之间将具有一些模式。无监督学习算法通过发现这些模式并利用它们来为数据集提供一些结构。这个概念在下图中显示:
请注意,无监督学习通过发现现有模式的新特征来添加结构。
数据挖掘生命周期中的无监督学习
理解无监督学习的作用,首先要看数据挖掘过程的整体生命周期。有不同的方法论将数据挖掘过程的生命周期划分为不同的独立阶段,称为阶段。目前,有两种流行的表示数据挖掘生命周期的方式:
-
CRISP-DM(跨行业标准数据挖掘过程)生命周期
-
SEMMA(样本、探索、修改、建模、访问)数据挖掘过程
CRISP-DM 是由一些数据挖掘者联合开发的,他们来自包括克莱斯勒和SPSS(社会科学统计软件包)在内的各种公司。SEMMA 是由SAS(统计分析系统)提出的。让我们看看这两种数据挖掘生命周期的表示之一,CRISP-DM,并尝试理解无监督学习在数据挖掘生命周期中的位置。请注意,SEMMA 在其生命周期内有一些类似的阶段。
如果我们看 CRISP-DM 生命周期,可以看到它包括六个不同的阶段,如下图所示:
让我们逐个了解每个阶段:
- 阶段 1:业务理解:这是收集需求的阶段,涉及从业务角度深入全面地理解问题。根据机器学习(ML)的要求定义问题的范围,并适当地重新表述它是这个阶段的重要部分。例如,对于二元分类问题,有时将需求用可以证明或拒绝的假设来表述是有帮助的。本阶段还涉及记录将在下游阶段 4 中训练的机器学习模型的期望。例如,对于分类问题,我们需要记录可以部署到生产中的模型的最低可接受准确性。
CRISP-DM 生命周期的第一阶段是业务理解,重点是需要做什么,而不是如何做。
-
第二阶段:数据理解:这是关于理解可用于数据挖掘的数据。在这个阶段,我们将找出是否有适合解决问题的正确数据集。在确定数据集之后,我们需要了解数据的质量和结构。我们需要找出可以从数据中提取的模式,这些模式可能会引导我们获得重要的见解。我们还将尝试找到可以根据第一阶段收集的要求用作标签(或目标变量)的正确特征。无监督学习算法可以在实现第二阶段目标方面发挥强大作用。无监督算法可以用于以下目的:
-
在数据集中发现模式
-
通过分析发现的模式来理解数据集的结构
-
识别或推导目标变量
-
第三阶段:数据准备:这是为我们将在第四阶段训练的 ML 模型准备数据的阶段。可用的标记数据被分成两个不相等的部分。较大的部分称为训练数据,用于在第四阶段训练模型。较小的部分称为测试数据,在第五阶段用于模型评估。在这个阶段,无监督机器学习算法可以用作准备数据的工具,例如,它们可以用于将非结构化数据转换为结构化数据,提供可以帮助训练模型的额外维度。
-
第四阶段:建模:这是我们使用监督学习来制定已发现模式的阶段。我们需要根据所选的监督学习算法的要求成功准备数据。这也是确定将用作标签的特定特征的阶段。在第三阶段,我们将数据分为测试集和训练集。在这个阶段,我们形成数学公式来表示我们感兴趣的模式中的关系。这是通过使用第三阶段创建的训练数据来训练模型完成的。如前所述,最终的数学公式将取决于我们选择的算法。
-
第五阶段:评估:这个阶段是关于使用第三阶段的测试数据测试新训练的模型。如果评估符合第一阶段设定的期望,那么我们需要再次迭代所有前面的阶段,从第一阶段开始。这在前面的图像中有所说明。
-
第六阶段:部署:如果评估符合或超过第五阶段描述的期望,那么训练好的模型将被部署到生产环境中,并开始为我们在第一阶段定义的问题提供解决方案。
CRISP-DM 生命周期的第二阶段(数据理解)和第三阶段(数据准备)都是关于理解数据并为训练模型做准备。这些阶段涉及数据处理。一些组织为这个数据工程阶段雇佣专家。
很明显,提出问题的解决方案的过程完全是数据驱动的。结合监督和无监督机器学习用于制定可行的解决方案。本章重点介绍解决方案的无监督学习部分。
数据工程包括第二阶段和第三阶段,是机器学习中最耗时的部分。它可能占据典型 ML 项目时间和资源的 70%。无监督学习算法在数据工程中可以发挥重要作用。
以下各节提供了有关无监督算法的更多细节。
无监督学习的当前研究趋势
多年来,对机器学习算法的研究更多地集中在监督学习技术上。由于监督学习技术可以直接用于推断,因此它们在时间、成本和准确性方面的优势相对容易衡量。无监督机器学习算法的潜力最*才被认识到。由于无监督学习不受指导,因此它不太依赖假设,并且可能在任何维度上收敛解决方案。尽管更难控制无监督学习算法的范围和处理要求,但它们有更多潜力发现隐藏的模式。研究人员还在努力将无监督机器学习技术与监督学习技术相结合,以设计新的强大算法。
实际例子
目前,无监督学习用于更好地理解数据并为其提供更多结构,例如,它用于市场细分、欺诈检测和市场篮分析(稍后在本章中讨论)。让我们看几个例子。
语音分类
无监督学习可以用于对语音文件中的个别声音进行分类。它利用了每个人的声音具有独特的特征这一事实,从而创建可能可分离的音频模式。这些模式可以用于语音识别,例如,谷歌在其 Google Home 设备中使用这种技术来训练它们区分不同人的声音。一旦训练完成,Google Home 可以个性化地为每个用户提供响应。
例如,假设我们有一段录制的三个人互相交谈半个小时的对话。使用无监督学习算法,我们可以识别数据集中不同人的声音。请注意,通过无监督学习,我们为给定的非结构化数据集添加了结构。这种结构为我们的问题空间提供了额外有用的维度,可以用于获取见解并为我们选择的机器学习算法准备数据。以下图表显示了无监督学习用于语音识别的情况:
请注意,在这种情况下,无监督学习建议我们添加一个具有三个不同级别的新特征。
文档分类
无监督机器学习算法也可以应用于非结构化文本数据的存储库,例如,如果我们有一组 PDF 文档的数据集,那么无监督学习可以用于以下目的:
-
发现数据集中的各种主题
-
将每个 PDF 文档与发现的主题之一关联起来
无监督学习用于文档分类的情况如下图所示。这是另一个例子,我们在非结构化数据中添加了更多的结构:
图 6.4:使用无监督学习进行文档分类
请注意,在这种情况下,无监督学习建议我们添加一个具有五个不同级别的新特征。
理解聚类算法
在无监督学习中使用的最简单和最强大的技术之一是基于通过聚类算法将相似模式分组在一起。它用于理解与我们试图解决的问题相关的数据的特定方面。聚类算法寻找数据项中的自然分组。由于该组不是基于任何目标或假设,因此被归类为无监督学习技术。
各种聚类算法创建的分组是基于在问题空间中找到各种数据点之间的相似性。确定数据点之间的相似性的最佳方法将因问题而异,并且将取决于我们正在处理的问题的性质。让我们看看可以用来计算各种数据点之间相似性的各种方法。
量化相似性
聚类算法创建的分组的可靠性是基于这样一个假设:我们能够准确量化问题空间中各种数据点之间的相似性或接*程度。这是通过使用各种距离度量来实现的。以下是用于量化相似性的三种最流行的方法:
-
欧几里得距离度量
-
曼哈顿距离度量
-
余弦距离度量
让我们更详细地看看这些距离度量。
欧几里得距离
不同点之间的距离可以量化两个数据点之间的相似性,并且广泛用于无监督机器学习技术,如聚类。欧几里得距离是最常见和简单的距离度量。它通过测量多维空间中两个数据点之间的最短距离来计算。例如,让我们考虑二维空间中的两点A(1,1)和B(4,4),如下图所示:
要计算A和B之间的距离——即d(A,B),我们可以使用以下毕达哥拉斯公式:
请注意,此计算是针对二维问题空间的。对于n维问题空间,我们可以计算两点A和B之间的距离如下:
曼哈顿距离
在许多情况下,使用欧几里得距离度量来测量两点之间的最短距离将无法真正代表两点之间的相似性或接*程度——例如,如果两个数据点代表地图上的位置,则使用地面交通工具(如汽车或出租车)从点 A 到点 B 的实际距离将大于欧几里得距离计算出的距离。对于这类情况,我们使用曼哈顿距离,它标记了两点之间的最长路线,并更好地反映了在繁忙城市中可以前往的源点和目的地点之间的接*程度。曼哈顿和欧几里得距离度量之间的比较如下图所示:
曼哈顿距离始终大于或等于相应的欧几里得距离。
余弦距离
欧几里得和曼哈顿距离度量在高维空间中表现不佳。在高维问题空间中,余弦距离更准确地反映了多维问题空间中两个数据点之间的接*程度。余弦距离度量是通过测量由两个连接到参考点的点所创建的余弦角来计算的。如果数据点接*,则角度将很窄,而不管它们具有的维度如何。另一方面,如果它们相距很远,那么角度将很大:
文本数据几乎可以被视为高维空间。由于余弦距离度量在高维空间中表现非常好,因此在处理文本数据时是一个不错的选择。
请注意,在前面的图中,A(2,5)和B(4.4)之间的角的余弦是余弦距离。这些点之间的参考点是原点——即X(0,0)。但实际上,问题空间中的任何点都可以充当参考数据点,并且不一定是原点。
K 均值聚类算法
k-means 聚类算法的名称来自于它试图创建k个聚类,通过计算均值来找到数据点之间的接*程度。它使用了一个相对简单的聚类方法,但由于其可扩展性和速度而仍然受欢迎。从算法上讲,k-means 聚类使用了一个迭代逻辑,将聚类的中心移动到它们所属的分组的最具代表性的数据点。
重要的是要注意,k-means 算法缺乏聚类所需的非常基本的功能之一。这个缺失的功能是,对于给定的数据集,k-means 算法无法确定最合适的聚类数。最合适的聚类数k取决于特定数据集中自然分组的数量。这种省略背后的哲学是尽可能简化算法,最大限度地提高其性能。这种精益简洁的设计使 k-means 适用于更大的数据集。假设将使用外部机制来计算k。确定k的最佳方法将取决于我们试图解决的问题。在某些情况下,k直接由聚类问题的上下文指定,例如,如果我们想将一类数据科学学生分成两个聚类,一个由具有数据科学技能的学生组成,另一个由具有编程技能的学生组成,那么k将为 2。在其他一些问题中,k的值可能不明显。在这种情况下,将不得不使用迭代的试错程序或基于启发式的算法来估计给定数据集的最合适的聚类数。
k-means 聚类的逻辑
本节描述了 k-means 聚类算法的逻辑。让我们逐一看一下。
初始化
为了对它们进行分组,k-means 算法使用距离度量来找到数据点之间的相似性或接*程度。在使用 k-means 算法之前,需要选择最合适的距离度量。默认情况下,将使用欧氏距离度量。此外,如果数据集中有异常值,则需要制定机制来确定要识别和删除数据集的异常值的标准。
k-means 算法的步骤
k-means 聚类算法涉及的步骤如下:
步骤 1 | 我们选择聚类的数量k。 |
---|---|
步骤 2 | 在数据点中,我们随机选择k个点作为聚类中心。 |
步骤 3 | 基于所选的距离度量,我们迭代地计算问题空间中每个点到k个聚类中心的距离。根据数据集的大小,这可能是一个耗时的步骤,例如,如果聚类中有 10,000 个点,k=3,这意味着需要计算 30,000 个距离。 |
步骤 4 | 我们将问题空间中的每个数据点分配给最*的聚类中心。 |
步骤 5 | 现在我们问题空间中的每个数据点都有一个分配的聚类中心。但我们还没有完成,因为初始聚类中心的选择是基于随机选择的。我们需要验证当前随机选择的聚类中心实际上是每个聚类的重心。我们通过计算每个k聚类的组成数据点的*均值来重新计算聚类中心。这一步解释了为什么这个算法被称为 k-means。 |
步骤 6 | 如果在步骤 5 中聚类中心发生了变化,这意味着我们需要重新计算每个数据点的聚类分配。为此,我们将回到步骤 3 重复这个计算密集的步骤。如果聚类中心没有发生变化,或者我们的预定停止条件(例如,最大迭代次数)已经满足,那么我们就完成了。 |
下图显示了在二维问题空间中运行 k-means 算法的结果:
(a)聚类前的数据点;(b)运行 k 均值聚类算法后的结果集群
请注意,在运行 k 均值后创建的两个结果集群在这种情况下有很好的区分度。
停止条件
对于 k 均值算法,默认的停止条件是在第 5 步中不再移动集群中心。但是与许多其他算法一样,k 均值算法可能需要很长时间才能收敛,特别是在处理高维问题空间中的大型数据集时。我们可以明确定义停止条件,而不是等待算法收敛,如下所示:
-
通过指定最大执行时间:
-
停止条件:如果 t>t[max],其中t是当前执行时间,t[max]是我们为算法设置的最大执行时间。
-
通过指定最大迭代次数:
-
停止条件:如果 m>m[max],其中m是当前迭代次数,m[max]是我们为算法设置的最大迭代次数。
编写 k 均值算法
让我们看看如何在 Python 中编写 k 均值算法:
- 首先,让我们导入编写 k 均值算法所需的软件包。请注意,我们正在导入
sklearn
软件包进行 k 均值聚类:
from sklearn import cluster import pandas as pd
import numpy as np
- 要使用 k 均值聚类,让我们在二维问题空间中创建 20 个数据点,这些数据点将用于 k 均值聚类:
dataset = pd.DataFrame({
'x': [11, 21, 28, 17, 29, 33, 24, 45, 45, 52, 51, 52, 55, 53, 55, 61, 62, 70, 72, 10],
'y': [39, 36, 30, 52, 53, 46, 55, 59, 63, 70, 66, 63, 58, 23, 14, 8, 18, 7, 24, 10]
})
- 让我们有两个集群(k=2),然后通过调用
fit
函数创建集群:
myKmeans = cluster.KMeans(n_clusters=2)
myKmeans.fit(dataset)
- 让我们创建一个名为
centroid
的变量,它是一个包含形成的集群中心位置的数组。在我们的情况下,k=2,数组的大小将为 2。让我们还创建另一个名为label
的变量,表示每个数据点分配给两个集群中的一个。由于有 20 个数据点,这个数组的大小将为 20:
centroids = myKmeans.cluster_centers_
labels = myKmeans.labels_
- 现在让我们打印这两个数组,
centroids
和labels
:
请注意,第一个数组显示了每个数据点与集群的分配,第二个数组显示了两个集群中心。
- 让我们使用
matplotlib
绘制并查看这些集群:
请注意,图中的较大点是由 k 均值算法确定的中心点。
k 均值聚类的局限性
k 均值算法旨在成为一种简单快速的算法。由于其设计上的故意简单性,它具有以下限制:
-
k 均值聚类的最大限制是初始集群数量必须预先确定。
-
集群中心的初始分配是随机的。这意味着每次运行算法时,可能会得到略有不同的集群。
-
每个数据点只分配给一个集群。
-
k 均值聚类对异常值敏感。
层次聚类
k 均值聚类使用自上而下的方法,因为我们从最重要的数据点开始算法,即集群中心。还有一种聚类的替代方法,即不是从顶部开始,而是从底部开始算法。在这种情况下,底部是问题空间中的每个单独数据点。解决方案是在向上移向集群中心的过程中不断将相似的数据点分组在一起。这种替代的自下而上方法由层次聚类算法使用,并在本节中讨论。
层次聚类的步骤
层次聚类涉及以下步骤:
-
我们在问题空间中为每个数据点创建一个单独的集群。如果我们的问题空间包含 100 个数据点,那么它将从 100 个集群开始。
-
我们只将彼此最接*的点分组。
-
我们检查停止条件;如果停止条件尚未满足,则重复步骤 2。
生成的集群结构称为树状图。
在树状图中,垂直线的高度决定了物品的接*程度,如下图所示:
请注意,停止条件显示为上图中的虚线。
编写一个分层聚类算法
让我们学习如何在 Python 中编写一个分层算法:
- 我们将首先从
sklearn.cluster
库中导入AgglomerativeClustering
,以及pandas
和numpy
包:
from sklearn.cluster import AgglomerativeClustering import pandas as pd
import numpy as np
- 然后我们将在二维问题空间中创建 20 个数据点:
dataset = pd.DataFrame({
'x': [11, 21, 28, 17, 29, 33, 24, 45, 45, 52, 51, 52, 55, 53, 55, 61, 62, 70, 72, 10],
'y': [39, 36, 30, 52, 53, 46, 55, 59, 63, 70, 66, 63, 58, 23, 14, 8, 18, 7, 24, 10]
})
- 然后我们通过指定超参数来创建分层集群。我们使用
fit_predict
函数来实际处理算法:
cluster = AgglomerativeClustering(n_clusters=2, affinity='euclidean', linkage='ward')
cluster.fit_predict(dataset)
- 现在让我们看一下每个数据点与创建的两个簇的关联:
您可以看到分层和 k 均值算法的集群分配非常相似。
评估聚类
良好质量的聚类的目标是属于不同簇的数据点应该是可区分的。这意味着以下内容:
-
属于同一簇的数据点应尽可能相似。
-
属于不同簇的数据点应尽可能不同。
人类直觉可以用来通过可视化集群结果来评估集群结果,但也有数学方法可以量化集群的质量。轮廓分析是一种比较 k 均值算法创建的集群中的紧密度和分离度的技术。轮廓绘制了一个图,显示了特定集群中每个点与相邻集群中其他点的接*程度。它将与每个集群关联的数字范围为[-0, 1]。以下表显示了此范围中的数字表示什么:
范围 | 意义 | 描述 |
---|---|---|
0.71–1.0 | 优秀 | 这意味着 k 均值聚类导致的组在相当程度上是可区分的。 |
0.51–0.70 | 合理 | 这意味着 k 均值聚类导致的组在某种程度上是可区分的。 |
0.26–0.50 | 弱 | 这意味着 k 均值聚类导致了分组,但不应依赖分组的质量。 |
<0.25 | 未找到任何聚类 | 使用选择的参数和使用的数据,无法使用 k 均值聚类创建分组。 |
请注意,问题空间中的每个簇将获得一个单独的分数。
聚类的应用
聚类用于我们需要在数据集中发现潜在模式的地方。
在政府使用案例中,聚类可用于以下目的:
-
犯罪热点分析
-
人口社会分析
在市场研究中,聚类可用于以下目的:
-
市场细分
-
定向广告
-
客户分类
主成分分析(PCA)也用于通常探索数据并从实时数据中去除噪音,例如股票市场交易。
降维
我们数据中的每个特征对应于问题空间中的一个维度。将特征的数量最小化以使问题空间更简单称为降维。可以通过以下两种方式之一来完成:
-
特征选择:选择在我们试图解决的问题的上下文中重要的一组特征
-
特征聚合:使用以下算法之一组合两个或多个特征以减少维度:
-
PCA:线性无监督 ML 算法
-
线性判别分析(LDA):线性监督 ML 算法
-
核主成分分析:一种非线性算法
让我们更深入地了解一种流行的降维算法,即 PCA。
主成分分析
PCA 是一种无监督的机器学习技术,可以使用线性变换来降低维度。在下图中,我们可以看到两个主成分PC1和PC2,它们显示了数据点的分布形状。PC1 和 PC2 可以用适当的系数来总结数据点:
让我们考虑以下代码:
from sklearn.decomposition import PCA
iris = pd.read_csv('iris.csv')
X = iris.drop('Species', axis=1)
pca = PCA(n_components=4)
pca.fit(X)
现在让我们打印我们的 PCA 模型的系数:
请注意,原始的 DataFrame 有四个特征,Sepal.Length
、Sepal.Width
、Petal.Length
和Petal.Width
。前面的 DataFrame 指定了四个主成分 PC1、PC2、PC3 和 PC4 的系数,例如,第一行指定了可以用来替换原始四个变量的 PC1 的系数。
根据这些系数,我们可以计算我们输入 DataFrame X 的 PCA 组件:
pca_df=(pd.DataFrame(pca.components_,columns=X.columns))
# Let us calculate PC1 using coefficients that are generated
X['PC1'] = X['Sepal.Length']* pca_df['Sepal.Length'][0] + X['Sepal.Width']* pca_df['Sepal.Width'][0]+ X['Petal.Length']* pca_df['Petal.Length'][0]+X['Petal.Width']* pca_df['Petal.Width'][0]
# Let us calculate PC2
X['PC2'] = X['Sepal.Length']* pca_df['Sepal.Length'][1] + X['Sepal.Width']* pca_df['Sepal.Width'][1]+ X['Petal.Length']* pca_df['Petal.Length'][1]+X['Petal.Width']* pca_df['Petal.Width'][1]
#Let us calculate PC3
X['PC3'] = X['Sepal.Length']* pca_df['Sepal.Length'][2] + X['Sepal.Width']* pca_df['Sepal.Width'][2]+ X['Petal.Length']* pca_df['Petal.Length'][2]+X['Petal.Width']* pca_df['Petal.Width'][2]
# Let us calculate PC4
X['PC4'] = X['Sepal.Length']* pca_df['Sepal.Length'][3] + X['Sepal.Width']* pca_df['Sepal.Width'][3]+ X['Petal.Length']* pca_df['Petal.Length'][3]+X['Petal.Width']* pca_df['Petal.Width'][3]
现在让我们在计算 PCA 组件后打印 X:
现在让我们打印方差比率,并尝试理解使用 PCA 的影响:
方差比率表示如下:
-
如果我们选择用 PC1 替换原始的四个特征,那么我们将能够捕获大约 92.3%的原始变量的方差。我们通过不捕获原始四个特征 100%的方差来引入一些*似。
-
如果我们选择用 PC1 和 PC2 替换原始的四个特征,那么我们将捕获额外的 5.3%的原始变量的方差。
-
如果我们选择用 PC1、PC2 和 PC3 替换原始的四个特征,那么我们现在将捕获原始变量进一步的 0.017%的方差。
-
如果我们选择用四个主成分替换原始的四个特征,那么我们将捕获原始变量的 100%的方差(92.4 + 0.053 + 0.017 + 0.005),但用四个主成分替换四个原始特征是没有意义的,因为我们没有减少维度,也没有取得任何成果。
PCA 的局限性
PCA 的局限性如下:
-
PCA 只能用于连续变量,对于类别变量无关。
-
在聚合时,PCA *似了组件变量;它以准确性为代价简化了维度的问题。在使用 PCA 之前,应该仔细研究这种权衡。
关联规则挖掘
特定数据集中的模式是需要被发现、理解和挖掘的宝藏。有一组重要的算法试图专注于给定数据集中的模式分析。在这类算法中,较受欢迎的算法之一称为关联规则挖掘算法,它为我们提供了以下功能:
-
衡量模式频率的能力
-
建立模式之间因果关系的能力。
-
通过将它们的准确性与随机猜测进行比较,量化模式的有用性
使用示例
当我们试图调查数据集中不同变量之间的因果关系时,使用关联规则挖掘。以下是它可以帮助回答的示例问题:
-
哪些湿度、云层覆盖和温度值可能导致明天下雨?
-
什么类型的保险索赔可能表明欺诈?
-
哪些药物的组合可能会导致患者并发症?
市场篮分析
在本书中,推荐引擎在第八章“神经网络算法”中进行了讨论。篮子分析是学习推荐的一种简单方法。在篮子分析中,我们的数据只包含有关哪些物品一起购买的信息。它没有任何关于用户或用户是否喜欢个别物品的信息。请注意,获取这些数据要比获取评级数据容易得多。
例如,当我们在沃尔玛购物时,就会产生这种数据,而不需要任何特殊技术来获取数据。这些数据在一段时间内收集起来,被称为交易数据。当将关联规则分析应用于便利店、超市和快餐连锁店中使用的购物车的交易数据集时,就称为市场篮子分析。它衡量了一组物品一起购买的条件概率,有助于回答以下问题:
-
货架上物品的最佳摆放位置是什么?
-
物品在营销目录中应该如何出现?
-
基于用户的购买模式,应该推荐什么?
由于市场篮子分析可以估计物品之间的关系,因此它经常用于大众市场零售,如超市、便利店、药店和快餐连锁店。市场篮子分析的优势在于其结果几乎是不言自明的,这意味着它们很容易被业务用户理解。
让我们来看一个典型的超市。商店中所有可用的唯一物品可以用一个集合={item[1],item[2],...,item[m]}来表示。因此,如果那家超市销售 500 种不同的物品,那么
将是一个大小为 500 的集合。
人们会从这家商店购买物品。每当有人购买物品并在柜台付款时,它就会被添加到一个特定交易中的物品集合中,称为项目集。在一段时间内,交易被分组在一个由表示的集合中,其中
={t[1],t[2],...,t[n]}。
让我们来看一下只包含四个交易的简单交易数据。这些交易总结在下表中:
t1 | 球门,护腕 |
---|---|
t2 | 球棒,球门,护腕,头盔 |
t3 | 头盔,球 |
t4 | 球棒、护腕、头盔 |
让我们更详细地看一下这个例子:
={球棒,球门,护腕,头盔,球},它代表了商店中所有可用的唯一物品。
让我们考虑来自的一个交易 t3。请注意,t3 中购买的物品可以用 itemset[t3]={头盔,球}表示,这表明顾客购买了两件物品。由于这个 itemset 中有两件物品,因此 itemset[t5]的大小被称为两。
关联规则
关联规则通过数学方式描述了各种交易中涉及的物品之间的关系。它通过研究形式为X⇒Y的两个项目集之间的关系来实现这一点,其中X⊂,Y⊂
。此外,X和Y是不重叠的项目集;这意味着
。
关联规则可以用以下形式描述:
{头盔,球}⇒{自行车}
在这里,{头盔,球}是X,{球}是Y。
规则类型
运行关联分析算法通常会从交易数据集中生成大量规则。其中大部分是无用的。为了挑选出可以提供有用信息的规则,我们可以将它们分类为以下三种类型之一:
-
琐碎
-
莫名其妙
-
可操作
让我们更详细地看看每种类型。
琐碎的规则
在生成的大量规则中,许多派生的规则将是无用的,因为它们总结了关于业务的常识。它们被称为琐碎规则。即使琐碎规则的置信度很高,它们仍然是无用的,不能用于任何数据驱动的决策。我们可以安全地忽略所有琐碎规则。
以下是琐碎规则的例子:
-
任何从高楼跳下的人都有可能死亡。
-
更努力工作会导致考试成绩更好。
-
随着温度下降,取暖器的销量会增加
-
在高速公路上超速驾驶会增加事故的可能性。
不可解释规则
在运行关联规则算法后生成的规则中,那些没有明显解释的规则是最难使用的。请注意,规则只有在能帮助我们发现和理解预期最终会导致某种行动的新模式时才有用。如果不是这种情况,我们无法解释事件X导致事件Y的原因,那么它就是一个不可解释的规则,因为它只是一个最终探索两个无关和独立事件之间毫无意义关系的数学公式。
以下是不可解释规则的例子:
-
穿红衬衫的人在考试中得分更高。
-
绿色自行车更容易被盗。
-
购买泡菜的人最终也会购买尿布。
可操作规则
可操作规则是我们正在寻找的黄金规则。它们被业务理解并引发见解。当呈现给熟悉业务领域的观众时,它们可以帮助我们发现事件可能的原因,例如,可操作规则可能根据当前的购买模式建议产品在商店中的最佳摆放位置。它们还可能建议将哪些商品放在一起,以最大化它们一起销售的机会。
以下是可操作规则及其相应的行动的例子:
- 规则 1:向用户的社交媒体账户展示广告会增加销售的可能性。
可操作项目:建议产品的替代广告方式
- 规则 2:创建更多的价格点会增加销售的可能性。
可操作项目:一个商品可能在促销中进行广告,而另一个商品的价格可能会上涨。
排名规则
关联规则有三种衡量方式:
-
物品的支持(频率)
-
置信度
-
提升
让我们更详细地看看它们。
支持
支持度量是一个数字,用来量化我们在数据集中寻找的模式有多频繁。首先计算我们感兴趣的模式出现的次数,然后将其除以所有交易的总数来计算。
让我们看看特定itemset[a]的以下公式:
numItemset[a] =包含 itemset[a]的交易数
num[total] =交易总数
仅通过支持,我们就可以了解到模式发生的罕见程度。低支持意味着我们在寻找一种罕见事件。
例如,如果itemset[a] = {头盔,球}在六次交易中出现了两次,那么支持(itemset[a])= 2/6 = 0.33。
置信度
置信度是一个数字,通过计算条件概率来量化我们可以将左侧(X)与右侧(Y)关联的强度。它计算了事件X发生的情况下,事件Y会发生的概率。
从数学上讲,考虑规则X ⇒ Y。
这条规则的置信度表示为 confidence(X ⇒ Y),并按以下方式测量:
让我们举个例子。考虑以下规则:
{头盔,球} ⇒ {球门}
这条规则的置信度由以下公式计算:
这意味着如果有人的篮子里有{头盔,球},那么他们还有球门的概率是 0.5 或 50%。
提升
估计规则质量的另一种方法是通过计算提升。提升返回一个数字,量化了规则在预测结果方面相对于仅假设等式右侧的结果的改进程度。如果X和Y项集是独立的,那么提升的计算如下:
关联分析算法
在本节中,我们将探讨以下两种可用于关联分析的算法:
-
Apriori 算法:由 Agrawal, R.和 Srikant 于 1994 年提出。
-
FP-growth 算法:由 Han 等人于 2001 年提出的改进建议。
让我们看看这些算法各自的情况。
Apriori 算法
Apriori 算法是一种迭代和多阶段的算法,用于生成关联规则。它基于生成和测试的方法。
在执行 apriori 算法之前,我们需要定义两个变量:support[threshold]和 Confidence[threshold]。
该算法包括以下两个阶段:
-
候选生成阶段:它生成包含所有高于 support[threshold]的项集的候选项集。
-
过滤阶段:它过滤掉所有低于预期 confidence[threshold]的规则。
过滤后,得到的规则就是答案。
Apriori 算法的局限性
Apriori 算法中的主要瓶颈是第 1 阶段候选规则的生成,例如, = {item [1] , item [2] , . . . , item [m] } 可以产生 2^m 个可能的项集。由于其多阶段设计,它首先生成这些项集,然后努力找到频繁项集。这个限制是一个巨大的性能瓶颈,使得 apriori 算法不适用于更大的项。
FP-growth 算法
频繁模式增长(FP-growth)算法是对 apriori 算法的改进。它首先展示频繁交易 FP 树,这是一个有序树。它包括两个步骤:
-
填充 FP 树
-
挖掘频繁模式
让我们一步一步地看这些步骤。
填充 FP 树
让我们考虑下表中显示的交易数据。让我们首先将其表示为稀疏矩阵:
ID | 球棒 | 球门 | 防护板 | 头盔 | 球 |
---|---|---|---|---|---|
1 | 0 | 1 | 1 | 0 | 0 |
2 | 1 | 1 | 1 | 1 | 0 |
3 | 0 | 0 | 0 | 1 | 1 |
4 | 1 | 0 | 1 | 1 | 0 |
让我们计算每个项的频率,并按频率降序排序:
项 | 频率 |
---|---|
防护板 | 3 |
头盔 | 3 |
球棒 | 2 |
球门 | 2 |
球 | 1 |
现在让我们根据频率重新排列基于交易的数据:
ID | 原始项 | 重新排序的项 |
---|---|---|
t1 | 防护板,球门 | 防护板,球门 |
t2 | 球棒,球门,防护板,头盔 | 头盔,防护板,球门,球棒 |
t3 | 头盔,球 | 头盔,球 |
t4 | 球棒,防护板,头盔 | 头盔,防护板,球棒 |
要构建 FP 树,让我们从 FP 树的第一个分支开始。FP 树以Null作为根开始。为了构建树,我们可以用一个节点表示每个项,如下图所示(这里显示了 t[1]的树表示)。请注意,每个节点的标签都是项的名称,冒号后面附加了其频率。还要注意pads项的频率为 1:
使用相同的模式,让我们绘制所有四个交易,得到完整的 FP 树。FP 树有四个叶节点,每个节点代表与四个交易相关的项集。请注意,我们需要计算每个项的频率,并在多次使用时增加它-例如,将 t[2]添加到 FP 树时,头盔 的频率增加到了两次。类似地,当添加 t[4]时,它再次增加到了三次。结果树如下图所示:
请注意,前面图中生成的 FP 树是有序树。
挖掘频繁模式
FP-growth 树的第二阶段涉及从 FP 树中挖掘频繁模式。通过创建一个有序树,意图是创建一个高效的数据结构,可以轻松导航以搜索频繁模式。
我们从叶节点(即末端节点)开始向上移动-例如,让我们从叶节点项之一 球棒 开始。然后我们需要计算 球棒 的条件模式基。通过指定从叶节点项到顶部的所有路径来计算条件模式基。球棒 的条件模式基如下:
球门: 1 | 护腕: 1 | 头盔: 1 |
---|---|---|
护腕: 1 | 头盔: 1 |
球棒 的 频繁模式 如下:
{球门, 护腕, 头盔} : 球棒
{护腕,头盔} : 球棒
使用 FP-growth 的代码
让我们看看如何使用 Python 中的 FP-growth 算法生成关联规则。为此,我们将使用 pyfpgrowth
软件包。首先,如果我们以前从未使用过 pyfpgrowth
,让我们首先安装它:
!pip install pyfpgrowth
然后,让我们导入实现此算法所需的软件包:
import pandas as pd
import numpy as np
import pyfpgrowth as fp
现在我们将创建以 transactionSet
形式的输入数据:
dict1 = {
'id':[0,1,2,3],
'items':[["wickets","pads"],
["bat","wickets","pads","helmet"],
["helmet","pad"],
["bat","pads","helmet"]]
}
transactionSet = pd.DataFrame(dict1)
一旦生成了输入数据,我们将生成基于我们传递给 find_frequent_patterns()
的参数的模式。请注意,传递给此函数的第二个参数是最小支持度,在本例中为 1:
patterns = fp.find_frequent_patterns(transactionSet['items'],1)
模式已生成。现在让我们打印模式。模式列出了项的组合及其支持:
现在让我们生成规则:
每个规则都有左侧和右侧,由冒号(:)分隔。它还为我们提供了输入数据集中每个规则的支持。
实际应用-将相似的推文进行聚类
无监督机器学习算法也可以实时应用于将相似的推文进行聚类。它们将执行以下操作:
-
步骤 1- 主题建模: 从给定的一组推文中发现各种主题
-
步骤 2- 聚类: 将每个推文与发现的主题之一关联起来
这种无监督学习的应用如下图所示:
请注意,此示例需要实时处理输入数据。
让我们逐一看看这些步骤。
主题建模
主题建模是发现一组文档中的概念的过程,这些概念可以用来区分它们。在推文的背景下,这是关于找出一组推文可以被分成哪些最合适的主题。潜在狄利克雷分配是一种用于主题建模的流行算法。因为每条推文都是一个短的 144 个字符的文档,通常涉及一个非常特定的主题,我们可以为主题建模目的编写一个更简单的算法。该算法描述如下:
-
对推文进行标记化处理。
-
预处理数据。删除停用词、数字、符号并进行词干处理
-
为推文创建一个术语-文档矩阵(TDM)。选择在唯一推文中出现最频繁的前 200 个词。
-
选择直接或间接代表概念或主题的前 10 个单词。例如时尚、纽约、编程、事故。这 10 个单词现在是我们成功发现的主题,并将成为 tweets 的聚类中心。
让我们继续下一步,即聚类
聚类
一旦我们发现了主题,我们将选择它们作为聚类的中心。然后我们可以运行 k-means 聚类算法,将每个 tweet 分配到其中一个聚类中心。
因此,这是一个实际的例子,说明一组 tweets 如何被聚类成发现的主题。
异常检测算法
异常 的词典定义是与众不同、异常、奇特或不容易分类的东西。它是偏离常规规则的。在数据科学的背景下,异常是偏离预期模式很多的数据点。寻找这样的数据点的技术被称为异常检测技术。
现在让我们看看异常检测算法的一些应用:
-
信用卡欺诈
-
在 磁共振成像(MRI) 扫描中发现恶性肿瘤
-
集群中的故障预防
-
考试中的冒名顶替
-
高速公路上的事故
在接下来的章节中,我们将看到各种异常检测技术。
使用聚类
诸如 k-means 的聚类算法可以用来将相似的数据点分组在一起。可以定义一个阈值,任何超出该阈值的点都可以被分类为异常。这种方法的问题在于,由于异常数据点的存在,k-means 聚类创建的分组本身可能会存在偏差,并可能影响方法的实用性和准确性。
使用基于密度的异常检测
基于密度的方法试图找到密集的邻域。k-最*邻(KNN)算法可以用于此目的。远离发现的密集邻域的异常被标记为异常。
使用支持向量机
支持向量机(SVM)算法可以用来学习数据点的边界。任何超出这些发现的边界的点都被识别为异常。
总结
在本章中,我们看了各种无监督的机器学习技术。我们看了尝试减少我们试图解决的问题的维度的情况,以及不同的方法。我们还研究了无监督机器学习技术在哪些情况下非常有帮助,包括市场篮分析和异常检测。
在下一章中,我们将看看各种监督学习技术。我们将从线性回归开始,然后我们将看看更复杂的监督机器学习技术,如基于决策树的算法、SVM 和 XGBoast。我们还将研究朴素贝叶斯算法,它最适合于非结构化的文本数据。
第七章:传统监督学习算法
在本章中,我们将重点介绍监督式机器学习算法,这是现代算法中最重要的类型之一。监督式机器学习算法的显著特征是使用带标签的数据来训练模型。在本书中,监督式机器学习算法分为两章。在本章中,我们将介绍所有传统的监督式机器学习算法,不包括神经网络。下一章将全面介绍使用神经网络实现监督式机器学习算法。事实上,在这一领域有如此多的持续发展,神经网络是一个值得在本书中单独章节讨论的综合性主题。
因此,这一章是关于监督式机器学习算法的两个部分中的第一部分。首先,我们将介绍监督式机器学习的基本概念。接下来,我们将介绍两种监督式机器模型——分类器和回归器。为了展示分类器的能力,我们将首先提出一个真实世界的问题作为挑战。然后,我们将介绍六种不同的分类算法,用于解决这个问题。然后,我们将专注于回归算法,首先提出一个类似的问题,以便为回归器解决问题。接下来,我们将介绍三种回归算法,并使用它们来解决问题。最后,我们将比较结果,以帮助我们总结本章介绍的概念。
本章的总体目标是让您了解不同类型的监督式机器学习技术,并了解对于某些类别的问题,最佳的监督式机器学习技术是什么。
本章讨论了以下概念:
-
理解监督式机器学习
-
理解分类算法
-
评估分类器性能的方法
-
理解回归算法
-
评估回归算法性能的方法
让我们从理解监督式机器学习背后的基本概念开始。
理解监督式机器学习
机器学习专注于使用数据驱动的方法来创建可以帮助我们做出决策的自主系统,无论是否有人类监督。为了创建这些自主系统,机器学习使用一组算法和方法来发现和制定数据中可重复的模式。在机器学习中最流行和强大的方法之一是监督式机器学习方法。在监督式机器学习中,算法被给定一组输入,称为特征,以及它们对应的输出,称为目标 变量。使用给定的数据集,监督式机器学习算法用于训练一个捕捉特征和目标变量之间复杂关系的模型,该关系由数学公式表示。这个训练好的模型是用于预测的基本工具。
通过训练模型,通过生成未知特征集的目标变量来进行预测。
在监督学习中从现有数据中学习的能力类似于人脑从经验中学习的能力。监督学习中的这种学习能力使用了人脑的一个属性,是将决策能力和智能引入机器的基本途径。
让我们考虑一个例子,我们想要使用监督式机器学习技术训练一个模型,可以将一组电子邮件分类为合法邮件(称为合法)和不需要的邮件(称为垃圾邮件)。首先,为了开始,我们需要过去的例子,这样机器才能学习应该将什么样的电子邮件内容分类为垃圾邮件。这种基于内容的文本数据学习任务是一个复杂的过程,可以通过监督式机器学习算法之一来实现。在这个例子中,可以用来训练模型的一些监督式机器学习算法包括决策树和朴素贝叶斯分类器,我们将在本章后面讨论。
制定监督式机器学习
在深入研究监督式机器学习算法的细节之前,让我们定义一些基本的监督式机器学习术语:
术语 | 解释 |
---|---|
目标变量 | 目标变量是我们希望模型预测的变量。在监督式机器学习模型中只能有一个目标变量。 |
标签 | 如果我们想要预测的目标变量是一个类别变量,那么它被称为标签。 |
特征 | 用于预测标签的一组输入变量称为特征。 |
特征工程 | 将特征转换为所选监督式机器学习算法准备的过程称为特征工程。 |
特征向量 | 在将输入提供给监督式机器学习算法之前,所有特征都被组合在一个称为特征向量的数据结构中。 |
历史数据 | 用于制定目标变量和特征之间关系的过去数据称为历史数据。历史数据带有示例。 |
训练/测试数据 | 历史数据与示例被分成两部分——一个更大的数据集称为训练数据,一个较小的数据集称为测试数据。 |
模型 | 目标变量和特征之间关系的最佳捕捉模式的数学表达。 |
训练 | 使用训练数据创建模型。 |
测试 | 使用测试数据评估训练模型的质量。 |
预测 | 使用模型预测目标变量。 |
经过训练的监督式机器学习模型能够通过估计特征来预测目标变量。
让我们介绍一下本章中将使用的符号,讨论机器学习技术:
变量 | 含义 |
---|---|
y | 实际标签 |
ý | 预测标签 |
d | 总示例数量 |
b | 训练示例的数量 |
c | 测试示例的数量 |
现在,让我们看看一些这些术语如何在实际中被制定。
正如我们讨论的,特征向量被定义为一个包含所有特征的数据结构。
如果特征的数量是n,训练示例的数量是b,那么X_train
表示训练特征向量。每个示例都是特征向量中的一行。
对于训练数据集,特征向量由X_train
表示。如果训练数据集中有b个示例,那么X_train
将有b行。如果训练数据集中有n个变量,那么它将有n列。因此,训练数据集将具有n x b的维度,如下图所示:
现在,让我们假设有b个训练示例和c个测试示例。一个特定的训练示例由(X, y)表示。
我们使用上标来指示训练集中的每个训练示例。
因此,我们的标记数据集由 D = {X((1)),y((1))), (X((2)),y((2))), ..... , (X((d)),y((d)))}表示。
我们将其分为两部分——D[train]和 D[test]。
因此,我们的训练集可以用 D[train] = {X((1)),y((1))), (X((2)),y((2))), ..... , (X((b)),y((b)))}来表示。
训练模型的目标是对于训练集中的任何第 i 个示例,目标值的预测值应尽可能接*示例中的实际值。换句话说,。
因此,我们的测试集可以用 D[test] = {X((1)),y((1))), (X((2)),y((2))), ..... , (X((c)),y((c)))}来表示。
目标变量的值由向量Y表示:
Y = {y^((1)), y^((2)), ....., y^((m))}
理解启用条件
监督式机器学习是基于算法使用示例来训练模型的能力。监督式机器学习算法需要满足一定的启用条件才能执行。这些启用条件如下:
-
足够的示例:监督式机器学习算法需要足够的示例来训练模型。
-
历史数据中的模式:用于训练模型的示例需要具有其中的模式。我们感兴趣事件的发生可能性应取决于模式、趋势和事件的组合。如果没有这些,我们处理的是无法用于训练模型的随机数据。
-
有效的假设:当我们使用示例训练监督式机器学习模型时,我们期望适用于示例的假设在未来也是有效的。让我们看一个实际的例子。如果我们想要为政府训练一个可以预测学生是否会获得签证的机器学习模型,那么理解是在模型用于预测时,法律和政策不会发生变化。如果在训练模型后实施了新的政策或法律,可能需要重新训练模型以纳入这些新信息。
区分分类器和回归器
在机器学习模型中,目标变量可以是类别变量或连续变量。目标变量的类型决定了我们拥有的监督式机器学习模型的类型。基本上,我们有两种类型的监督式机器学习模型:
-
分类器:如果目标变量是类别变量,则机器学习模型称为分类器。分类器可用于回答以下类型的业务问题:
-
这种异常组织生长是否是恶性肿瘤?
-
根据当前的天气条件,明天会下雨吗?
-
基于特定申请人的资料,他们的抵押贷款申请是否应该被批准?
-
回归器:如果目标变量是连续变量,我们训练一个回归器。回归器可用于回答以下类型的业务问题:
-
根据当前的天气条件,明天会下多少雨?
-
具有给定特征的特定房屋的价格将是多少?
让我们更详细地看看分类器和回归器。
理解分类算法
在监督式机器学习中,如果目标变量是类别变量,则模型被归类为分类器:
-
目标变量称为标签。
-
历史数据称为标记数据。
-
需要预测标签的生产数据称为未标记数据。
使用训练模型准确标记未标记数据的能力是分类算法的真正力量。分类器预测未标记数据的标签以回答特定的业务问题。
在我们介绍分类算法的细节之前,让我们首先提出一个业务问题,作为分类器的挑战。然后我们将使用六种不同的算法来回答相同的挑战,这将帮助我们比较它们的方法、途径和性能。
提出分类器挑战
我们将首先提出一个常见的问题,我们将使用它作为测试六种不同分类算法的挑战。这个常见的问题在本章中被称为分类器挑战。使用所有六种分类器来解决同一个问题将帮助我们以两种方式:
-
所有输入变量都需要被处理和组装成一个复杂的数据结构,称为特征向量。使用相同的特征向量可以帮助我们避免为所有六个算法重复数据准备。
-
我们可以通过使用相同的特征向量作为输入来比较各种算法的性能。
分类器挑战是关于预测一个人购买的可能性。在零售行业,可以帮助最大化销售的一件事是更好地了解客户的行为。这可以通过分析历史数据中发现的模式来实现。让我们先阐述问题。
问题陈述
根据历史数据,我们能否训练一个二元分类器,可以预测特定用户最终是否会购买产品?
首先,让我们探索可用于解决这个问题的历史标记数据集:
x € ℜ^b, y € {0,1}
对于特定示例,当y = 1 时,我们称之为正类,当y = 0 时,我们称之为负类。
尽管正类和负类的级别可以任意选择,但定义正类为感兴趣的事件是一个好的做法。如果我们试图为银行标记欺诈交易,那么正类(即y = 1)应该是欺诈交易,而不是相反。
现在,让我们来看一下以下内容:
-
实际标签,用y表示
-
预测的标签,用y`表示
请注意,对于我们的分类器挑战,示例中找到的标签的实际值由y表示。如果在我们的示例中,有人购买了一个物品,我们说y = 1。预测值由y`表示。输入特征向量x的维度为 4。我们想确定用户在给定特定输入时购买的概率是多少。
因此,我们希望确定在给定特征向量x的特定值时y = 1 的概率。从数学上讲,我们可以表示如下:
现在,让我们看看如何处理和组装特征向量x中的不同输入变量。在下一节中,将更详细地讨论使用处理管道组装x的不同部分的方法。
使用数据处理管道进行特征工程
为了选择一个特定的机器学习算法的数据准备被称为特征工程,它是机器学习生命周期的一个关键部分。特征工程在不同的阶段或阶段进行。用于处理数据的多阶段处理代码被统称为数据管道。在可能的情况下使用标准处理步骤制作数据管道,使其可重用并减少训练模型所需的工作量。通过使用更多经过测试的软件模块,代码的质量也得到了提高。
让我们为分类器挑战设计一个可重用的处理管道。如前所述,我们将准备数据一次,然后将其用于所有分类器。
导入数据
这个问题的历史数据存储在一个名为dataset
的文件中,格式为.csv
。我们将使用 pandas 的pd.read_csv
函数将数据导入为数据框:
dataset = pd.read_csv('Social_Network_Ads.csv')
特征选择
选择与我们想要解决的问题相关的特征的过程称为特征选择。这是特征工程的一个重要部分。
一旦文件被导入,我们删除User ID
列,该列用于识别一个人,并且在训练模型时应该被排除:
dataset = dataset.drop(columns=['User ID'])
现在让我们预览数据集:
dataset.head(5)
数据集如下:
现在,让我们看看如何进一步处理输入数据集。
独热编码
许多机器学习算法要求所有特征都是连续变量。这意味着如果一些特征是类别变量,我们需要找到一种策略将它们转换为连续变量。独热编码是执行这种转换的最有效方式之一。对于这个特定的问题,我们唯一的类别变量是Gender
。让我们使用独热编码将其转换为连续变量:
enc = sklearn.preprocessing.OneHotEncoder()
enc.fit(dataset.iloc[:,[0]])
onehotlabels = enc.transform(dataset.iloc[:,[0]]).toarray()
genders = pd.DataFrame({'Female': onehotlabels[:, 0], 'Male': onehotlabels[:, 1]})
result = pd.concat([genders,dataset.iloc[:,1:]], axis=1, sort=False)
result.head(5)
一旦转换完成,让我们再次查看数据集:
请注意,为了将变量从类别变量转换为连续变量,独热编码已将Gender
转换为两个单独的列——Male
和Female
。
指定特征和标签
让我们指定特征和标签。我们将使用y
来代表标签,X
代表特征集:
y=result['Purchased']
X=result.drop(columns=['Purchased'])
X
代表特征向量,包含我们需要用来训练模型的所有输入变量。
将数据集分为测试和训练部分
现在,让我们使用sklearn.model_selection import train_test_split
将训练数据集分为 25%的测试部分和 75%的训练部分:
#from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)
这已经创建了以下四个数据结构:
-
X_train
:包含训练数据特征的数据结构 -
X_test
:包含训练测试特征的数据结构 -
y_train
:包含训练数据集中标签值的向量 -
y_test
:包含测试数据集中标签值的向量
缩放特征
对于许多机器学习算法,将变量从0
到1
进行缩放是一个好的做法。这也被称为特征归一化。让我们应用缩放转换来实现这一点:
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
在我们缩放数据之后,它准备好作为输入用于我们将在后续部分中介绍的不同分类器。
评估分类器
模型训练完成后,我们需要评估其性能。为此,我们将使用以下过程:
-
我们将标签数据集分为两部分——训练部分和测试部分。我们将使用测试部分来评估训练好的模型。
-
我们将使用测试部分的特征来为每一行生成标签。这是我们的预测标签集。
-
我们将比较预测标签集与实际标签以评估模型。
除非我们试图解决的问题非常琐碎,否则在评估模型时会有一些错误分类。我们如何解释这些错误分类以确定模型的质量取决于我们选择使用的性能指标。
一旦我们有了实际标签集和预测标签集,就可以使用一系列性能指标来评估模型。用于量化模型的最佳指标将取决于我们想要解决的业务问题的要求,以及训练数据集的特征。
混淆矩阵
混淆矩阵用于总结对分类器的评估结果。二元分类器的混淆矩阵如下所示:
如果我们正在训练的分类器的标签有两个级别,则称为二元分类器。监督机器学习的第一个关键用例,特别是二元分类器,是在第一次世界大战期间用于区分飞机和飞行鸟。
分类可以分为以下四类:
-
真正例(TP):正确分类的正分类
-
真负例(TN):正确分类的负分类
-
假正例(FP):实际上是负分类的正分类
-
假阴性(FN):实际上是积极的负面分类
让我们看看如何使用这四个类别来创建各种性能指标。
性能指标
性能指标用于量化训练模型的性能。基于此,让我们定义以下四个指标:
指标 | 公式 |
---|---|
准确率 | ![]() |
召回率 | ![]() |
精度 | ![]() |
F1 分数 | ![]() |
准确率是所有预测中正确分类的比例。在计算准确率时,我们不区分 TP 和 TN。通过准确率评估模型是直接的,但在某些情况下,它不起作用。
让我们看看我们需要更多的东西来量化模型的性能的情况。其中之一是当我们使用模型来预测罕见事件时,比如以下的例子:
-
一个用于预测银行交易数据库中欺诈交易的模型
-
一个用于预测飞机发动机零部件机械故障可能性的模型
在这两个例子中,我们试图预测罕见事件。在这种情况下,比准确率更重要的是召回率和精度。让我们逐个来看:
-
召回率:这计算了命中率。在前面的例子中,它是模型成功标记的欺诈文件占所有欺诈文件的比例。如果在我们的测试数据集中有 100 万笔交易,其中有 100 笔被确认为欺诈交易,模型能够识别出 78 笔。在这种情况下,召回率值将是 78/100。
-
精度:精度衡量了模型标记的交易中实际上是坏的交易有多少。我们不是专注于模型未能标记的坏交易,而是想确定模型标记的坏交易有多精确。
请注意,F1 分数将召回率和精度结合在一起。如果一个模型的精度和召回率都是完美的,那么它的 F1 分数将是完美的。高 F1 分数意味着我们训练了一个高质量的模型,具有高召回率和精度。
理解过拟合
如果一个机器学习模型在开发环境中表现出色,但在生产环境中明显下降,我们说这个模型是过拟合的。这意味着训练模型过于密切地遵循训练数据集。这表明模型创建的规则中有太多细节。模型方差和偏差之间的权衡最能捕捉到这个概念。让我们逐个来看这些概念。
偏差
任何机器学习模型都是基于某些假设进行训练的。一般来说,这些假设是对一些真实世界现象的简化*似。这些假设简化了特征和特征特性之间的实际关系,并使模型更容易训练。更多的假设意味着更多的偏差。因此,在训练模型时,更简化的假设=高偏差,更符合实际现象的现实假设=低偏差。
在线性回归中,忽略了特征的非线性,并将它们*似为线性变量。因此,线性回归模型天生容易表现出高偏差。
方差
方差量化了模型在使用不同数据集训练时对目标变量的估计准确性。它量化了我们的模型的数学公式是否是底层模式的良好概括。
基于特定情景和情况的特定过拟合规则=高方差,而基于广泛情景和情况的泛化规则=低方差。
我们在机器学习中的目标是训练表现出低偏差和低方差的模型。实现这一目标并不总是容易的,通常会让数据科学家夜不能寐。
偏差-方差权衡
在训练特定的机器学习模型时,很难确定训练模型所包含的规则的正确泛化级别。为了找到正确的泛化级别而进行的挣扎被称为偏差-方差权衡。
请注意,更简化的假设=更泛化=低方差=高方差。
偏差和方差之间的权衡是由算法的选择、数据的特征和各种超参数决定的。根据您尝试解决的具体问题的要求,重要的是在偏差和方差之间取得正确的折衷。
指定分类器的阶段
一旦标记的数据准备好,分类器的开发包括训练、评估和部署。在以下图表中,CRISP-DM(数据挖掘的跨行业标准流程)生命周期展示了实施分类器的这三个阶段(CRISP-DM 生命周期在第五章*,图形算法中有更详细的解释)
在实施分类器的前两个阶段——测试和训练阶段,我们使用标记的数据。标记的数据被分成两个分区——一个更大的分区称为训练数据,一个更小的分区称为测试数据。使用随机抽样技术将输入的标记数据分成训练和测试分区,以确保两个分区都包含一致的模式。请注意,如前图所示,首先是训练阶段,使用训练数据来训练模型。训练阶段结束后,使用测试数据评估训练模型。不同的性能指标用于量化训练模型的性能。评估模型后,我们有模型部署阶段,其中训练好的模型被部署并用于推理,通过标记未标记的数据解决现实世界的问题。
现在,让我们看一些分类算法。
我们将在接下来的部分中看到以下分类算法:
-
决策树算法
-
XGBoost 算法
-
随机森林算法
-
逻辑回归算法
-
支持向量机(SVM)算法
-
朴素贝叶斯算法
让我们从决策树算法开始。
决策树分类算法
决策树基于递归分区方法(分而治之),生成一组规则,可用于预测标签。它从根节点开始,分成多个分支。内部节点表示对某个属性的测试,测试的结果由分支到下一级表示。决策树以包含决策的叶节点结束。当分区不再改善结果时,过程停止。
理解决策树分类算法
决策树分类的显著特点是生成可解释的层次规则,用于在运行时预测标签。该算法具有递归性质。创建这些规则层次涉及以下步骤:
-
找到最重要的特征:在所有特征中,算法确定了最能区分训练数据集中数据点的特征。计算基于信息增益或基尼不纯度等指标。
-
分叉:使用最重要的特征,算法创建一个标准,用于将训练数据集分成两个分支:
-
通过满足标准的数据点
-
未通过标准的数据点
-
检查叶节点:如果任何结果分支大多包含一个类的标签,则该分支被确定为最终分支,形成一个叶节点。
-
检查停止条件并重复:如果未满足提供的停止条件,则算法将返回到步骤 1进行下一次迭代。否则,模型被标记为已训练,并且结果决策树的每个最低级节点都被标记为叶节点。停止条件可以简单地定义为迭代次数,或者可以使用默认的停止条件,即一旦每个叶节点达到一定的同质性水*,算法就会停止。
决策树算法可以用以下图解释:
在上图中,根节点包含一堆圆圈和十字。该算法创建了一个标准,试图将圆圈与十字分开。在每个级别,决策树创建数据的分区,预期从第 1 级开始越来越同质。完美的分类器只包含只包含圆圈或十字的叶节点。由于训练数据集固有的随机性,训练完美的分类器通常很困难。
使用决策树分类算法进行分类器挑战
现在,让我们使用决策树分类算法来解决我们之前定义的常见问题,预测客户最终是否购买产品:
- 首先,让我们实例化决策树分类算法,并使用我们为分类器准备的训练部分数据来训练模型:
classifier = sklearn.tree.DecisionTreeClassifier(criterion = 'entropy', random_state = 100, max_depth=2)
classifier.fit(X_train, y_train)
- 现在,让我们使用我们训练好的模型来预测我们标记数据的测试部分的标签。让我们生成一个可以总结我们训练好的模型性能的混淆矩阵:
import sklearn.metrics as metrics
y_pred = classifier.predict(X_test)
cm = metrics.confusion_matrix(y_test, y_pred)
cm
这给出了以下输出:
- 现在,让我们通过使用决策树分类算法来计算所创建分类器的
准确率
、召回率
和精确度
值:
accuracy= metrics.accuracy_score(y_test,y_pred)
recall = metrics.recall_score(y_test,y_pred)
precision = metrics.precision_score(y_test,y_pred)
print(accuracy,recall,precision)
- 运行上述代码将产生以下输出:
性能指标帮助我们比较不同的训练建模技术。
决策树分类器的优势和劣势
在本节中,让我们看看使用决策树分类算法的优势和劣势。
优势
以下是决策树分类器的优势:
-
使用决策树算法创建的模型的规则可被人类解释。这样的模型被称为白盒模型。白盒模型是在需要追踪决策的细节和原因时的必要条件。这种透明性在我们想要防止偏见和保护脆弱社区的应用中至关重要。例如,在政府和保险行业的关键用例中,通常需要白盒模型。
-
决策树分类器旨在从离散问题空间中提取信息。这意味着大多数特征都是类别变量,因此使用决策树来训练模型是一个不错的选择。
劣势
以下是决策树分类器的弱点:
-
如果决策树分类器生成的树太深,规则会捕捉太多细节,导致过拟合的模型。在使用决策树算法时,我们需要意识到决策树容易过拟合,因此我们需要及时修剪树以防止这种情况。
-
决策树分类器的一个弱点是它们无法捕捉规则中的非线性关系。
用例
在本节中,让我们看看决策树算法用于哪些用例。
分类记录
决策树分类器可用于对数据点进行分类,例如以下示例:
-
抵押贷款申请:训练一个二元分类器,以确定申请人是否可能违约。
-
客户细分:将客户分类为高价值、中价值和低价值客户,以便为每个类别定制营销策略。
-
医学诊断:训练一个分类器,可以对良性或恶性生长进行分类。
-
治疗效果分析:训练一个分类器,可以标记对特定治疗产生积极反应的患者。
特征选择
决策树分类算法选择一小部分特征来创建规则。当特征数量很大时,可以使用该特征选择来选择另一个机器学习算法的特征。
理解集成方法
集成是一种机器学习方法,通过使用不同的参数创建多个略有不同的模型,然后将它们组合成一个聚合模型。为了创建有效的集成,我们需要找到我们的聚合标准,以生成最终模型。让我们看看一些集成算法。
使用 XGBoost 算法实现梯度提升
XGBoost 于 2014 年创建,基于梯度提升原理。它已成为最受欢迎的集成分类算法之一。它生成一堆相互关联的树,并使用梯度下降来最小化残差误差。这使其非常适合分布式基础设施,如 Apache Spark,或云计算,如 Google Cloud 或亚马逊网络服务(AWS)。
现在让我们看看如何使用 XGBoost 算法实现梯度提升:
- 首先,我们将实例化 XGBClassfier 分类器,并使用数据的训练部分来训练模型:
- 然后,我们将基于新训练的模型生成预测:
y_pred = classifier.predict(X_test)
cm = metrics.confusion_matrix(y_test, y_pred)
cm
产生以下输出:
- 最后,我们将量化模型的性能:
accuracy= metrics.accuracy_score(y_test,y_pred)
recall = metrics.recall_score(y_test,y_pred)
precision = metrics.precision_score(y_test,y_pred)
print(accuracy,recall,precision)
这给我们以下输出:
接下来,让我们看看随机森林算法。
使用随机森林算法
随机森林是一种集成方法,通过组合多个决策树来减少偏差和方差。
训练随机森林算法
在训练中,该算法从训练数据中获取N个样本,并创建我们整体数据的m个子集。这些子集是通过随机选择输入数据的一些行和列来创建的。该算法构建m个独立的决策树。这些分类树由C[1]
到C[m]
表示。
使用随机森林进行预测
模型训练完成后,可以用于标记新数据。每个个体树生成一个标签。最终预测由这些个体预测的投票决定,如下所示:
请注意,在上图中,训练了m棵树,表示为C[1]
到C[m]
。即树 = {C[1],..,C[m]}
每棵树生成一个由一组表示的预测:
个体预测 = P= {P[1],..., P[m]}
最终预测由P[f]
表示。它由个体预测的大多数决定。mode
函数可用于找到多数决定(mode
是最常重复且处于多数的数字)。个体预测和最终预测如下所示:
P[f] = mode (P)
区分随机森林算法和集成提升
随机森林算法生成的每棵树都是完全独立的。它不知道集成中其他树的任何细节。这使它与其他技术有所不同,如集成增强。
使用随机森林算法进行分类器挑战
让我们实例化随机森林算法,并使用它来训练我们的模型使用训练数据。
这里有两个关键的超参数:
-
n_estimators
-
max_depth
n_estimators
超参数控制构建多少个独立的决策树,max_depth
超参数控制每个独立决策树可以有多深。
换句话说,决策树可以不断分裂,直到它有一个节点代表训练集中的每个给定示例。通过设置max_depth
,我们限制了它可以进行多少级别的分裂。这控制了模型的复杂性,并确定了它与训练数据的拟合程度。如果我们参考以下输出,n_estimators
控制了随机森林模型的宽度,max_depth
控制了模型的深度:
一旦随机森林模型训练好了,让我们用它进行预测:
y_pred = classifier.predict(X_test)
cm = metrics.confusion_matrix(y_test, y_pred)
cm
它的输出是:
现在,让我们量化我们的模型有多好:
accuracy= metrics.accuracy_score(y_test,y_pred)
recall = metrics.recall_score(y_test,y_pred)
precision = metrics.precision_score(y_test,y_pred)
print(accuracy,recall,precision)
我们将观察以下输出:
接下来,让我们来看看逻辑回归。
逻辑回归
逻辑回归是一种用于二元分类的分类算法。它使用逻辑函数来制定输入特征和目标变量之间的交互。它是用于建模二元因变量的最简单的分类技术之一。
假设
逻辑回归假设以下内容:
-
训练数据集没有缺失值。
-
标签是一个二进制类别变量。
-
标签是有序的,换句话说,是一个具有有序值的分类变量。
-
所有特征或输入变量彼此独立。
建立关系
对于逻辑回归,预测值计算如下:
假设。
所以现在:
上述关系可以用图形表示如下:
注意,如果z很大,σ (z)将等于1
。如果z非常小或非常负,σ (z)将等于0
。因此,逻辑回归的目标是找到W和j的正确值。
逻辑回归是根据用于制定它的函数命名的,称为逻辑或Sigmoid 函数。
损失和成本函数
loss
函数定义了我们想要量化训练数据中特定示例的错误的方式。cost
函数定义了我们想要最小化整个训练数据集中的错误的方式。因此,loss
函数用于训练数据集中的一个示例,cost
函数用于量化实际值和预测值的整体偏差。它取决于w和h的选择。
逻辑回归中使用的loss
函数如下:
Loss (ý^((i)), y^((i))) = - (y^((i))log ý((i))+(1-y((i)) ) log (1-ý^((i)))
注意当*y^((i)) = 1, Loss(ý^((i)), y^((i))**) = - logý((i))*.最小化损失将导致ý((i))的值很大。作为 Sigmoid 函数,最大值将是1
。
如果y^((i)) = 0, Loss (ý^((i)), y^((i))) = - log (1-ý((i))**)*。最小化损失将导致*ý((i))尽可能小,即0
。
逻辑回归的成本函数如下:
何时使用逻辑回归
逻辑回归在二元分类器方面表现出色。当数据量很大但数据质量不佳时,逻辑回归效果不佳。它可以捕捉不太复杂的关系。虽然它通常不会产生最佳性能,但它确实为起步设定了一个很好的基准。
使用逻辑回归算法进行分类器挑战
在本节中,我们将看到如何使用逻辑回归算法进行分类器挑战:
- 首先,让我们实例化一个逻辑回归模型,并使用训练数据对其进行训练:
from sklearn.linear_model import LogisticRegression
classifier = LogisticRegression(random_state = 0)
classifier.fit(X_train, y_train)
- 让我们预测
test
数据的值并创建一个混淆矩阵:
y_pred = classifier.predict(X_test)
cm = metrics.confusion_matrix(y_test, y_pred)
cm
运行上述代码后,我们得到以下输出:
- 现在,让我们看看性能指标:
accuracy= metrics.accuracy_score(y_test,y_pred)
recall = metrics.recall_score(y_test,y_pred)
precision = metrics.precision_score(y_test,y_pred)
print(accuracy,recall,precision)
- 运行上述代码后,我们得到以下输出:
接下来,让我们看看SVM。
SVM 算法
现在,让我们看看 SVM。SVM 是一种找到最大化两个类之间间隔的最优超*面的分类器。在 SVM 中,我们的优化目标是最大化间隔。间隔被定义为分隔超*面(决策边界)与最靠*该超*面的训练样本之间的距离,称为支持向量。因此,让我们从一个只有两个维度X1和X2的非常基本的例子开始。我们希望有一条线将圆圈与十字分开。如下图所示:
我们画了两条线,都完美地将十字与圆圈分开。然而,必须有一个最佳线或决策边界,使我们有最佳机会正确分类大多数额外的例子。一个合理的选择可能是一条均匀分布在这两个类之间的线,为每个类提供一点缓冲,如下所示:
现在,让我们看看如何使用 SVM 来训练我们挑战的分类器。
使用 SVM 算法进行分类器挑战
- 首先,让我们实例化 SVM 分类器,然后使用标记数据的训练部分对其进行训练。
kernel
超参数确定应用于输入数据的转换类型,以使其线性可分。
from sklearn.svm import SVC
classifier = SVC(kernel = 'linear', random_state = 0)
classifier.fit(X_train, y_train)
- 训练完成后,让我们生成一些预测并查看混淆矩阵:
y_pred = classifier.predict(X_test)
cm = metrics.confusion_matrix(y_test, y_pred)
cm
- 观察以下输出:
- 现在,让我们来看看各种性能指标:
accuracy= metrics.accuracy_score(y_test,y_pred)
recall = metrics.recall_score(y_test,y_pred)
precision = metrics.precision_score(y_test,y_pred)
print(accuracy,recall,precision)
运行上述代码后,我们得到以下值作为输出:
理解朴素贝叶斯算法
基于概率论,朴素贝叶斯是最简单的分类算法之一。如果使用正确,它可以得出准确的预测。朴素贝叶斯算法之所以被如此命名有两个原因:
-
它基于一个天真的假设,即特征和输入变量之间是独立的。
-
它基于贝叶斯定理。
该算法试图基于先前属性/实例的概率对实例进行分类,假设属性完全独立。
有三种类型的事件:
-
独立事件不会影响另一个事件发生的概率(例如,收到一封电子邮件提供免费参加科技活动的机会和公司进行重新组织)。
-
依赖事件会影响另一个事件发生的概率;也就是说,它们在某种程度上是相关的(例如,你准时参加会议的概率可能会受到航空公司员工罢工或航班不准时的影响)。
-
互斥事件不能同时发生(例如,单次掷骰子得到三和六的概率为 0——这两个结果是互斥的)。
贝叶斯定理
贝叶斯定理用于计算两个独立事件A和B之间的条件概率。事件A和B发生的概率由 P(A)和 P(B)表示。条件概率由 P(B|A)表示,这是事件A发生的条件概率,假设事件B已经发生:
计算概率
朴素贝叶斯基于概率基本原理。单个事件发生的概率(观察概率)是通过将事件发生的次数除以可能导致该事件发生的总进程次数来计算的。例如,呼叫中心每天接到 100 多个支持电话,一个月内有 50 次。您想知道基于以前的响应时间,呼叫在 3 分钟内得到响应的概率。如果呼叫中心在 27 次匹配这个时间记录,那么 100 次呼叫在 3 分钟内得到响应的观察概率如下:
- P(3 分钟内 100 个支持电话)=(27/50)= 0.54(54%)*
根据过去的 50 次记录,100 次呼叫大约有一半的时间可以在 3 分钟内得到响应。
AND 事件的乘法规则
要计算两个或更多事件同时发生的概率,请考虑事件是独立还是相关的。如果它们是独立的,则使用简单的乘法规则:
- P(结果 1 和结果 2)= P(结果 1)* P(结果 2)*
例如,要计算收到免费参加技术活动的电子邮件的概率和工作场所发生重新组织的概率,将使用这个简单的乘法规则。这两个事件是独立的,因为其中一个发生并不影响另一个发生的机会
如果收到技术活动的电子邮件的概率为 31%,并且员工重新组织的概率为 82%,则同时发生的概率如下计算:
P(电子邮件和重新组织)= P(电子邮件)* P(重新组织)=(0.31)*(0.82)= 0.2542(25%)
一般乘法规则
如果两个或更多事件是相关的,则使用一般乘法规则。这个公式实际上在独立和相关事件的情况下都是有效的:
- P(结果 1 和结果 2)= P(结果 1)* P(结果 2 | 结果 1)*
请注意,P(结果 2 | 结果 1)
指的是结果 1
已经发生的情况下结果 2
发生的条件概率。该公式包含了事件之间的依赖关系。如果事件是独立的,那么条件概率是无关紧要的,因为一个结果不会影响另一个发生的机会,P(结果 2 | 结果 1)
就是P(结果 2)
。请注意,在这种情况下,该公式变成了简单的乘法规则。
OR 事件的加法规则
在计算两个事件中的一个或另一个发生的概率(互斥)时,使用以下简单的加法规则:
- P(结果 1 或结果 2)= P(结果 1)+ P(结果 2)*
例如,掷出 6 或 3 的概率是多少?要回答这个问题,首先注意到两个结果不能同时发生。掷出 6 的概率是(1/6),掷出 3 的概率也是如此:
- P(6 或 3)=(1/6)+(1/6)= 0.33(33%)*
如果事件不是互斥的并且可以同时发生,请使用以下一般加法公式,这在互斥和非互斥的情况下都是有效的:
- P(结果 1 或结果 2)= P(结果 1)+ P(结果 2)P(结果 1 和结果 2)*
使用朴素贝叶斯算法进行分类器挑战
现在,让我们使用朴素贝叶斯算法来解决分类器挑战:
- 首先,我们导入
GaussianNB()
函数并用它来训练模型:
from sklearn.naive_bayes import GaussianNB
classifier = GaussianNB()
classifier.fit(X_train, y_train)
- 现在,让我们使用训练好的模型来预测结果。我们将用它来预测我们的测试分区
X_test
的标签:
Predicting the Test set results
y_pred = classifier.predict(X_test)
cm = metrics.confusion_matrix(y_test, y_pred)
cm
- 现在,让我们打印混淆矩阵:
- 现在,让我们打印性能矩阵来量化我们训练模型的质量:
accuracy= metrics.accuracy_score(y_test,y_pred)
recall = metrics.recall_score(y_test,y_pred)
precision = metrics.precision_score(y_test,y_pred)
print(accuracy,recall,precision)
这将产生以下输出:
对于分类算法,获胜者是...
让我们看一下我们提出的各种算法的性能指标。这在下表中总结如下:
算法 | 准确度 | 召回率 | 精确度 |
---|---|---|---|
决策树 | 0.94 | 0.93 | 0.88 |
XGBoost | 0.93 | 0.90 | 0.87 |
随机森林 | 0.93 | 0.90 | 0.87 |
逻辑回归 | 0.91 | 0.81 | 0.89 |
支持向量机 | 0.89 | 0.71 | 0.92 |
朴素贝叶斯 | 0.92 | 0.81 | 0.92 |
从前面的表中可以看出,决策树分类器在准确性和召回率方面表现最佳。如果我们寻求精确度,那么支持向量机和朴素贝叶斯之间存在*局,因此任何一个都适用于我们。
了解回归算法
监督机器学习模型使用回归算法之一,如果目标变量是连续变量。在这种情况下,机器学习模型被称为回归器。
在本节中,我们将介绍各种可用于训练监督机器学习回归模型的算法,或者简单地说,回归器。在我们深入了解算法的细节之前,让我们首先为这些算法创建一个挑战,以测试它们的性能、能力和有效性。
呈现回归器挑战
与分类算法使用的方法类似,我们将首先提出一个问题,作为所有回归算法的挑战来解决。我们将把这个共同的问题称为回归器挑战。然后,我们将使用三种不同的回归算法来解决这个挑战。使用一个共同的挑战来测试不同的回归算法有两个好处:
-
我们可以准备一次数据,然后在所有三个回归算法上使用准备好的数据。
-
我们可以以有意义的方式比较三种回归算法的性能,因为我们将使用它们来解决同一个问题。
让我们看一下挑战的问题陈述。
回归器挑战的问题陈述
预测不同车辆的里程数在当今是很重要的。高效的车辆对环境有益,也具有成本效益。里程数可以根据发动机功率和车辆特性来估算。让我们为回归器创建一个挑战,训练一个能够根据车辆特性预测车辆的每加仑英里数(MPG)的模型。
让我们看看我们将用来训练回归器的历史数据集。
探索历史数据集
以下是我们拥有的历史数据集数据的特征:
名称 | 类型 | 描述 |
---|---|---|
名称 |
类别 | 标识特定车辆 |
CYLINDERS |
连续 | 气缸数量(4 至 8 之间) |
DISPLACEMENT |
连续 | 发动机排量(立方英寸) |
HORSEPOWER |
连续 | 发动机马力 |
ACCELERATION |
连续 | 从 0 到 60 英里/小时的加速时间(秒) |
这个问题的目标变量是一个连续变量,MPG
,它指定了每辆车的英里数。
让我们首先为这个问题设计数据处理管道。
使用数据处理管道进行特征工程
让我们看看如何设计一个可重复使用的处理管道来解决回归器挑战。如前所述,我们将一次准备数据,然后在所有回归算法中使用它。让我们按照以下步骤进行:
- 我们首先导入数据集,如下所示:
dataset = pd.read_csv('auto.csv')
- 现在让我们预览数据集:
dataset.head(5)
数据集将如下所示:
- 现在,让我们继续进行特征选择。让我们删除
NAME
列,因为它只是一个用于汽车的标识符。用于识别数据集中行的列对于训练模型是不相关的。让我们删除这一列:
dataset=dataset.drop(columns=['NAME'])
- 让我们转换所有的输入变量并填充所有的空值:
dataset=dataset.drop(columns=['NAME'])
dataset= dataset.apply(pd.to_numeric, errors='coerce')
dataset.fillna(0, inplace=True)
填充提高了数据的质量,并准备好用于训练模型。现在,让我们看最后一步:
- 让我们将数据分成测试和训练分区:
from sklearn.model_selection import train_test_split
#from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)
这创建了以下四个数据结构:
-
X_train
:包含训练数据的特征的数据结构 -
X_test
:包含训练测试的特征的数据结构 -
y_train
:包含训练数据集中标签的值的向量 -
y_test
:包含测试数据集中标签的值的向量
现在,让我们使用准备好的数据在三个不同的回归器上,以便比较它们的性能。
线性回归
在所有监督学习技术中,线性回归算法是最容易理解的。我们首先看一下简单线性回归,然后将概念扩展到多元线性回归。
简单线性回归
在其最简单的形式中,线性回归阐述了单个连续自变量和单个连续自变量之间的关系。回归用于显示因变量(显示在 y 轴上)的变化程度可以归因于解释变量(显示在 x 轴上)的变化程度。它可以表示如下:
这个公式可以解释如下:
-
y 是因变量。
-
X 是自变量。
-
是斜率,表示每增加一个 X,线就上升多少。
-
α 是截距,表示 X = 0 时 y 的值。
单个连续因变量和单个连续自变量之间关系的一些例子如下:
-
一个人的体重和他们的卡路里摄入量
-
特定社区房屋价格和面积
-
空气中的湿度和下雨的可能性
对于线性回归,输入(自变量)和目标(因变量)变量都必须是数值型的。最佳关系是通过最小化每个点到通过所有点的线的垂直距离的*方和来找到的。假设预测变量和目标变量之间是线性关系。例如,投入研发的资金越多,销售额就越高。
让我们看一个具体的例子。让我们尝试阐明特定产品的营销支出和销售之间的关系。它们被发现直接相关。营销支出和销售在二维图上绘制,并显示为蓝色的钻石。这种关系最好通过绘制一条直线来*似,如下图所示:
一旦画出线性线,我们就可以看到营销支出和销售之间的数学关系。
评估回归器
我们画的线性线是因变量和自变量之间关系的*似值。即使最佳线也会与实际值有一些偏差,如下所示:
评估线性回归模型性能的一种典型方法是使用均方根误差(RMSE)。这通过数学计算训练模型产生的误差的标准偏差。对于训练数据集中的某个示例,loss
函数计算如下:
损失(ý^((i)), y^((i))) = 1/2(ý^((i)-) y^((i)))²
这导致以下cost
函数,最小化训练集中所有示例的损失:
让我们尝试解释 RMSE。如果我们的示例模型的 RMSE 为$50,这意味着大约 68.2%的预测值将在真实值(即α)的100(即 2α)范围内。最后,99.7%的预测值将在实际值的$150 范围内。
多元回归
事实上,大多数现实世界的分析都有多个自变量。多元回归是简单线性回归的扩展。关键区别在于额外的预测变量有额外的 beta 系数。在训练模型时,目标是找到最小化线性方程误差的 beta 系数。让我们尝试数学上阐述因变量和一组自变量(特征)之间的关系。
与简单线性方程类似,因变量y被量化为截距项的总和,加上β系数乘以每个i特征的x值:
y = α + β [1] x [1] + β [2] x 2 +...+ β [i] x [i] + ε
误差用ε表示,表明预测并不完美。
β系数允许每个特征对y的值有单独的估计影响,因为y每增加一个单位的x[i],y的变化量为β [i]。此外,截距(α)表示当独立变量都为 0 时y的期望值。
请注意,前述方程中的所有变量都可以用一堆向量表示。目标和预测变量现在是带有行的向量,而回归系数β和误差ε也是向量。
使用线性回归算法进行回归挑战
现在,让我们使用数据集的训练部分来训练模型:
- 让我们从导入线性回归包开始:
from sklearn.linear_model import LinearRegression
- 然后,让我们实例化线性回归模型,并使用训练数据集对其进行训练:
regressor = LinearRegression()
regressor.fit(X_train, y_train)
- 现在,让我们使用数据集的测试部分来预测结果:
y_pred = regressor.predict(X_test)
from sklearn.metrics import mean_squared_error
from math import sqrt
sqrt(mean_squared_error(y_test, y_pred))
- 运行上述代码生成的输出将生成以下内容:
如前一节所讨论的,RMSE 是误差的标准差。它表明 68.2%的预测值将在目标变量值的4.36
范围内。
何时使用线性回归?
线性回归用于解决许多现实世界的问题,包括以下内容:
-
销售预测
-
预测最佳产品价格
-
量化事件和响应之间的因果关系,例如临床药物试验、工程安全测试或市场研究
-
识别可用于预测未来行为的模式,给定已知条件,例如预测保险索赔、自然灾害损失、选举结果和犯罪率
线性回归的弱点
线性回归的弱点如下:
-
它只适用于数值特征。
-
分类数据需要进行预处理。
-
它无法很好地处理缺失数据。
-
它对数据做出假设。
回归树算法
回归树算法类似于分类树算法,只是目标变量是连续变量,而不是类别变量。
使用回归树算法进行回归挑战
在本节中,我们将看到如何使用回归树算法进行回归挑战:
- 首先,我们使用回归树算法训练模型:
- 一旦回归树模型训练完成,我们就可以使用训练好的模型来预测值:
y_pred = regressor.predict(X_test)
- 然后,我们计算 RMSE 来量化模型的性能:
from sklearn.metrics import mean_squared_error
from math import sqrt
sqrt(mean_squared_error(y_test, y_pred))
我们得到以下输出:
梯度提升回归算法
现在,让我们来看看梯度提升回归算法。它使用一组决策树来更好地表达数据中的潜在模式。
使用梯度提升回归算法来解决回归问题
在这一部分,我们将看到如何使用梯度提升回归算法来解决回归问题:
- 首先,我们使用梯度提升回归算法来训练模型:
- 一旦梯度回归算法模型被训练,我们就可以用它来预测数值:
y_pred = regressor.predict(X_test)
- 最后,我们计算 RMSE 来量化模型的性能:
from sklearn.metrics import mean_squared_error
from math import sqrt
sqrt(mean_squared_error(y_test, y_pred))
- 运行这个将给我们输出值,如下所示:
对于回归算法,获胜者是...
让我们来看看我们在相同数据和完全相同用例上使用的三种回归算法的表现:
算法 | RMSE |
---|---|
线性回归 | 4.36214129677179 |
回归树 | 5.2771702288377 |
梯度提升回归 | 4.034836373089085 |
从所有回归算法的表现来看,很明显梯度提升回归的表现最好,因为它具有最低的 RMSE。其次是线性回归。对于这个问题,回归树算法的表现最差。
实际例子 - 如何预测天气
让我们看看如何使用本章中开发的概念来预测天气。假设我们想根据一年内针对特定城市收集的数据来预测明天是否会下雨。
用于训练该模型的数据在名为weather.csv
的 CSV 文件中:
- 让我们将数据导入为一个 pandas 数据框:
import numpy as np
import pandas as pd
df = pd.read_csv("weather.csv")
- 让我们来看看数据框的列:
- 接下来,让我们来看一下
weather.csv
数据的前 13 列的标题:
- 现在,让我们来看一下
weather.csv
数据的最后 10 列:
- 让我们用
x
来代表输入特征。我们将在特征列表中删除Date
字段,因为在预测的情境下它没有用处。我们还将删除RainTomorrow
标签:
x = df.drop(['Date','RainTomorrow'],axis=1)
- 让我们用
y
来代表标签:
y = df['RainTomorrow']
- 现在,让我们将数据分成
train_test_split
:
from sklearn.model_selection import train_test_split
train_x , train_y ,test_x , test_y = train_test_split(x,y , test_size = 0.2,random_state = 2)
- 由于标签是一个二元变量,我们正在训练一个分类器。因此,在这里逻辑回归将是一个不错的选择。首先,让我们实例化逻辑回归模型:
model = LogisticRegression()
- 现在,我们可以使用
train_x
和test_x
来训练模型:
model.fit(train_x , test_x)
- 一旦模型被训练,让我们用它进行预测:
predict = model.predict(train_y)
- 现在,让我们找出我们训练模型的准确性:
现在,这个二元分类器可以用来预测明天是否会下雨。
摘要
在本章中,我们首先了解了监督式机器学习的基础知识。然后,我们更详细地了解了各种分类算法。接下来,我们研究了评估分类器性能的不同方法,并研究了各种回归算法。我们还研究了用于评估我们研究的算法性能的不同方法。
在下一章中,我们将研究神经网络和深度学习算法。我们将研究训练神经网络所使用的方法,还将研究用于评估和部署神经网络的各种工具和框架。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [翻译] 为什么 Tracebit 用 C# 开发
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· RFID实践——.NET IoT程序读取高频RFID卡/标签
2023-04-16 精通 Sklearn 和 TensorFlow 预测性分析:1~5 全
2023-04-16 Python 智能项目:6~10
2023-04-16 Python 智能项目:1~5
2023-04-16 Python 强化学习实用指南:11~14
2023-04-16 Python 强化学习实用指南:6~10
2023-04-16 Python 强化学习实用指南:1~5
2023-04-16 Python 元学习实用指南:6~10