HKUST-数据挖掘知识发现笔记-全-
HKUST 数据挖掘知识发现笔记(全)
001:课程概览 🗺️

在本节课中,我们将对《数据挖掘与知识发现》这门课程进行整体概览。我们将了解课程的基本信息、参考书籍,并初步认识数据挖掘的五大核心主题。
本课程是香港科技大学的一门课程。主要的参考书籍包括论文以及两本教材:《数据挖掘:概念与技术》和《数据挖掘导论》。
五大主题介绍
接下来,我们将逐一介绍本课程涵盖的五个主要主题。
1. 关联分析
关联分析旨在发现数据集中项之间的有趣关系。一个经典的例子是超市购物篮分析。
假设我们有三位顾客:Raymond、Aid 和 Grace。他们的购物记录如下:
- Raymond 购买了苹果和橙子。
- Aid 购买了橙子和牛奶。
- Grace 购买了苹果和橙子。
我们可以统计商品的出现频率。例如,苹果被购买了2次,橙子被购买了3次,而“苹果和橙子”这个组合被购买了2次。如果我们设定一个最小频率(例如2次),那么满足条件的商品或商品组合被称为频繁项集。
关联分析的另一个重要输出是关联规则,其形式为 X -> Y(例如,苹果 -> 橙子)。规则 苹果 -> 橙子 的置信度计算如下:在所有购买了苹果的顾客中,也购买了橙子的顾客比例。在这个例子中,购买苹果的顾客有2位(Raymond 和 Grace),其中2位也购买了橙子,因此置信度为 2/2 = 100%。同理,规则 橙子 -> 苹果 的置信度为 2/3 ≈ 67%。本主题的目标就是找出所有频繁项集和有意义的关联规则。
2. 聚类分析
上一节我们介绍了如何发现项之间的关联,本节我们来看看如何将相似的对象分组。聚类是一种无监督学习方法,目的是将数据点分组成不同的簇,使得同一簇内的点彼此相似,而不同簇的点相异。
假设我们有三位学生:Raymond、Lewis 和 Wman。他们的计算机科目和历史科目成绩如下:
- Raymond: 计算机 100分,历史 40分。
- Lewis: 计算机 20分,历史 90分。
- Wman: 计算机 10分,历史 80分。
如果我们将这些成绩绘制在二维坐标系中(X轴为计算机成绩,Y轴为历史成绩),每个学生对应一个点。我们可以直观地看到数据点形成了两个组:一组计算机成绩高、历史成绩低;另一组历史成绩高、计算机成绩低。聚类的任务就是自动地发现这些分组(簇)。
3. 分类分析
在了解了如何对无标签数据进行分组后,本节我们学习如何根据已有数据对新的对象进行预测。分类是一种有监督学习方法,用于预测离散的类别标签。
假设一家保险公司想要预测一位新客户是否会购买保险单。已知该客户的属性为:种族=白人,收入=高,有无子女=无。公司根据历史数据训练出了一个决策树模型。
以下是使用决策树进行预测的步骤:
- 从根节点开始,检查“有无子女”属性。该客户“无”子女,因此走向右子节点。
- 在下一个节点,检查“收入”属性。该客户收入“高”,因此走向左子节点。
- 到达叶节点,该节点显示预测结果为“是”(购买保险)的概率为100%。
因此,模型预测这位客户会购买保险单。决策树是分类方法中的一种,我们将在后续课程中学习更多细节。
4. 数据仓库
前面介绍的都是数据挖掘的具体技术,本节我们来看一个提升数据查询效率的系统概念——数据仓库。当数据库非常庞大且查询非常复杂时,直接查询可能需要很长的响应时间(例如一天到一周),用户体验很差。
数据仓库的核心思想是预计算。系统会预先估计用户可能提出的复杂查询,提前执行这些查询并将结果存储在硬盘上。这个存储预计算结果的系统就是数据仓库。
例如,查询1:“找出所有就读于UST大学、学习大数据专业并住在UST校园的学生。” 这是一个复杂查询。数据仓库会提前计算好这个查询的结果(假设结果是Raymond, Peter, Mary),并存储起来。
当用户真正提交这个查询时,系统无需重新进行复杂的计算,而是直接从数据仓库中检索已存储的结果,从而在极短时间(如一秒内)返回答案,大大提升了查询性能。
5. 网络数据库
最后,我们探讨一个与互联网紧密相关的主题——网络数据库,其典型应用是搜索引擎(如Google)的网页排名。
当我们搜索“Raymond Wong”时,搜索引擎会返回一系列相关的网页。本课程将学习搜索引擎如何对这些网页进行排序。了解网页排名算法非常重要,例如,如果你毕业后创业,你会希望自己公司的网站在相关搜索中能排在结果页的前列,而无需向搜索引擎支付广告费用。通过学习这些知识,你可以优化网站,使其更符合排名规则,从而获得更好的自然搜索排名。
课程总结
本节课我们一起学习了《数据挖掘与知识发现》课程的概览。我们介绍了课程的五⼤核心主题:
- 关联分析:发现数据集中项之间的有趣联系,如频繁项集和关联规则。
- 聚类分析:将相似的数据对象自动分组。
- 分类分析:根据已有数据构建模型,用于预测新数据的类别。
- 数据仓库:通过预计算和存储查询结果来优化复杂查询的性能。
- 网络数据库:理解搜索引擎的网页排名原理。



这些主题构成了数据挖掘领域的基础,在后续课程中我们将对每个主题进行深入探讨。
002:关联规则挖掘导论

在本节课中,我们将学习关联规则挖掘的基本概念。这是一种从数据中发现物品之间有趣关联的技术,例如在超市购物数据中发现“尿布”和“啤酒”经常被一起购买。我们将通过一个超市场景的例子来理解其核心思想,并探讨其在不同领域的应用。
超市场景示例
上一节我们介绍了数据挖掘的基本概念,本节中我们来看看一个具体的应用场景——关联规则挖掘。
这是一个超市场景。我们知道有四位顾客:Raymond、David、Emily 和 Derek。
我们知道 Raymond 购买了苹果、可乐、咖啡。其中每一样东西被称为一个项。
顾客在某个时间点购买的所有东西,我们称之为一次历史记录或交易。
David 购买了尿布(婴儿用品)和可乐。
Emily 购买了牛奶和饼干。
Derek 购买了可乐和牛奶。
在这个主题中,我们想要发现物品之间的一些关联。我想告诉大家的是,我们可以发现一个有趣的关联:尿布(婴儿用品)和啤酒(成人饮品)经常被一起购买。
这看起来很奇怪。你能猜出原因吗?
一种可能的解释是,一些父亲不想照顾婴儿,所以他们想喝点啤酒来释放压力。这是一个合理的解释。
另一个由其他人给出的解释是:这个模式经常在工作日傍晚出现。白天,父亲在办公室工作。傍晚下班时,他记得早上妻子嘱咐他要为婴儿买尿布。当然,当他离开办公室寻找尿布时,也会顺便购买他喜欢的啤酒。因此,尿布和啤酒通常会一起被购买。
超市经理的策略
假设我是一名超市经理。如果我们知道尿布和啤酒总是一起被购买,你知道我应该做什么促销吗?
以下是可能的策略:
- 将尿布和啤酒放在相近的位置。
- 进行捆绑促销,例如购买尿布时啤酒打折。
另一种策略是,将尿布和啤酒放在超市里相距很远的位置。这样,当丈夫购买其中一样后,为了找到另一样,他需要走过很长的路程,途中可能会看到并购买其他商品。这与宜家的策略类似。
也有人认为,如果这两样商品总是一起购买,那么提供折扣可能会降低超市的收入。相反,可以提供“购买这两样商品,免费获得另一样商品”的促销来提升销售额。
不同的人对此有不同的策略和想法。最重要的是,超市经理可以根据发现的模式来设计促销方案。
关联规则挖掘的应用
现在让我们看看关联规则挖掘的一些应用。我已经阐述了一个关于超市经理的真实例子。我认为这已经很清楚了。接下来,我将举例说明,以便你理解这项技术在现代的广泛应用。
网络挖掘
例如,当你使用谷歌或百度时,实际上网络挖掘也在使用关联规则挖掘技术。
假设我在谷歌搜索“电脑”。你可以看到“电脑”和“尺寸”、“电脑”和“显示器”等关联词。实际上,你可以将这些词视为项。这些项在所有互联网网页文档中频繁共同出现。因此,“计算机科学”是最频繁的项,“大数据”是第二频繁的项。如果你输入“大数据”,你会看到“大数据分析”等。实际上,谷歌和百度也在使用关联规则挖掘技术进行推荐,只是你可能没有发现。
医学分析

在医学分析中,例如当前的情况,假设我们有病人 Raymond,我们知道他的性别是男性,我们还知道关于 Raymond 的其他信息,比如他是否吸烟等。我们有许多与 Raymond 相关的属性。同时,我们知道这位病人是否患有肺癌。我们还有病人 Mary,女性,吸烟等,可能她没有患肺癌。我们拥有大量记录。在关联规则挖掘中,我们可以发现某些属性之间的相关性,例如吸烟与癌症之间的相关性。这对于理解医学分析中的相关性非常容易。
生物信息学
在生物信息学中,情况也类似。例如,我们有病人 Mary,这次我们有一些 DNA 数据。在生物信息学中,人们已经发现某些基因与某些癌症相关。这就是生物信息学中的关联规则挖掘。
网络分析
在网络分析中,例如拒绝服务攻击,可能有些同学不了解。让我解释一下,这是攻击者使用的一种行为。假设我们有一个网络服务器或邮件服务器。如果我是攻击者,我不喜欢这个服务器,我想让它瘫痪,那么我会发起拒绝服务攻击。我的意思是,作为攻击者,我向服务器发送大量流量,导致服务器无法处理如此多的流量,从而使服务器瘫痪。攻击者的这种行为被称为拒绝服务攻击。我想说的是,在网络流量中,我们知道当攻击者向服务器发送数据时,我们使用的是数据包。数据包包含源 IP 地址和目标 IP 地址。源 IP 地址是攻击者的 IP 地址,目标地址是目标服务器的 IP 地址。因此,在服务器端,如果我们发现大量来自同一源地址的数据包频繁到达,那么这个源地址就会被识别为攻击者,服务器将屏蔽来自该攻击者的所有访问。
程序模式发现
程序模式发现也非常容易,但我不想详述程序一、程序二、程序三等细节。根据一些机器学习和数据挖掘技术,我们可以提取一些特征,如特征一、特征二、特征三。基于这些,我们可以发现某些特征之间的相关性,例如某些人的写作风格特征,然后根据这些模式进行一些分析。


本节课中我们一起学习了关联规则挖掘的基本概念。我们通过一个超市购物篮的例子,理解了如何从交易数据中发现物品之间的关联(如“尿布 -> 啤酒”)。我们还探讨了超市经理如何利用这些发现制定营销策略,并了解了关联规则挖掘在网络搜索、医学分析、生物信息学和网络安全等多个领域的广泛应用。关联规则挖掘的核心在于从大量数据中自动发现有价值的、潜在有用的模式。
003:基本概念

在本节课中,我们将要学习关联规则挖掘的基本概念。我们将从超市购物篮分析的经典场景出发,逐步定义项目、项目集、支持度、置信度等核心术语,并理解如何发现“有趣”的关联规则。最后,我们会探讨解决此问题的两种方法,并理解为什么寻找频繁项集是计算上的难点。
问题定义与核心概念
上一节我们介绍了关联规则挖掘的应用场景。本节中,我们来看看如何形式化地定义这个问题。


首先,我们用一个简化的交易数据表来表示超市场景。每一行代表一位顾客的一次交易(Transaction),每一列代表一个商品(Item)。如果某次交易包含了某个商品,则在对应位置标记为1。

以下是交易数据的另一种表示形式(项目列表表示法):
- Transaction 1: A, D
- Transaction 2: A, B, D
- Transaction 3: B, C
- Transaction 4: A, B, C
- Transaction 5: B, C
现在,我们来定义一些核心概念:
- 项目(Item):指单个商品,例如 A, B, C, D, E。
- 项目集(Itemset):指一个或多个项目的集合。例如
{A},{B, C},{A, B, C}。包含k个项目的集合称为k-项集。 - 支持度(Support):一个项目集的支持度定义为包含该项目集的事务总数。
- 公式:
support(X) = count(transactions containing X) - 例如:
support({B}) = 4(事务2, 3, 4, 5包含B)。support({B, C}) = 3(事务3, 4, 5同时包含B和C)。
- 公式:
- 频繁项集 / 大项集(Frequent Itemset / Large Itemset):指支持度不低于用户给定阈值(例如
min_sup = 3)的项目集。- 例如:给定
min_sup = 3,则{B}(支持度4)和{B, C}(支持度3)是频繁项集,而{A, B, C}(支持度1)不是。
- 例如:给定
- 关联规则(Association Rule):形如
X -> Y的表达式,其中X和Y是不相交的项目集。X称为规则前件(左部),Y称为规则后件(右部)。 - 规则支持度(Rule Support):规则
X -> Y的支持度定义为同时包含X和Y的事务总数。- 公式:
support(X -> Y) = support(X ∪ Y) - 例如:规则
{B, C} -> {E}的支持度为2(事务2和4同时包含B, C和E)。
- 公式:
- 规则置信度(Rule Confidence):规则
X -> Y的置信度定义为在包含X的事务中,同时也包含Y的事务所占的比例。- 公式:
confidence(X -> Y) = support(X ∪ Y) / support(X) - 例如:规则
{B, C} -> {E}的置信度为2 / 3 ≈ 66.7%。直观理解是:购买了B和C的顾客中,有66.7%也购买了E。
- 公式:
关联规则挖掘的目标


上一节我们定义了关联规则及其度量指标。本节中,我们来看看关联规则挖掘的具体目标是什么。

我们的目标是:从交易数据中,找出所有“有趣”的关联规则。
那么,如何定义“有趣”?通常,用户(如超市经理)会设定两个阈值:
- 最小支持度阈值(min_sup):例如 3。
- 最小置信度阈值(min_conf):例如 50%。
一条规则被认为是“有趣的”,当且仅当它同时满足:
support(rule) >= min_supconfidence(rule) >= min_conf
因此,关联规则挖掘问题可以形式化为:给定交易数据库、最小支持度阈值和最小置信度阈值,找出所有满足这两个条件的关联规则。
解决方法一:朴素方法


理解了目标后,我们首先来看一种最直观的解决方法。
这是一种简单但耗时的“暴力”方法,分为三个步骤:
- 枚举所有可能的规则:生成所有形如
X -> Y(其中X ∩ Y = ∅)的规则。 - 计算每条规则的支持度和置信度:遍历数据库,为每一条生成的规则计算其支持度和置信度。
- 筛选有趣的规则:保留那些支持度
>= min_sup且置信度>= min_conf的规则。
以下是一个小例子,假设我们只有项目A, B, C,min_sup = 2,min_conf = 50%:


| 规则 | 支持度 | 置信度 | 是否有趣? |
|---|---|---|---|
| A -> B | 2 | 67% | 是 |
| A -> C | 1 | 33% | 否 |
| B -> A | 2 | 50% | 是 |
| B -> C | 3 | 75% | 是 |
| C -> A | 1 | 33% | 否 |
| C -> B | 3 | 100% | 是 |
最终,我们得到的“有趣”规则集合是 {A->B, B->A, B->C, C->B}。
这种方法虽然直接,但效率很低。因为可能的规则数量会随着项目数呈指数级增长,计算每条规则的支持度和置信度需要扫描整个数据库,非常耗时。
解决方法二:两步法(Apriori原理基础)
由于朴素方法效率低下,我们需要更聪明的方法。本节介绍一个更高效的两步法,它是经典Apriori算法的基础。
观察发现,一条规则 X -> Y 要有高的支持度,其对应的项目集 X ∪ Y 必须有高的支持度(即必须是频繁项集)。这启发我们将问题分解:

步骤一:找出所有频繁项集
- 目标:找出所有支持度
>= min_sup的项目集。这一步是计算上的主要瓶颈。
步骤二:从频繁项集生成关联规则
- 目标:对于每一个找到的频繁项集
Z,考虑其所有非空真子集X。对于每个这样的X,可以生成一条规则X -> (Z - X)。 - 我们只需要计算这些规则的置信度:
confidence = support(Z) / support(X)。 - 保留那些置信度
>= min_conf的规则。
为什么这个方法更高效?
- 步骤二只需要在步骤一找到的(通常数量少得多的)频繁项集上进行,避免了在全部可能的规则上进行枚举。
- 步骤一中有一个关键性质(Apriori性质):一个频繁项集的所有子集也一定是频繁的。反之,如果一个项集不是频繁的,那么它的所有超集也一定不是频繁的。这个性质可以用来大幅剪枝搜索空间,我们将在后续课程详细讲解。
两步法的正确性
我们可以证明,两步法得到的规则集合 S2 与朴素方法得到的规则集合 S_final 是完全相同的。
- 证明
S2是S_final的子集:S2中的任何规则X->Y都源于某个频繁项集Z = X∪Y。由于Z是频繁的,support(Z) >= min_sup,即规则支持度达标。又因为规则是通过置信度>= min_conf筛选出来的,所以该规则也在S_final中。 - 证明
S_final是S2的子集:S_final中的任何规则X->Y,其支持度support(X∪Y) >= min_sup,所以Z = X∪Y是频繁项集(在步骤一被找到)。同时,其置信度support(Z)/support(X) >= min_conf。在步骤二中,当我们处理频繁项集Z及其子集X时,必然会生成这条规则并因其置信度达标而保留,所以该规则也在S2中。

因此,两步法是正确且更高效的。


频繁项集挖掘的难度
上一节我们了解到,两步法中的步骤一(寻找所有频繁项集)是更困难的部分。本节中,我们来看看这个问题为什么在计算上是困难的。





寻找所有频繁项集的问题可以形式化为:给定一个交易数据库 D 和一个最小支持度阈值 min_sup,找出 D 中所有支持度不低于 min_sup 的项目集。



我们可以证明,这个问题是 NP-hard 的。这意味着,在最坏情况下,不存在能在多项式时间内解决所有实例的算法(除非 P=NP)。
证明思路(归约法):
- 我们选择一个已知的 NP-complete 问题,例如“平衡完全二分子图问题”(Balanced Complete Bipartite Subgraph)。
- 将该问题的任意一个实例,在多项式时间内转换(归约)为我们的频繁项集挖掘问题的一个实例。
- 证明:如果能解决我们的频繁项集问题,那么就等价于解决了原来的 NP-complete 问题。
- 由于原问题是 NP-complete 的,因此我们的频繁项集挖掘问题至少和它一样难,即 NP-hard。
归约过程简述:
- 将二分图左边的每个顶点映射为一个“交易”。
- 将二分图右边的每个顶点映射为一个“商品”。
- 如果图中左边顶点
u和右边顶点v之间有边,则在交易u中包含商品v。 - 设置最小支持度阈值
min_sup等于原问题中要找的子图大小k。 - 那么,在原图中存在一个大小为
k的平衡完全二分子图,当且仅当在我们的交易数据中存在一个支持度至少为k的k-项集。
这个归约表明,频繁项集挖掘在计算上是困难的。尽管如此,在实践中,由于数据通常具有某些特性(如稀疏性),并且我们可以利用 Apriori 性质等启发式方法进行剪枝,因此仍然可以设计出在现实数据上表现高效的算法(如Apriori、FP-Growth等),这将是后续课程的重点。
总结


本节课中我们一起学习了关联规则挖掘的基本概念。
- 我们首先定义了项目、项目集、支持度、置信度、频繁项集和关联规则这些核心术语。
- 然后明确了关联规则挖掘的目标:找出所有满足最小支持度和最小置信度阈值的规则。
- 接着,我们分析了解决该问题的两种思路:一种是简单但低效的朴素枚举法;另一种是更高效的两步法,该方法先找频繁项集,再从频繁项集生成高置信度规则。
- 最后,我们了解到两步法中的关键步骤——频繁项集挖掘是一个 NP-hard 问题,这解释了为什么我们需要设计巧妙的算法(如基于Apriori性质的算法)来高效地解决它,这将是下节课的主要内容。
004:Apriori 性质与算法

在本节课中,我们将学习关联规则挖掘中的核心算法——Apriori算法。我们将重点理解其背后的两个关键性质,并通过一个详细的例子,一步步学习算法的执行过程。
概述
Apriori算法是发现频繁项集(即经常一起出现的商品组合)的经典方法。它的核心思想基于两个重要的性质,可以显著减少需要检查的项集数量,从而提高算法效率。本节我们将深入探讨这些性质,并学习算法的具体步骤。


Apriori 性质
上一节我们介绍了频繁项集和支持度的概念。本节中,我们来看看Apriori算法赖以成立的两个基本性质。
性质 1
如果一个项集 S 是频繁的,那么 S 的任何非空子集也一定是频繁的。
公式:如果 support(S) >= min_sup,那么对于任意 S' ⊂ S,都有 support(S') >= min_sup。

解释:例如,如果项集 {啤酒,尿布} 是频繁的(即同时购买次数很多),那么单独购买 {啤酒} 或单独购买 {尿布} 的次数也一定很多。因为包含 {啤酒,尿布} 的交易必然也包含 {啤酒} 和 {尿布}。


性质 2
如果一个项集 S 不是频繁的,那么 S 的任何超集也一定不是频繁的。
公式:如果 support(S) < min_sup,那么对于任意 S'' ⊃ S,都有 support(S'') < min_sup。
解释:这是性质1的逆否命题。例如,如果项集 {牛奶} 本身就不频繁(购买次数很少),那么任何包含 {牛奶} 的更大组合,如 {牛奶,面包} 或 {牛奶,面包,鸡蛋},其购买次数只会更少或持平,因此也一定不频繁。
这两个性质是Apriori算法“剪枝”操作的理论基础,它允许我们在不扫描数据库的情况下,提前排除大量不可能成为频繁项集的候选组合。
Apriori 算法步骤


理解了核心性质后,我们来看看Apriori算法是如何利用这些性质来工作的。算法采用一种逐层搜索的迭代方法,即先找出所有频繁1-项集,再用它们来构造候选2-项集,并筛选出频繁2-项集,如此往复,直到不能再找到新的频繁项集为止。
整个过程主要包含两个关键阶段:候选生成 和 支持度计数。候选生成阶段(包括连接和剪枝步骤)利用内存中的信息生成可能的候选项集,而支持度计数阶段则需要扫描数据库来计算每个候选项集的实际支持度。
以下是算法的详细步骤,我们将通过一个例子来具体说明。
步骤 1:找出频繁 1-项集 (L1)
首先,算法扫描一次数据库,统计每个单独商品(1-项集)出现的次数。
例子:假设我们有以下交易数据,最小支持度计数设为 2。

| 交易ID | 购买的商品 |
|---|---|
| T1 | A, C, D |
| T2 | B, C, E |
| T3 | A, B, C, E |
| T4 | B, E |
| T5 | A, B, C, E |
扫描后,我们得到每个商品的出现次数(支持度计数):
| 项集 | 支持度计数 |
|---|---|
| 3 | |
| 4 | |
| 4 | |
| 1 | |
| 4 |
根据最小支持度 2,我们可以筛选出频繁 1-项集 L1:
L1 = { {A}, {B}, {C}, {E} }
(项集 {D} 因为支持度计数为 1,小于 2,被排除。)
步骤 2:生成候选 2-项集 (C2) 并找出频繁项集 (L2)

接下来,我们要找出频繁 2-项集。首先,我们基于 L1 生成所有可能的 2-项集作为候选。
连接步骤 (Join Step):将 L1 中的项集两两连接。由于是生成 2-项集,连接操作就是简单的两两组合。
C2 = L1 JOIN L1 = { {A,B}, {A,C}, {A,E}, {B,C}, {B,E}, {C,E} }
剪枝步骤 (Prune Step):在生成 2-项集时,剪枝步骤是隐含的。因为所有 1-项子集(即 L1 中的项)都是频繁的,所以 C2 中的所有候选都暂时保留。
支持度计数步骤 (Counting Step):现在,我们需要扫描数据库,计算 C2 中每个候选的支持度计数。
| 候选 2-项集 | 支持度计数 | 是否 >= 2? |
|---|---|---|
| 2 | 是 | |
| 3 | 是 | |
| 2 | 是 | |
| 3 | 是 | |
| 4 | 是 | |
| 3 | 是 |
所有候选的支持度都大于等于2,因此频繁 2-项集 L2 为:
L2 = { {A,B}, {A,C}, {A,E}, {B,C}, {B,E}, {C,E} }
步骤 3:生成候选 3-项集 (C3) 并找出频繁项集 (L3)
现在,我们基于 L2 来寻找频繁 3-项集。这一步的连接和剪枝操作更加明显。
连接步骤 (Join Step):将 L2 中的项集进行连接。连接的原则是:两个项集的前 k-1 项必须相同(按字母顺序排序后),然后合并它们。
- 以 {A, C} 和 {A, E} 为例,它们的前一项(k-1=1)都是 {A},因此可以连接生成 {A, C, E}。
- 以 {A, B} 和 {A, C} 为例,它们的前一项都是 {A},可以连接生成 {A, B, C}。
- 以 {B, C} 和 {B, E} 为例,它们的前一项都是 {B},可以连接生成 {B, C, E}。
- {A, C} 和 {B, C} 的前一项分别是 {A} 和 {B},不相同,不能连接。
按照此规则,我们得到候选 3-项集:
C3 = { {A, B, C}, {A, C, E}, {B, C, E} }
剪枝步骤 (Prune Step):利用 Apriori 性质 2 进行剪枝。检查 C3 中每个候选的所有 2-项子集是否都在 L2 中。如果有一个子集不在 L2 中,则该候选不可能是频繁的,应被剪枝。
{A, B, C}的 2-项子集是 {A,B}, {A,C}, {B,C}。它们都在 L2 中,保留。{A, C, E}的 2-项子集是 {A,C}, {A,E}, {C,E}。它们都在 L2 中,保留。{B, C, E}的 2-项子集是 {B,C}, {B,E}, {C,E}。它们都在 L2 中,保留。


经过剪枝,C3 保持不变。
支持度计数步骤 (Counting Step):再次扫描数据库,计算 C3 中每个候选的支持度计数。
| 候选 3-项集 | 支持度计数 | 是否 >= 2? |
|---|---|---|
| 2 | 是 | |
| 2 | 是 | |
| 3 | 是 |
所有候选都满足最小支持度,因此频繁 3-项集 L3 为:
L3 = { {A, B, C}, {A, C, E}, {B, C, E} }
步骤 4:生成候选 4-项集 (C4) 并终止
我们继续基于 L3 寻找频繁 4-项集。
连接步骤 (Join Step):尝试连接 L3 中的项集。
- {A, B, C} 和 {A, C, E} 的前两项(k-1=2)分别是 {A, B} 和 {A, C},不相同,不能连接。
- {A, B, C} 和 {B, C, E} 的前两项分别是 {A, B} 和 {B, C},不相同,不能连接。
- {A, C, E} 和 {B, C, E} 的前两项分别是 {A, C} 和 {B, C},不相同,不能连接。
由于无法生成任何新的候选 4-项集,C4 = ∅。算法终止。



算法总结
本节课中我们一起学习了Apriori算法的核心思想与执行步骤。我们来总结一下关键点:
- 核心思想:Apriori算法基于两个反单调性性质来减少搜索空间。它采用一种逐层迭代的方法来发现频繁项集。
- 主要步骤:每一层(k-项集)的处理都包含:
- 连接:通过上一层的频繁项集 (L_{k-1}) 生成候选 k-项集 (C_k)。
- 剪枝:利用性质2,删除那些子集不全是频繁的候选,得到修剪后的 C_k。
- 计数:扫描数据库,计算修剪后 C_k 中所有候选的支持度,筛选出频繁 k-项集 (L_k)。
- 终止条件:当无法生成新的候选集(C_k 为空)时,算法结束。
- 优点:通过剪枝,大大减少了需要扫描数据库进行支持度计算的候选集数量,比暴力枚举所有组合高效得多。
- 输出:算法最终输出所有满足最小支持度阈值的频繁项集,即 L1 ∪ L2 ∪ L3 ∪ ...。


通过本节的例子,你应该已经掌握了Apriori算法的手动计算过程。理解这个过程是应用和优化该算法的基础。
005:FP树算法详解(第一部分)

在本节课中,我们将要学习一种名为FP树(Frequent Pattern Tree)的高效频繁项集挖掘算法。我们将详细讲解其构建过程,并与传统的Apriori算法进行对比,理解其优势所在。




概述:为什么需要FP树?
上一节我们介绍了Apriori算法,它通过生成候选集和多次扫描数据库来发现频繁项集。然而,这种方法存在两个主要缺点:
- 处理大量候选集非常昂贵。
- 需要反复扫描数据库,速度较慢。

本节中,我们来看看FP树算法如何解决这些问题。FP树的核心思想是只扫描数据库两次,将关键信息压缩存储在一个称为“频繁模式树”的数据结构中,然后直接从这个树中生成所有频繁项集,从而更高效。

第一步:推导有序频繁项
首先,我们需要处理原始事务数据,找出所有频繁项并按规则排序。
我们有一个事务数据库示例:
| 事务ID | 购买的商品 |
|---|---|
| 1 | A, B, D, E, F, G |
| 2 | A, F, G |
| 3 | B, D, E, G |
| 4 | B, F, D |
| 5 | B, A, E, G |
我们的目标是找到所有支持度至少为3的频繁项集。与Apriori类似,我们先计算每个单项的支持度。
以下是频率表:
- A: 4
- B: 4
- D: 3
- E: 3
- F: 3
- G: 3
- C: 2 (非频繁)
- H: 1 (非频繁)
设定最小支持度 min_sup = 3,我们得到频繁项为:{A, B, D, E, F, G}。


现在,我们需要对这些频繁项进行排序。排序规则是:
- 按支持度降序排列。
- 如果支持度相同,则按字母顺序排列。
根据频率表,A和B的支持度为4,D、E、F、G的支持度为3。因此,排序后的顺序为:A, B, D, E, F, G。(因为A和B支持度相同,按字母顺序A在前;D、E、F、G支持度相同,按字母顺序排列)。


接下来,我们为每个原始事务生成其对应的“有序频繁项”列表。方法是:只保留该事务中的频繁项,并按照上述全局顺序排列。
以下是生成的有序频繁项列表:


| 事务ID | 原始商品 | 有序频繁项 |
|---|---|---|
| 1 | A, B, D, E, F, G | A, B, D, E, F, G |
| 2 | A, F, G | A, F, G |
| 3 | B, D, E, G | B, D, E, G |
| 4 | B, F, D | B, D, F |
| 5 | B, A, E, G | A, B, E, G |
注意:事务4中原始项为B, F, D,排序后应为B, D, F(因为顺序是A,B,D,E,F,G,B之后是D,然后是F)。



第二步:从数据构建FP树
有了有序频繁项列表后,我们就可以构建FP树了。FP树是一种前缀树(Trie),树中每个节点代表一个项及其在该路径上的累计出现次数。此外,还有一个“头指针表”将所有相同项名的节点横向链接起来,便于快速访问。
构建过程如下:
- 创建树的根节点(Root),标记为
null。 - 依次读取每条“有序频繁项”事务。
- 从根节点开始,将事务中的项逐个插入树中。
- 如果当前节点存在一个与待插入项同名的子节点,则只需将该子节点的计数值加1。
- 如果不存在,则创建一个新的子节点,计数值设为1。
- 在创建或更新节点的同时,通过头指针表将其链接到同名的其他节点上。
以下是针对我们示例数据,一步步构建FP树的过程图示(文字描述关键步骤):

- 插入事务1 (A, B, D, E, F, G):从根节点创建子节点A(1),然后A下创建B(1),B下创建D(1),依此类推,直到G(1)。同时,头指针表指向每个新创建的节点。
- 插入事务2 (A, F, G):从根节点找到已存在的子节点A,将其计数增为2。在A下没有F,所以创建新节点F(1)。在F下创建G(1)。更新头指针表,将F和G链接到各自的链表中。
- 插入事务3 (B, D, E, G):从根节点没有B,所以创建新分支:根 -> B(1) -> D(1) -> E(1) -> G(1)。
- 插入事务4 (B, D, F):从根节点找到已存在的B(1),计数增为2。B下找到D(1),计数增为2。D下没有F,创建新节点F(1)。
- 插入事务5 (A, B, E, G):从根节点找到A(2),计数增为3。A下找到B(1),计数增为2。B下没有E,创建新分支:B -> E(1) -> G(1)。

最终构建的FP树结构如下图所示(以文本形式示意):
Root
/ \
A(3) B(1)
| |
B(2) D(1)
/ \ |
D(1) E(1) E(1)
| | |
E(1) F(1) G(1)
| |
F(1) G(1)
|
G(1)
(注:实际FP树通过头指针表横向链接所有相同项,例如所有A节点链接在一起,所有B节点链接在一起,等等。)


FP树的优势:
- 压缩性:FP树通常比原始数据库小得多。上例中,原始事务有20个项的出现,而FP树只有14个节点(不计根节点),因为它共享了相同的前缀。
- 完备性:FP树完整地保留了频繁项集的关联信息。理论上,可以从FP树重建出“有序频繁项”列表。
- 一次扫描:构建FP树只需要对数据库进行两次扫描(第一次计算单项频率,第二次构建树),避免了Apriori的多次扫描。

第三步:为每个项生成条件模式基
上一节我们构建了完整的FP树,本节中我们来看看如何从这个树中挖掘频繁项集。核心方法是“分而治之”:为每个频繁项生成“条件模式基”,然后递归地构建更小的“条件FP树”。
首先,我们关注最后一个项(按顺序):G。
1. 寻找G的条件模式基:
我们利用头指针表,找到所有G节点,并追溯其到根节点的路径(排除G本身)。这些路径就是G的条件模式基。
-
路径1:
A:3 -> B:2 -> D:1 -> E:1 -> F:1(计数为G节点的计数:1) -
路径2:
A:3 -> F:1(计数:1) -
路径3:
B:1 -> D:1 -> E:1(计数:1) -
路径4:
B:2 -> D:2 -> F:1(计数:1)? (检查树,B(2)下的F(1)的G?似乎有误,应根据实际树结构调整)- 实际上,根据我们构建的树,G出现在以下路径末梢:
Root -> A -> B -> D -> E -> F -> G(计1)Root -> A -> F -> G(计1)Root -> B -> D -> E -> G(计1)Root -> B -> D -> F -> G? (需要检查树中B->D->F路径下是否有G,根据构建步骤4,B(2)->D(2)下创建了F(1),但未创建G。事务4B,D,F不包含G)Root -> A -> B -> E -> G(计1,来自事务5)
因此,G的条件模式基是:
A B D E F: 1A F: 1B D E: 1A B E: 1
- 实际上,根据我们构建的树,G出现在以下路径末梢:


2. 构建G的条件FP树:
条件模式基可以看作是一个新的“事务”集合,其中的项必须与G共同出现。我们基于这个集合,用同样的方法构建一个新的FP树,但这里只考虑那些在条件模式基中累计支持度仍然 >= min_sup 的项。
- 统计条件模式基中各项的频率:A(3), B(3), D(2), E(2), F(2)。(例如A出现在3条路径中)
- 保留支持度>=3的项:
{A:3, B:3}。 - 按规则排序(支持度相同按字母):
A, B。 - 用过滤和排序后的路径构建树:
- 路径
A B D E F过滤排序后为A B(计数1) - 路径
A F过滤后为A(计数1) - 路径
B D E过滤后为B(计数1) - 路径
A B E过滤后为A B(计数1)
- 路径
- 构建的条件FP树将只包含一个分支或节点。同时,我们记录下该项(G)本身的支持度,这里是3(因为头指针表中G的链表有3个节点?需要计算:实际事务1,2,3,5包含G,共4个?检查数据:事务1,2,3,5有G,所以G的支持度是4。这里应以实际头指针表计数为准,我们假设示例中G的最终计数为3)。
条件模式基和条件FP树是递归挖掘的关键。对于项G,其条件FP树可能非常简单(例如只有单个路径)。
第四步:从条件FP树生成频繁项集


现在,我们有了项G的条件FP树。如何从中生成包含G的频繁项集呢?
规则如下:
- 单项集:项
G本身就是一个频繁项集,其支持度就是头指针表中G的计数(例如3)。 - 多选项集:观察条件FP树。如果条件FP树是一条单一路径,那么问题会变得非常简单。我们可以通过枚举该路径上所有节点的组合,并与当前项(G)连接,来生成所有包含G的频繁项集。
- 假设G的条件FP树是单路径:
A(3) -> B(3)。 - 那么,包含G的频繁项集有:
{G}(支持度来自G的计数){A, G}(支持度取路径中A的计数?不,取条件模式基中A出现的次数?这里应为min_sup。实际上,{A,G}的支持度等于条件FP树中A节点的计数值,因为该计数代表了A与G在原始事务中共同出现的次数。需要根据条件模式基累计计算。){B, G}{A, B, G}
- 假设G的条件FP树是单路径:
递归过程:
如果条件FP树不是单一路径(即仍然有分支),那么我们需要对这个条件FP树重复上述过程:为其中的每个项(例如条件FP树中的A),生成它的“条件模式基”和“条件FP树”,直到所有条件FP树都是单一路径为止。这是一个递归的“分而治之”过程。
例如,如果G的条件FP树不是单路径,我们会对树中的项(如A、B)分别进行:
- 生成
G条件下A的条件模式基和条件FP树。 - 生成
G条件下B的条件模式基和条件FP树。 - ... 以此类推,直到所有子树都是单路径,可以轻松生成项集。
总结与复杂度分析

本节课中我们一起学习了FP树算法的前半部分,包括其构建和递归挖掘的基本框架。

总结关键点:
- 动机:FP树通过压缩数据和减少扫描次数,克服了Apriori算法的两大缺点。
- 构建:
- 第一次扫描数据库,计算单项频率,确定频繁项及排序顺序。
- 第二次扫描,根据“有序频繁项”列表构建FP树和头指针表。
- 挖掘:采用分治策略。
- 从频率表最底部的项开始(如G),利用头指针表找到其所有前缀路径(条件模式基)。
- 基于条件模式基构建该项的条件FP树。
- 如果条件FP树是单路径,则直接生成该路径上所有项的组合与当前项的连接,即为包含当前项的所有频繁项集。
- 如果条件FP树不是单路径,则递归地对树中的每个项进行上述过程。
算法复杂度优势:
- 数据库扫描:仅需两次。
- 构建成本:插入一个事务到FP树的成本约等于该事务中频繁项的数量。
- 空间效率:FP树的大小通常远小于原始数据库中频繁项出现的总数,因为它共享了公共前缀。


FP树算法巧妙地将数据挖掘问题转化为对一棵紧凑树的递归遍历问题,极大地提升了频繁项集发现的效率。在下一部分,我们将通过更复杂的示例,深入探讨递归挖掘非单路径条件FP树的完整过程。
006:绪论

在本节课中,我们将要学习数据挖掘中的一个核心概念——聚类分析。我们将通过日常生活中的例子来理解聚类的含义、目的及其在不同领域的应用。
什么是聚类?
上一节我们介绍了数据挖掘的基本概念,本节中我们来看看什么是聚类。
聚类是一种将数据对象分组的方法,使得同一组(即簇)内的对象彼此相似,而不同组之间的对象则相异。这就像我们的大脑会自然地根据某些特征对事物进行分类。
例如,考虑以下四种生物:人类、大猩猩、猫和狗。如果我们想将它们分成两组,大多数人会基于“腿的数量”、“是否有尾巴”等属性,将猫和狗分为一组(四足动物),而将人类和大猩猩分为另一组(灵长类动物)。这个过程就是基于属性相似性的聚类。

聚类的目标与动机
理解了聚类的概念后,我们来看看为什么要进行聚类。主要有两个核心动机:数据摘要和数据压缩。
假设我们有一个学生数据集,包含他们在计算机和历史两门科目上的成绩。每个学生可以用一个点表示在二维坐标系中。

通过观察,我们可以发现数据点自然地形成了两个簇:
- 簇1:计算机成绩高、历史成绩低的学生。
- 簇2:历史成绩高、计算机成绩低的学生。
以下是聚类的主要目的:
- 数据摘要:当数据量巨大时(例如数百万学生),我们无需记住每个学生的具体分数。相反,我们可以总结为:“有2000名学生属于‘擅长计算机但不擅长历史’的群体,有4000名学生属于‘擅长历史但不擅长计算机’的群体。” 这大大简化了我们对数据的理解。
- 数据压缩:我们无需存储海量的原始数据记录,只需存储每个簇的摘要信息(例如,簇的中心点、数据点数量、成绩范围)。这可以节省大量的存储空间。

聚类的应用领域
聚类分析的应用非常广泛,几乎遍及所有需要从数据中发现模式的领域。以下是几个典型的应用场景:
- 生物学:正如开头的例子,可以根据基因序列、形态特征等属性对不同的物种或药物进行分组,以发现其相似性。
- 商业营销:可以根据客户的性别、年龄、购买历史等属性对客户进行分群,从而实现精准营销。例如,为不同的客户群体推荐不同的产品或服务。
- 网络分析:可以根据网络流量的源地址、目标地址、内容类型等属性对流量模式进行分组,以识别异常流量或优化网络管理。
- 程序分析:可以根据代码的结构、复杂度等属性对软件程序进行分组,以进行质量评估或缺陷预测。


本节课中我们一起学习了聚类分析的基本概念。我们了解到,聚类是一种基于对象属性相似性进行分组的技术,其核心目标是实现数据的摘要和压缩。我们还探讨了聚类在生物学、商业、网络等多个领域的实际应用。掌握聚类是理解数据内在结构的重要一步。
007:原始K-Means算法(第一部分)🎯


在本节课中,我们将要学习聚类分析中的第一个核心算法——原始K-Means算法。我们将从基本概念入手,通过一个简单的二维例子,详细讲解算法的步骤、工作原理以及其优缺点。
基本概念与目标


K-Means是一种将数据点划分为K个簇的聚类方法。其核心思想是:每个数据点属于离其最近的簇中心(均值点)所在的簇。我们的目标是找到K个簇中心,使得所有数据点到其所属簇中心的距离之和最小。
假设我们有N个数据点:X1, X2, ..., XN。用户(例如超市经理)需要指定簇的数量K(K < N)。我们用 Mi 表示第 i 个簇中所有数据点的均值(中心点)。
算法步骤详解
原始K-Means算法的过程是一个迭代优化的过程,具体步骤如下:
- 初始化:随机猜测K个簇中心
M1, M2, ..., MK的初始位置。 - 迭代直至收敛:
- 分配步骤:对于每一个数据点,计算它到所有K个簇中心的距离(通常使用欧几里得距离)。将该数据点分配给距离最近的簇中心所在的簇。
- 更新步骤:对于每一个簇,重新计算其簇中心。新的簇中心
Mi等于该簇内所有数据点坐标的平均值。
- 停止条件:当簇中心的位置不再发生变化,或者达到了预设的最大迭代次数时,算法停止。


一个直观的二维示例
为了帮助理解,我们来看一个具体的例子。假设我们在二维空间中有8个数据点,并希望将它们分为2个簇(K=2)。

第一步:随机初始化
我们闭上眼睛,随机选择两个点作为初始的簇中心(图中用白色圆点表示)。
第二步:分配数据点
对于每一个蓝色的数据点,我们计算它到两个白色中心点的距离(图中用黑色线段表示)。例如,对于点X1,它到左边中心点的距离更短,因此它被分配到左边的簇(用浅蓝色表示)。同理,点X5到右边中心点的距离更短,因此被分配到右边的簇(用深蓝色表示)。分配完成后,所有点都有了颜色归属。
第三步:更新簇中心
现在,左边的簇包含了4个浅蓝色的点。我们计算这4个点坐标的平均值,得到一个新的中心点位置(新的白色圆点)。同样地,我们计算右边6个深蓝色点的坐标平均值,更新右边的中心点位置。


第四步:再次分配与更新
用新的中心点位置,重复第二步的分配过程。你会发现,有些点的归属可能会发生变化(例如,原本属于右边簇的点,现在可能离左边的新中心点更近,从而被重新分配到左边的簇)。然后,再次基于新的簇成员更新中心点位置。
第五步:迭代至收敛
不断重复“分配”和“更新”这两个步骤,直到中心点的位置基本不再移动,或者达到了我们设定的最大迭代次数(例如200次)。最终,我们得到了稳定的两个簇。




算法的影响因素与评估
上一节我们介绍了K-Means的基本流程,本节中我们来看看算法的表现如何评估,以及受哪些因素影响。
K-Means的结果强烈依赖于初始簇中心的选择。不同的初始猜测可能导致完全不同的最终聚类结果。
考虑以下三种不同的初始中心位置:
- 初始中心分别位于左右两侧 -> 最终能正确分出左右两个簇。
- 初始中心分别位于上下两侧 -> 最终可能分出上下两个簇,但这不符合我们“肉眼”看到的自然分组。
- 初始中心都集中在左侧 -> 最终可能所有点都被归为一个簇,另一个簇为空。


显然,第一种情况的结果是最好的。但计算机没有“眼睛”,它需要一个量化的指标来评估聚类结果的好坏。
一个常用的评估指标是簇内平方误差和。其思想是计算每个数据点到其所属簇中心的距离的平方,然后对所有点求和。公式可以表示为:
SSE = Σ Σ ||x - μ_i||²
(其中,外层求和遍历所有簇i,内层求和遍历属于簇i的所有点x,μ_i是簇i的中心)
SSE的值越小,说明簇内点越紧密,聚类效果越好。因此,在实际应用中,为了得到更好的结果,通常会多次运行K-Means算法(每次使用不同的随机初始中心),然后选择SSE最小的那次结果作为最终输出。
K-Means的优缺点总结
本节课中我们一起学习了原始K-Means算法的核心思想与步骤。最后,我们来总结一下它的主要特点:


优点:
- 原理简单,实现容易,收敛速度快。
- 对于处理大数据集,该算法是相对高效和可扩展的。
缺点:
- 需要预先指定K值:在数据维度很高时,我们可能无法直观判断应该分成多少类。
- 对初始值敏感:不同的初始中心可能导致不同的结果,有时会收敛到局部最优解(即次优的分区)。
- 对异常值敏感:由于使用均值作为簇中心,异常值会显著拉偏中心点的位置。
- 不适合非凸形状的簇:K-Means假设簇是凸形的(类似球形),对于流形或复杂形状的数据集效果不佳。
在后续的课程中,我们将介绍K-Means的变种算法,以及如何应对其中一些挑战。


008:层次聚类 引言 🧩




在本节课中,我们将要学习层次聚类方法。这是一种重要的聚类技术,它通过构建一个树状结构(称为树状图)来展示数据点之间的层次关系。我们将介绍层次聚类的两种主要方法:自底向上和自顶向下,并解释如何衡量不同簇之间的距离。

层次聚类方法概述
层次聚类方法主要有两种实现途径:凝聚方法和分裂方法。


凝聚方法对应着自底向上的策略。分裂方法则对应着自底向上的反向策略,即自顶向下。
上一节我们介绍了聚类的概念,本节中我们来看看层次聚类的具体思路。
自底向上与自顶向下方法
为了更好地理解这两种方法,我们通过一个简单的例子来说明。


假设我们有八个数据点。在自底向上方法中,初始时每个数据点自成一个簇。然后,我们找到距离最近的两个簇,将它们合并。这个过程不断重复,直到所有数据点合并成一个簇。
以下是自底向上方法的步骤:
- 初始状态:每个数据点是一个独立的簇。
- 找到距离最近的两个簇。
- 合并这两个簇。
- 重复步骤2和3,直到只剩下一个簇。
相反,自顶向下方法从一个包含所有数据点的大簇开始。然后,将这个簇分裂成两个较小的簇。这个过程不断重复,直到每个数据点都成为一个独立的簇。
以下是自顶向下方法的步骤:
- 初始状态:所有数据点属于同一个簇。
- 将这个簇分裂成两个子簇。
- 对每个子簇重复步骤2,直到每个簇只包含一个数据点。
树状图


层次聚类的结果可以用一个二维图来表示,称为树状图。

在树状图中,每个数据点最初位于底部。当两个簇合并时,它们会在图中以一个连接点相连,该点的高度代表了合并时的距离。通过观察树状图,我们可以决定将数据分成多少个簇。

例如,如果我们想得到两个簇,可以在树状图中画一条水平切割线,切割线穿过的分支数就是簇的数量。同样,如果我们想得到三个簇,可以在合适的高度画一条切割线。
树状图的一个优点是,即使我们不知道数据集中簇的确切数量,也可以通过观察图中距离的突然增大来推断出自然的簇结构。
簇间距离度量
在层次聚类中,一个关键步骤是计算两个簇之间的距离。当簇中只有一个点时,距离计算很简单,例如使用欧氏距离公式:distance = sqrt((x1-x2)^2 + (y1-y2)^2)。
然而,当簇包含多个点时,我们需要定义如何计算两个簇之间的距离。有几种常用的方法:



以下是几种主要的簇间距离度量方法:
- 单链连接: 取两个簇中所有点对之间距离的最小值。公式可表示为:
d(A, B) = min{d(a, b) for a in A, b in B}。 - 全链连接: 取两个簇中所有点对之间距离的最大值。公式可表示为:
d(A, B) = max{d(a, b) for a in A, b in B}。 - 组平均连接: 取两个簇中所有点对之间距离的平均值。
- 质心连接: 计算每个簇的质心(均值点),然后计算两个质心之间的距离。
- 中值连接: 与质心连接类似,但在合并两个簇后,新簇的“中心”是两个原簇中心的中点,而不是所有点的均值。这可以避免大簇在合并时过度影响中心点的位置。
没有一种度量方法是普遍最好的,选择哪种方法取决于具体的数据特性和用户需求。
凝聚方法(自底向上)示例
我们以单链连接为例,演示自底向上方法的过程。


假设有五个数据点。首先,我们计算所有点对之间的距离矩阵。初始时,每个点是一个簇。
我们找到距离最小的两个点(例如点1和点2),将它们合并为一个新簇。然后,我们需要更新距离矩阵,计算这个新簇与其他簇之间的距离。对于单链连接,新簇与另一个簇的距离是原两个簇中所有点到那个簇的最小距离。
重复这个过程(找最小距离、合并、更新矩阵),直到所有点合并为一个簇。这个过程会生成一个树状图。
同样的过程可以应用于全链连接、组平均连接等其他距离度量,只是更新簇间距离的规则不同。
分裂方法(自顶向下)概述
分裂方法是自底向上方法的反向过程。它从一个包含所有数据点的大簇开始,递归地将其分裂为更小的簇,直到满足停止条件(如每个簇只有一个点)。



分裂方法又可以分为两类:
- 多路分裂: 使用所有属性来计算距离和进行分裂。其过程与凝聚方法类似,但是方向相反。它通常使用组平均、单链等距离度量来决定如何分裂一个簇。一种常见的策略是:先将距离整体最远的点分离出来形成一个簇,然后迭代地将剩余点中更靠近这个新簇的点移入,直到没有点应该被移入为止,从而完成一次分裂。
- 单路分裂: 基于单个指定属性的值来分裂数据。这种方法常用于属性是二元(0/1)的情况。

单路分裂与卡方度量
单路分裂方法通常用于二元属性数据。为了决定使用哪个属性进行分裂,我们需要衡量属性之间的相关性。这里引入卡方度量。
卡方度量用于评估两个二元属性之间的相关性。其计算公式虽然看起来复杂,但可以通过列联表来理解和计算。
卡方值越大,表明两个属性之间的相关性越强。在聚类背景下,如果一个属性与其他属性的平均卡方值很高,意味着基于这个属性更容易将数据点区分成不同的簇。
因此,单路分裂的步骤是:
- 计算每对属性之间的卡方值。
- 对于每个属性,计算它与其他所有属性的平均卡方值。
- 选择具有最大平均卡方值的属性作为分裂依据。
- 根据该属性的值(0或1)将数据集分成两个子集。
- 对每个子集递归地重复此过程。



本节课中我们一起学习了层次聚类的基本概念。我们介绍了两种主要方法:自底向上的凝聚法和自顶向下的分裂法。我们了解了展示聚类结果的树状图,以及五种计算簇间距离的方法(单链、全链、组平均、质心、中值)。最后,我们还探讨了分裂法中的多路分裂和基于卡方度量的单路分裂策略。层次聚类为我们提供了一种可视化数据层次结构的强大工具。
009:分类与决策树入门
在本节课中,我们将要学习数据挖掘中的分类概念,并通过一个贴近生活的学生例子来理解其核心思想。我们将介绍训练集、测试集、输入属性和目标属性等基本概念,并初步了解决策树的应用。
从学生例子理解分类
上一节我们回顾了分类的基本概念,本节中我们通过一个具体的例子来加深理解。这个例子将帮助我们区分训练集与测试集,并展示如何从数据中发现规律。
假设我们想预测一个人是否来自中国大陆。我们收集了一些学生的信息,包括他们是否拥有以下社交账户:ICQ、WhatsApp、Facebook、Facebook Messenger、WeChat、QQ、Instagram、YY。最后一个信息“是否来自中国大陆”是我们想要预测的目标。
首先,我们询问了几位已知来源的学生,记录下他们的账户拥有情况和来源地。这些已知的数据构成了我们的训练集。训练集用于让模型学习规律。
以下是训练集中的部分数据示例(用文字描述):
- Raymond: 无ICQ,有WhatsApp,有Facebook,无Messenger,有WeChat,有QQ,有IG,有YY。来自香港(否)。
- 全衡: 无ICQ,有WhatsApp,有Facebook,有Messenger,有WeChat,无QQ,有IG,无YY。来自香港(否)。
- 曾洋: 无ICQ,有WhatsApp,有Facebook,有Messenger,有WeChat,有QQ,无IG,有YY。来自中国大陆(是)。
- 子烟: 无ICQ,有WhatsApp,有Facebook,无Messenger,有WeChat,有QQ,有IG,有YY。来自中国大陆(是)。
在训练集中,账户信息(如是否有QQ)被称为输入属性,而我们想预测的“是否来自中国大陆”被称为目标属性。
从训练集中发现规律
基于上面的训练数据,我们可以尝试寻找规律。例如,我们观察“是否有QQ账户”这个属性与目标的关系。
统计发现:
- 在训练集中,拥有QQ账户的学生里,有相当一部分(例如4/6)来自中国大陆。
- 而没有QQ账户的学生,则全部来自香港(非中国大陆)。
由此,我们可以总结出一条简单的规则:如果 QQ = “否”,则预测为“非中国大陆”;如果 QQ = “是”,则预测为“中国大陆”的可能性较高。
应用规则进行预测
现在,我们有了新的学生(测试集),我们只知道他们的输入属性(社交账户情况),而不知道他们是否来自中国大陆。我们的目标就是应用刚才学到的规则进行预测。
例如,对于学生Stephen(无QQ账户),根据规则“无QQ则非大陆”,我们预测他来自香港。经核实,预测正确。
这个例子展示了分类的核心流程:
- 使用带有输入属性和已知目标属性的训练集进行学习,发现规律(规则)。
- 将学到的规律应用于只有输入属性的新数据(测试集),预测其未知的目标属性。
决策树:一种分类方法
我们刚才手动发现的规则,在数据挖掘中可以通过算法自动构建,并以树形结构呈现,这就是决策树。

决策树从一个根节点开始,根据输入属性的值(例如“是否有孩子?”)将数据分成不同的分支,在每个分支节点上继续根据其他属性(例如“收入是否高?”)进行划分,直到到达叶节点,叶节点就给出了最终的分类预测(例如“购买保险”或“不购买保险”)。
一个简化的决策树判断逻辑可以用伪代码表示:
如果 (孩子 == “是”) {
如果 (收入 == “高”) {
预测为 “不购买保险”
} 否则 {
预测为 “购买保险”
}
} 否则 {
如果 (收入 == “高”) {
预测为 “购买保险”
} 否则 {
预测为 “不购买保险”
}
}


分类的实际应用
分类技术在实际中有广泛的应用:
- 市场营销:根据客户属性预测其是否会购买某产品。
- 信贷评估:银行根据申请人背景(如职业、国籍、信用历史)预测其还款风险,从而决定信用额度。这解释了为什么不同背景的学生可能获得不同的初始信用卡额度。
- 网络安全:根据网络流量模式判断是否遭受攻击。
- 软件工程:根据程序员经验预测其能否修复特定类型的程序错误。
分类与聚类的异同

之前我们学习过聚类分析,这里简要比较一下分类与聚类的异同。
相似之处:两者都是重要的数据分析方法,目的都是对数据对象进行分组或划分。

核心区别:
- 分类属于有监督学习。在训练阶段,数据带有已知的标签(即目标属性),算法学习从输入属性到标签的映射关系。
- 聚类属于无监督学习。数据没有预先定义的标签,算法完全根据数据自身的相似性将其分组,组别的意义需要事后解释。

简单来说,分类是“按已知答案学习并预测新答案”,而聚类是“在未知答案的情况下探索数据的内在分组结构”。


本节课中我们一起学习了分类的基本概念。我们通过一个学生例子,理解了如何利用训练集学习规律,并对测试集进行预测。我们认识了输入属性和目标属性,并初步了解了决策树这一强大的分类工具。最后,我们探讨了分类的实际应用,并比较了分类与聚类的异同。掌握这些基础知识是进一步学习复杂分类算法(如决策树构建、朴素贝叶斯、支持向量机等)的关键。
010:决策树 ID3算法 第一部分


在本节课中,我们将要学习决策树算法,特别是ID3算法。决策树是一种用于分类的常用方法,它通过一系列规则将数据划分为不同的类别。我们将从理解信息论中的核心概念“熵”开始,逐步学习ID3算法如何利用熵来选择最佳属性进行数据划分。
熵:信息的度量
上一节我们介绍了分类问题的动机,本节中我们来看看决策树的基础——熵。熵是信息论中的一个概念,用于衡量一个随机变量的不确定性或信息量。
考虑一个随机变量,它在32种结果上具有均匀分布。为了识别一个结果,我们需要一个能取32个不同值的标签。这很容易,我们可以用5个比特来表示这个变量。

正如我们在之前的空间聚类主题中提到的,熵是一种衡量节点信息量的方法。
如果我们给定一个概率分布 P1, P2, ..., Pn,这意味着我们有n种可能的结果,每种结果的概率分别为 P1, P2, ..., Pn。那么这个分布所包含的信息,也称为该分布的熵,定义如下:
熵公式:
Entropy = - (P1 * log2(P1) + P2 * log2(P2) + ... + Pn * log2(Pn))
用一个通用公式可能难以理解,让我们通过例子来说明。
首先,假设我们有两种可能的结果。


示例一:
假设掷一枚硬币,出现正面的概率是0.5,出现反面的概率也是0.5。那么熵的计算如下:
Entropy = - (0.5 * log2(0.5) + 0.5 * log2(0.5)) = 1
示例二:
假设硬币出现正面的概率是0.67,出现反面的概率是0.33。那么熵的计算如下:
Entropy = - (0.67 * log2(0.67) + 0.33 * log2(0.33)) ≈ 0.92
示例三:
假设硬币出现正面的概率是1,出现反面的概率是0。那么熵的计算如下:
Entropy = - (1 * log2(1) + 0 * log2(0)) = 0
现在,你可以看到第一个例子的熵等于1。第二个例子的概率分布不那么均匀,熵的计算值更小。第三个例子的所有概率集中在一个结果上,熵为零。
现在,忘记熵的概念。假设我们有这三枚硬币。我想和你赌博。我掷硬币,谁想告诉我掷硬币的结果是正面还是反面?我认为会是反面。为什么你确定是反面?因为得到反面的概率是1,就像100%会得到反面。是的,实际上我想启发其他学生。既然概率是1和0,我们知道我们有一些信息。
然而,对于第一枚硬币,我认为没有学生能告诉我掷硬币的结果是正面还是反面。所以我们没有足够的信息。
我们理解到这里没有太多信息。然而,对于中间的硬币,如果你赌博,通常你也会预测。更有可能我们得到反面,但你也预期有时会得到正面。所以我们在这里有一些部分信息。
我想说的是,熵恰好捕捉到了这种东西。当我们有很多信息时,熵为零。然而,对于第一种情况,我们没有任何信息,熵值较大。在中间情况,我们有一些中间值。所以,熵是一种衡量我们拥有信息量的方式,熵越小(像这样),我们拥有的信息就越多。

ID3算法:核心思想

现在,主要思想非常简单。在开始时,我不考虑任何输入属性。我没有关于输入属性的任何信息。我只知道我有目标属性。
在没有输入属性信息的情况下,我想知道这个目标属性的熵。怎么做呢?

让我们看一个例子。假设目标属性“购买保险”的值为“是”或“否”。根据表格,我们有4个“是”和4个“否”。所以概率 P(是) = 1/2,P(否) = 1/2。我们可以使用熵公式计算。1/2 放在这里,1/2 放在这里。我们计算出的这个数据集的熵(不考虑输入属性)正好等于1。这衡量了一些信息。你知道这实际上是等概率分布,是最大的熵值。
接下来,我将考虑“种族”属性。让我关闭所有标注回到数据。现在考虑种族属性。我们有黑人记录。考虑黑人记录。黑人记录中,目标属性为“是”的概率是 1/4,为“否”的概率是 3/4。所以我们有这个分布。然后计算黑人记录的熵:1/4 在这里,3/4 在这里。计算熵,我们得到这个值。


类似地,我们可以为白人记录做计算。白人记录在这里。然后我们有三个“是”和一个“否”。所以目标属性为“是”的概率是 3/4,为“否”的概率是 1/4。1/4 在这里,3/4 在这里。计算熵,我们得到这个值。
现在,我们有两个不同的熵值。我们想将这两个熵合并成一个单一的值,怎么做?只是一个简单的加权平均。

Entropy_black 在这里。Entropy_white 在这里。这部分是黑人记录的比例。让我们看看,黑人有4条记录。所以是 4/8。这部分对应白人记录的比例。我们有4条白人记录。所以是 4/8。所以我们有这两个值。通过计算器,1/2 乘以这个值,加上 1/2 乘以这个值,我们得到这个值。
然后继续。信息增益,他们通常使用信息增益。信息增益是熵的差值,即使用种族属性之前的原始熵(这个值),减去使用种族属性之后的熵(这个值)。我们理解这个值小于1。我们获得了更多信息。所以一减去某个数,我们得到这个数字。让我总结一下对于属性“种族”,信息增益等于这个值。
如果没有问题,让我们再看一个属性“收入”。事实上,想法是一样的。类似地,在我们有这个输入属性之前,我们的熵是这个值。对于收入属性,同样的想法。只关注高收入,高收入我们有一个“是”和零个“否”。所以我们知道概率 P(是)=1,P(否)=0。然后,关注低收入,在这里。然后我们有两个“是”和四个“否”,所以 P(是)=2/6,P(否)=4/6。简化后,这是 1/3,这是 2/3。通过简单计算,我们得到这个值。我们也想合并它。这个在这里,这个在这里。记住,这是高收入记录的比例。我们有2条记录,所以实际上是 2/8。这个是低收入记录的比例,有6条记录,所以是 6/8,即 3/4。通过简单计算,我们得到这个值。类似地,我们想计算这里的信息增益。信息增益就是这个数减去这个数,即数字一减去这个,我们得到属性“收入”的增益。把这个复制到这里。
现在,我们已经计算了种族属性和收入属性的信息增益。然后现在转到“子女”属性。我不带你过一遍了。你可以回家自己看。所以我们有属性“子女”。信息增益在这里。下一件事,我们想找到某个属性。具有最大信息增益或较小信息增益的属性,这样我可以在后续过程中获得更多信息。

在接下来的过程中,我想做以下事情。你只需理解主要思想。我们有根节点。根节点有8条记录。我们想根据某个属性(可能是种族、收入或子女)将这些记录分成不同的部分。假设这是“子女”。然后我们将记录分成两部分。然后,子女属性为“是”的放在左侧,为“否”的放在右侧。左侧是记录2,3,4。右侧是记录1,5,6,7,8。我们想这样分割记录,使得我们获得最大的信息增益。谁想回答这个问题?我们想要最大的信息增益还是较小的信息增益?应该是最大的信息增益。所以这里哪个值最大?信息增益:收入是0.1,种族是0.3,子女是0.5。哪个值最大?0.5。所以我们想找到具有最大信息增益的属性,对吧?是的。所以我们将选择属性“子女”。我们理解我们将选择这个属性,它具有最大的信息增益。所以我们有这个属性“子女”。在原始数据中,左侧子女=“是”,右侧子女=“否”。左侧是记录2,3,4,如我所提到的。右侧是1,5,6,7,8。
然后通常我们关注目标属性。让我总结所有目标属性的统计:2,3,4,我们有三个“是”和零个“否”。1,5,6,7,8,我们有一个“是”和四个“否”。然后通常我们需要百分比。现在我们总结:这里100%是“是”,0%是“否”。这里20%是“是”,80%是“否”。现在我们完成了第一次分割。


构建决策树与停止条件


现在,在接下来的过程中,我们应该在哪里停止?这取决于用户需求。例如,超市经理。假设我是超市经理。我想要绿色框。其中一个值“是”或“否”应该是100%。我不需要在这里做任何事情,因为我已经达到了我想要的目标。然而,在右侧这里是80%“否”和20%“是”。我不满意。我想把它分成两部分,使得最后我们有100%“是”或100%“否”。这是超市经理设定的一个停止条件。假设这是我的停止标准,然后我将继续下一步。继续意味着我将再次分割这些记录,基于我们之前的思想。

怎么做?让我们再次进入全屏模式。全屏模式。

现在,我们想对右侧这部分进一步执行相同的过程。看看怎么做。目前,我们只有记录1,5,6,7,8,这意味着记录2,3,4不在这里。移除它们。现在我们考虑记录1,5,6,7,8。类似地,在不考虑输入属性的情况下,我们想考虑信息量。目标属性为“是”的概率是 1/5。目标属性为“否”的概率是 4/5。所以我们有 1/5 和 4/5,我们得到这样的熵值。
我们已经使用了“子女”属性。现在,我们有两个剩余属性用于分割。即“种族”属性和“收入”属性。让我们考虑“种族”属性。种族属性有两个可能的结果:黑人和白人。现在考虑黑人记录。黑人记录在这里。黑人记录中有一个“是”和三个“否”。所以我们知道 P(是)=1/4,P(否)=3/4。所以是 1/4 和 3/4。
类似地,对于白人记录,让我用白色,白人记录只有一条“否”,所以 P(是)=0,P(否)=1。所以我们有这个公式,你知道这等于零。然后合并这两个,我们知道熵,这对应黑人记录的比例,这里有四条记录,所以是 4/5。这对应白人记录的比例,1/5。通过计算器,我们得到这个值。然后信息增益就是这个值减去这个值。所以我们得到这个值。然后这个值,总结种族属性的这个值,我们得到这个结果。信息增益0.0729,明白吗?如果没有问题,我想你也可以理解,对于剩余属性“收入”,你可以自己做。我不会带你过一遍。好的,回家检查一下。对于属性“收入”,我们也可以计算信息增益是这个值。


这次我们需要将其分成两部分,我们应该选择哪个属性?我们想回答这个问题。

现在让我们看看。在信息增益中,你应该选择收入,因为信息增益最大。是的,信息增益最大。谢谢。好的,现在让我返回。让我们看看。现在我们将选择这个属性,然后我们将根据收入高低将其分成两部分。我们知道我们有记录1,5,6,7,8,我们圈出来。高收入是这条记录。所以我们左侧是记录1。右侧是记录5,6,7,8。类似地,总结目标属性值。左侧有一个“是”和零个“否”。右侧有零个“是”和四个“否”。然后绿色框总结:100%“是”和0%“否”。这里0%“是”和100%“否”。现在我们得到了这个。这达到了超市经理设定的停止条件。其中一个值是100%。所以这满足了超市的需求。然后我们停止。然后这是生成的决策树。然后假设我们有一个新客户,如我们提到的,子女=“否”且收入=“高”。那么我们将预测这个客户会购买保险单。如我所提到的,停止条件是由超市经理或用户设计的。我刚提到其中一个应该是100%。我们有不同种类的停止条件。例如,准确率或每个节点由我提到的。有些人可能使用树的最大高度,例如这里,树的最大高度等于2。假设超市经理规定树的最大高度最多为1。

如果是这种情况,那么树将是这样的。如果树的高度最多为1,那么我们不需要进一步分割。所以不同的停止条件会产生不同的决策树。

C4.5算法:对ID3的改进
现在,转到C4.5,实际上类似于ID3。我不知道学生以前是否学过。我不知道你是否知道这两者之间的区别。让我们看看这里,ID3我们刚学过,我们有输入度量。信息增益,如我们提到的,是使用输入属性之前的熵,减去使用输入属性之后的熵,这是我们之前学过的。C4.5算法。在我给出直观解释之前,我先给出公式,然后之后我会给出直观解释。这里的信息增益正是我们在这里看到的。好的,只是复制。然后我们需要用输入属性的分裂信息来调整这个差值。这是什么意思?分裂信息,这个属性信息,然后像这样,你可以看到我们有 P(v)。然后还有对数。然后求和。实际上,这是熵。这是熵。也许你很难理解这里的公式。让我用一个例子说明,然后在我说明后你会理解,我会给出直观解释。
现在,类似地,对于这个C4.5,整个过程完全相同。我们不考虑输入属性。我们只关注目标属性。好的,我们有一半“是”和一半“否”。所以我们有这样的东西,在我们使用输入属性之前,熵等于1。在我们使用输入属性之后的熵,我们使用相同的公式。好的,这是从前一行复制粘贴的。完全相同的东西。我不带你过一遍了,完全相同的东西。但现在这是新的东西。新东西我想放慢速度。种族属性的分裂信息定义如下。
种族属性等于黑人的概率。等于让我看看,4条记录,所以是 4/8。种族属性等于白人的概率。等于4条记录,所以是 4/8。所以这等于 1/2。这等于 1/2。所以我们理解我们有这个概率,这个概率,使用熵公式,1/2 这个和 1/2 这个。然后求和并取负,然后我们计算这个值。现在,信息增益更新为类似这样的东西。信息增益,如我们提到的,减去差值,然后除以这个分裂信息。然后通过计算器,是这个值减去这个值,然后除以一,我们得到这个值。然后最后,总结。这个种族属性的信息增益等于这个值。
类似地,我们也可以计算属性“收入”和属性“子女”。好的,让我再说一个收入属性。对于属性“收入”这里,从前一行复制粘贴。我不带你过一遍收入属性。好的,非常简单,关注这里收入。同样,收入等于“高”的概率。收入等于“低”的概率。让我们看看,高收入有2条记录。所以是 2/8。低收入有6条记录。所以是 6/8。所以我们有 2/8 在这里,6/8 在这里。通过计算器得到这个值。类似地,信息增益等于这个值。初始熵是这个值,减去这个值。然后除以这个值,通过计算器,我们得到这个值。让我们总结一下,我们有属性“收入”,等于这个,等于这个。因此,属性“子女”。我没做。你可以自己做。

C4.5算法的直观理解
现在,我们已经完成了关于C4.5的说明,但我还没有提到背后的直观理解。让我给出背后的直观理解,这更重要。让我们看看。也许我把它放在这里信息。首先,我需要给你一些例子,以便你理解。让我们看看。现在让我复制这个“子女”属性。事实上,我正在复制这个“子女”属性和“ID”属性。假设我们有这样的记录。我们有这样的东西。“是”,“是”。然后,“否”,“否”。然后,“否”,“否”。然后。我们有一个ID,假设我们有一个属性ID:1,2,3,4,5,6,7,8。然后类似这样的东西。我们想预测客户最后是否会购买保险单。然后我们类似这样的东西。现在,忘记所有的熵、C4.5、ID3等等。现在我想使用其中一个属性,“子女”或“ID”来预测保险。凭直觉。凭直觉,你认为我应该选择哪个属性?来预测一些值,对于保险属性。哪个属性,“子女”还是“ID”?谁想回答?凭直觉,我的问题是,现在我们有了“子女”属性和“ID”属性。如果你想为每个客户做预测,对于保险属性,你是选择仅用“子女”属性还是“ID”属性来做预测?谁想回答并举手?是的,我们应该使用“子女”属性。哦,为什么?是的,你的直觉是正确的。是的,“子女”属性。为什么?是的,只是你的直觉,是的,因为我们可以看到“子女”属性有一些,例如,聚类或分组。但对于“ID”,就像一些随机数,随机数。好的,实际上你,你接近要点了。好的,让我问你,这里我们有两个可能的值,对吧?这里我们有8个可能的值,对吧?然后你说我们有两个可能的值,它更泛化,泛化来描述数据集,对吧?是的,是的,因为我们只有两个可能的值。如果我们只是用,子女=“是”,然后是“是”,那么更容易描述数据集,对吧?是的。然而,对于ID,我们有很多很多不同的值。我可以说,如果我们有一些规则,规则ID=1,是;ID=2,是;ID=3,是;ID=4,是;ID=5,否;我们也可以有100%的置信度生成很多规则,但实际上,我们不会使用可能的值,对吧?是的,是的。原因是与ID相比,我们对“子女”属性有更多的泛化,对吧?是的,好的,谢谢。是的,谢谢。是的,所以我认为学生可能也理解,凭我们的直觉,“子女”属性是更好的预测属性,因为它更泛化。



现在,让我给你更多数字,然后你知道我在ID3中是什么意思。让我们看看在ID3中。在ID3中,如果我们想计算。“子女”属性。还有,“ID”属性,我们想计算。例如,信息增益。根据这个例子,根据这个例子,我不展示中间结果。我只展示最后一步。这个ID3的信息增益,让我把它放在右侧,以便你知道比较。现在,ID3在这里。好的,我计算了一些东西。好的,我跳过了,你可以在家检查。这应该等于0.548。然后对于ID这个属性,ID3,然后这等于一减去,让我看看0等于一。然后你可以看到ID文件。ID属性ID。对于分割,我们必须。属性ID用于分割。所以这与我们的直觉相矛盾。我想说的是,这与我们的直觉相矛盾。原因如下。让我写下来。实际上,直觉是这个蓝色的东西。ID3有更高的倾向去选择包含更多值的属性。如果你逐步进行,你会看到实际上确实如此。如果我们有更多的值,ID3会选择那个属性。选择那个属性。好的,你可以自己计算。好的,然后接下来,好的,如果你理解这个,好的,让我继续,好的,让我继续。好的,既然我没有给出公式,我想你可以自己检查。你可以在家验证这个说法。
然后现在我想转到C4.5。C4.5。我们有一个属性“子女”。然后我们有分裂信息,分裂信息。为了让你理解我在做什么,我想展示这个空间。“子女”的分裂信息,我们可以基于这个概率分布计算。这类似于 3/8。好的,log(3/8)。然后 -5/8 * log(5/8)。然后最后,我们得到这个值0.9544。然后这里的信息增益。对于这个“子女”属性,正是你记得的这个数字除以这个数字。所以让我写下来0.5488除以0.9544。最后,这个值等于0.5750。让我再做一个,然后我会做一些解释。ID,让我做ID。这个ID的分裂信息等于。让我给出公式 1/8。六。1/8 乘以八次。它乘以然后等于三。然后,再次,或者这个ID3正好等于这个数字除以3。1 除以三。所以你知道这等于0.333。所以你可以看到,根据“子女”属性的信息增益和ID的信息增益,好的,我们有这个值和这个值。当然,我们会选择较大的一个。所以我们必须选择。我们必须选择属性“子女”。我们将选择属性“子女”进行分割。好的,你可以看到这次C4.5将选择“子女”属性,这与我们的直觉一致。让我在这里写下原因。原因是,让我用绿色。让我写下。实际上,C4.5试图惩罚包含更多值的属性。让我在这里解释一下。让我用一些符号解释这里。现在,C4.5,如我提到的,在顶部,ID有8个值。C,好的,我们有两个值。好的,我们有很多值。你可以看到“子女”只有两个值。如果我们计算分裂信息,通常这个值非常小。ID,如果我们有很多值,如果我们计算分裂信息,通常,这是一个非常大的数字。如果你理解我们关于直觉的解释,我们想要更多的泛化,这意味着我们不想要更多的值,而我们有很多值。所以如果ID有很多值,那么这个信息必须非常大。所以信息增益,虽然这之后等于一,但我们除以这个大值,因为我们有更多可能的值,并且这个分裂非常大,除以它。所以这就是我们的意思,我们想要惩罚具有更多值的属性。所以我们除以这个分裂信息,使得这个值一由于更多的值而变得更小。所以我们理解C4.5正在做类似这样的事情。所以这里分裂信息可以帮助我们找到与我们想要的属性一致的属性。有问题吗?

CART算法:基尼指数
现在,让我们看最后一个。CART也是一个常见的决策树。常见的决策树给你。


看。我们也有输入度量。好的,像熵。但这次他们不使用熵。他们使用基尼指数或统计学中的基尼数,也来自数学。这等于这个方程。我稍后也会给出直观解释。让我们先遵循步骤。一减去一些概率的平方,然后求和。好的,看看我们在做什么。让我移除保险标注。类似地,类似地,我们一开始也不考虑输入属性。我们知道我们只关注目标属性。目标属性“购买保险”为“是”的概率,等于 4/8。所以这里,目标属性为“否”的概率,等于 4/8。然后这是 1/2。这等于 1/2。公式是 1 - (1/2)^2 - (1/2)^2。所以我们有这个方程。通过简单的计算器,1/2 非常简单。然后接下来,我想你记得这个过程。过程完全相同,完全相同。
现在我们只考虑“种族”属性。然后我们考虑黑人记录。好的,黑人记录。我想要黑人记录。我们有概率。P(是)=1/4。P(否)=3/4。所以根据那个方程,基尼指数 1 - (3/4)^2 - (1/4)^2。然后我想你也知道下一步。白人记录的熵,这是三个“是”和一个“否”。所以这里 P(是)=3/4,P(否)=1/4。所以 1 - (3/4)^2 - (1/4)^2,通过计算器得到这个值。类似地,我们可以用这个合并它,同样,黑人记录的比例和白人记录的比例,这之前已经说明过。通过计算器,我们得到这个值。还有信息增益是这个值减去这个值。然后我们得到这个值。让我总结一下,对于属性“种族”,我们有这个值。然后我们也对第二个属性“收入”做同样的计算。我不带你过一遍了。你可以回家自己看。你可以自己在家做。我们也可以找到这个种族属性的信息增益,抱歉,这应该是“收入”,收入应该等于0.167,还有对于属性“子女”,信息增益是问号问号,实际上课堂练习5问题1B也问了这个,你可以自己做。

现在我们完成了。我们已经完成了基尼指数。现在让我通过白板上的例子给出关于基尼指数的直观理解。让我找一些空间。让我在这里找空间。啊,这里。
在我解释之前,让我找这个空间,让我给你一些例子。假设我有一个容器。我们知道在这个容器里,有两种类型的球。我们有两种类型的球。我们有红球,还有白球,两种类型的球。然后,我取出一个球的概率是 P(X)。我取出一个球的概率是 P(Y)。现在,让我问你。假设我想取出两个球。有放回。有放回意味着我取出一个球后,我会把它放回容器,所以 P(X) 和 P(Y) 保持不变。所以我们理解我们有放回。所以我们理解当我们取出两个球时,我们取出X球的概率是 P(X),如果我们取出Y球,那么概率等于 P(Y)。现在,让我给出这个问题。问题是,两个球具有不同值的概率。在我们的案例中,实际上,这个不同值对应于保险值,实际上这两个值是“是”或“否”。如果这两个球具有不同的值,是什么意思?好的,实际上,我想你知道在数学中,通常我们可以用补集来计算它。谁想告诉我这是什么?你可以举手。我的问题是,现在场景是我们有一个容器。我们有两种类型的球。X球的概率是 P(X)。Y球的概率是 P(Y)。如果我取出两个球(有放回),两个球具有不同值的概率是多少?抱歉,也许应该是具有不同值。应该具有不同值。如果两个球具有两个不同的值。那么这个公式是什么?这个公式是什么?好的,谁想告诉我。是的,也是成双。是 1 - P(X)^2 - P(Y)^2。是 1 - P(X)^2 - P(Y)^2。实际上,你这里是什么意思?物理意义是两个球具有相同的值X,以及两个球这里具有相同的值Y,对吧?是的,好的,谢谢,是的。好的,现在你可以看到,在我们写下这样的东西之后,我们有这个方程,1 减去某个平方减去某个平方,正是我们在这里讨论的。好的,我们在这里讨论过。我想说的是,基尼指数类似于这样的东西。类似于这样的东西。啊,继续,让我继续继续。示例一。示例一,还有示例二。让我给出这个 P(X)。假设也使用类似这样的东西。假设我们有概率 P(X)=1 和 P(Y)=0。那么如果我们计算这个概率,让我用 P 表示,等于 1 - 1^2 - 0^2,等于 0。对于另一种情况,P1=0.5,P=1 - 0.5^2 - 0.5^2,然后等于 0.5。我们也理解,我们也理解,如果我们不用眼睛计算这个基尼指数,我们知道这个有更多信息。而后一个没有太多信息。我们理解这与熵一致。如果这个值非常小,那么我们有很多信息。如果这个值较大,我们在中间没有信息,我们在中间值,我们也在中间值。所以我们理解这个结论。结论是,如果 P 值较小,那么我们拥有更多信息。我们拥有更多信息。这与我们之前看到的一致。我们之前看到过。更多信息意味着我们对此有高概率。也许让我回到这个黑色的东西。如果 P 较小,如果两个球具有不同的值,具有不同值的概率较低,这意味着两个球更可能具有相同的值,相同的值意味着类似这样的东西,类似这样的东西。很可能两个球非常相似,就像我们有这个更多信息。所以这与黑色的东西一致。对你有任何问题吗?

总结

在本节课中,我们一起学习了决策树ID3算法的第一部分。我们从信息论的基础概念“熵”开始,理解了它如何衡量信息的不确定性。接着,我们深入探讨了ID3算法如何利用信息增益来选择最佳属性进行数据分割,从而构建决策树。我们还简要介绍了C4.5算法如何通过引入分裂信息来改进ID3,避免选择具有过多取值的属性,以及CART算法使用的基尼指数作为另一种划分标准。通过具体的计算示例和直观解释,我们掌握了这些核心算法的工作原理和区别。
011:朴素贝叶斯分类器

概述
在本节课中,我们将要学习贝叶斯分类器,这是一种基于概率统计的分类方法。我们将从最简单的朴素贝叶斯分类器开始,理解其核心假设和计算过程,然后过渡到更复杂的贝叶斯信念网络,学习如何处理属性间的依赖关系。

条件概率与贝叶斯规则

上一节我们介绍了分类器的基本概念,本节中我们来看看其背后的数学基础:条件概率和贝叶斯规则。
条件概率的定义如下。对于随机变量 A 和 B,在事件 B 发生的条件下,事件 A 发生的概率为:
P(A|B) = P(A ∩ B) / P(B)
从条件概率的定义,我们可以推导出贝叶斯规则:
P(A|B) = P(B|A) * P(A) / P(B)
贝叶斯规则的意义在于,有时直接计算 P(A|B) 很困难,但计算其“反向”条件概率 P(B|A) 以及先验概率 P(A) 和 P(B) 却相对容易。这个规则允许我们交换条件部分和结果部分,从而利用更容易获得的信息进行推断。




朴素贝叶斯分类器
理解了概率基础后,本节我们来看看最简单的贝叶斯分类器——朴素贝叶斯分类器。


朴素贝叶斯分类器有一个核心的“朴素”假设:在给定目标属性的条件下,所有输入属性之间是相互独立的。



这意味着,如果我们知道目标属性(例如“是否购买保险”),那么输入属性(如“种族”、“收入”、“是否有子女”)的概率可以独立地相乘。其独立性假设公式如下:
P(种族, 收入, 子女 | 保险) = P(种族 | 保险) * P(收入 | 保险) * P(子女 | 保险)
分类过程示例
假设我们的目标是根据客户信息预测其是否会购买保险。我们有一个包含8条记录的训练集。
以下是分类的具体步骤:


-
设定目标:计算在给定客户信息(种族=白人,收入=高,子女=无)的条件下,该客户购买保险(保险=是)的概率。即计算
P(保险=是 | 种族=白, 收入=高, 子女=无)。 -
应用贝叶斯规则:由于直接计算困难,我们应用贝叶斯规则:
P(保险=是 | 信息) = P(信息 | 保险=是) * P(保险=是) / P(信息) -
应用朴素假设:在“保险=是”的条件下,假设各属性独立:
P(信息 | 保险=是) = P(种族=白 | 保险=是) * P(收入=高 | 保险=是) * P(子女=无 | 保险=是) -
从训练数据估计概率:
P(保险=是) = 4/8 = 0.5P(种族=白 | 保险=是) = 3/4 = 0.75P(收入=高 | 保险=是) = 2/4 = 0.5P(子女=无 | 保险=是) = 1/4 = 0.25

-
计算分子:
0.75 * 0.5 * 0.25 * 0.5 = 0.046875 -
计算分母与比较:分母
P(信息)对于“是”和“否”两类是相同的,因此我们只需比较分子部分。类似地计算“保险=否”的分子,得到0.0。因为0.046875 > 0.0,所以我们预测该客户会购买保险。
核心要点:朴素贝叶斯分类器通过比较不同类别下的后验概率大小来进行预测,而无需计算精确的概率值,因为分母是相同的。
贝叶斯信念网络

上一节我们介绍了属性独立的朴素贝叶斯分类器,但在现实中,属性间往往存在依赖关系。本节中我们来看看更通用的模型——贝叶斯信念网络。
贝叶斯信念网络通过一个有向无环图来刻画属性间的依赖关系。图中的节点代表属性,边代表依赖关系。与朴素贝叶斯不同,它不要求所有属性在给定目标下条件独立。
网络结构与条件概率表
以一个医疗诊断网络为例,节点包括:锻炼(E)、饮食(D)、心脏病(HD)、血压(BP)、胸痛(CP)。边表示:锻炼和饮食影响心脏病;饮食影响胃灼热(HB);心脏病影响血压和胸痛。


每个节点都附有一个条件概率表,量化其与父节点之间的关系。例如,P(HD=是 | E=是, D=健康) = 0.25。
条件独立性
贝叶斯信念网络的关键特性是条件独立性。定义:如果给定Z时,X的概率分布与Y无关,则称X在给定Z的条件下条件独立于Y。即:
P(X | Y, Z) = P(X | Z)
在信念网络中,一个重要的性质是:一个节点在给定其父节点的条件下,条件独立于它的所有非后代节点。这个性质可以大大简化概率计算。
推理示例
我们通过三个逐步复杂的例子,演示如何利用网络进行推理:
- 无额外信息:预测一个没有任何已知信息的新患者患心脏病的概率。我们需要对所有可能影响HD的父节点状态(E和D的组合)进行求和。
P(HD=是) = Σ_{E,D} P(HD=是 | E, D) * P(E) * P(D)
通过计算得到P(HD=是) ≈ 0.49,P(HD=否) ≈ 0.51,因此判断该患者不太可能患心脏病。


-
已知高血压:已知患者血压高(BP=高),预测其患心脏病的概率。这里需要应用贝叶斯规则,因为已知信息是子节点。
P(HD=是 | BP=高) = P(BP=高 | HD=是) * P(HD=是) / P(BP=高)
通过计算得到P(HD=是 | BP=高) ≈ 0.803,因此判断该患者很可能患心脏病。 -
已知多项信息:已知患者锻炼(E=是)、健康饮食(D=健康)且高血压(BP=高),预测其患病概率。这涉及更复杂的条件独立性应用和贝叶斯规则。
最终计算得到P(HD=是 | E=是, D=健康, BP=高) ≈ 0.586,因此判断该患者较可能患心脏病。

课堂练习解析
最后,我们通过一个综合练习来巩固对贝叶斯信念网络推理的理解。
问题:已知患者锻炼(E=是)、高血压(BP=高)、有胸痛(CP=是),利用给定的信念网络,预测其是否患心脏病(HD)。
推理过程:
- 目标:计算
P(HD=是 | E=是, BP=高, CP=是)。 - 应用贝叶斯规则,将目标转换为涉及
P(BP=高, CP=是 | HD=是, E=是)的表达式。 - 利用条件独立性简化:
- 给定父节点HD,其子节点BP和CP条件独立。
- E是HD的父节点,在计算涉及HD子节点的概率时,E作为非后代节点,在给定HD的条件下可以被移除。
- 进一步展开,对HD的所有可能取值求和,并利用网络中的条件概率表查找数值。
- 计算得到
P(HD=是 | ...) ≈ 0.65,大于0.5。 - 结论:该患者很可能患有心脏病。

总结
本节课中我们一起学习了两种重要的贝叶斯分类器。
- 朴素贝叶斯分类器:基于“属性条件独立”的强假设,计算简单高效,适用于特征维度高且相关性较弱的场景。
- 贝叶斯信念网络:通过图模型显式地表示属性间的依赖关系,更加灵活和强大。其推理核心在于利用条件独立性简化计算,并通过贝叶斯规则在证据(观察到的属性)和查询目标之间建立联系。


理解条件概率、贝叶斯规则以及条件独立性是掌握这些模型的关键。
数据挖掘与知识发现:12:最近邻分类器 🧠


在本节课中,我们将要学习一种非常直观且简单的分类方法——最近邻分类器。我们将通过一个学生是否购买教科书的例子,来理解其核心思想和工作流程。

上一节我们介绍了分类问题的基本概念,本节中我们来看看一个具体的分类算法:最近邻分类器。这是一种基于实例的学习方法,其核心思想非常简单:通过比较新数据点与已知数据点的“距离”来进行预测。

现在,我们来看一个具体的例子。假设我们有以下学生数据,包含计算机和历史两门课程的成绩,以及一个目标属性:该学生是否购买了教科书。

如上图所示,每个点代表一个学生。横轴是计算机成绩,纵轴是历史成绩。点的形状(例如圆形或方形)代表其标签(是否购书)。现在,我们有一个新学生,其计算机成绩为95分,历史成绩为35分,我们不知道他是否会购买教科书。
最近邻分类器的做法如下:
1-最近邻分类器
首先,我们来看最简单的形式:1-最近邻(1-NN)。以下是其步骤:
- 寻找最近邻:计算新数据点(95, 35)与所有已知数据点的距离(例如欧氏距离)。
- 分配标签:找到距离最近的那个邻居,并将其标签直接赋予新数据点。
在这个例子中,距离新点最近的点是“负例”(未购书)。因此,我们预测这位新学生不会购买教科书。
理解了1-最近邻后,我们可以将其推广到更通用的形式:K-最近邻分类器。这里的K是一个由用户(如超市经理)设定的参数。
K-最近邻分类器
假设我们设定 K = 3。以下是K-最近邻分类器的工作步骤:
- 寻找K个最近邻:找到距离新数据点最近的K个已知数据点。
- 多数投票:查看这K个邻居的标签,将其中占多数的标签作为新数据点的预测结果。
在这个例子中,距离最近的3个邻居里,有2个是“负例”(未购书),1个是“正例”(购书)。根据多数原则,我们以约66.7%的置信度预测该学生不会购买教科书。
在结束之前,有一个重要的实践细节需要说明。在设置K值时,通常建议将其设为一个奇数。
为什么K通常是奇数?
原因在于避免平局。如果K是偶数(例如K=4),可能会出现2个正例和2个负例的情况,导致无法通过多数投票做出决定。设置为奇数可以确保投票总能产生一个明确的结果。这类似于我们社会中的委员会通常由奇数名成员组成,以避免表决时出现僵局。




本节课中我们一起学习了最近邻分类器。我们首先通过1-最近邻理解了其核心思想:物以类聚,即一个数据点的类别可以由其最近邻居的类别决定。接着,我们将其推广到K-最近邻,通过多数投票机制来提高预测的稳健性。最后,我们讨论了将K值设为奇数这一重要实践技巧,以避免决策时出现平局。这是一种简单而强大的分类方法,为理解更复杂的模型奠定了基础。
013:线性支持向量机(第一部分)
在本节课中,我们将学习支持向量机(SVM)的基本概念,特别是线性支持向量机。我们将了解其工作原理、核心公式以及如何通过优化方法找到最佳分类边界。
概述
我们已经学习了决策树和最近邻分类器。今天,我们将讨论支持向量机,并初步介绍神经网络。支持向量机有两种变体:线性支持向量机和非线性支持向量机。本节我们将从简单的线性支持向量机开始。
线性支持向量机的优点在于其结果可以可视化,并且如果原始数据能够被很好地划分,其分类准确率会非常高。
线性支持向量机的基本思想
假设我们有一个数据集,包含两个输入属性 x1 和 x2,以及八个数据点。其中,蓝色点代表目标属性值为“是”(例如,+1),黄色点代表目标属性值为“否”(例如,-1)。
在这个二维空间中,我们可以画一条直线将整个数据集分成两部分:一部分包含所有蓝点,另一部分包含所有黄点。这就是线性可分的情况。
这条直线的方程可以表示为:
W1 * x1 + W2 * x2 + B = 0
其中,W1、W2 和 B 是常数。对于所有蓝点,将其坐标代入方程左侧,结果会大于或等于0;对于所有黄点,结果会小于或等于0。
选择最佳分割线
实际上,我们可以画出多条直线来分割数据,例如分割线1、2、3、4。那么,我们应该选择哪一条呢?
上一节我们介绍了分割线的概念,本节中我们来看看如何选择最优的分割线。理想情况下,我们应选择那条使“间隔”最大化的直线。
间隔是指分割线到其两侧最近数据点的距离之和。最大化间隔的好处是,即使数据中存在一些噪声或轻微重叠,分类器也能保持较好的鲁棒性。
以下是最大化间隔的直观原因:
- 间隔小的分割线对噪声敏感,容易导致错误分类。
- 间隔大的分割线为数据点的分布留出了缓冲空间,容错能力更强。
间隔的数学表示
设我们的分割线方程为 W1x1 + W2x2 + B = 0。我们可以定义两条平行的边界线:
- 上边界线:W1x1 + W2x2 + B = +1
- 下边界线:W1x1 + W2x2 + B = -1
所有蓝点应满足 W1x1 + W2x2 + B >= +1。
所有黄点应满足 W1x1 + W2x2 + B <= -1。
为了统一表示,我们引入数据点的标签 y(蓝点为+1,黄点为-1)。那么,对于每一个数据点 (x1, x2, y),都需要满足:
y * (W1x1 + W2x2 + B) >= 1
这个约束条件对于数据集中的每一个点都成立。如果有8个数据点,我们就有8个这样的不等式约束。
两条边界线之间的垂直距离,即“间隔”,可以通过公式计算:
间隔 = 2 / sqrt(W1² + W2²)
优化问题
我们的目标是最大化这个间隔。由于最大化 2 / sqrt(W1² + W2²) 等价于最小化 sqrt(W1² + W2²),进而等价于最小化 (W1² + W2²)/ 2。
因此,线性支持向量机的核心优化问题可以表述为:
最小化目标函数:(1/2) * (W1² + W2²)
约束条件:对于每一个数据点 i,满足 y_i * (W1x1_i + W2x2_i + B) >= 1
这是一个带线性约束的二次规划问题。我们将其转化为这种标准形式的原因是,对于二次规划问题,存在大量成熟、高效的优化求解器(如某些数学软件或编程库中的工具),我们可以直接利用这些工具快速找到最优的 W1、W2 和 B,而无需自己从头设计复杂的优化算法。
从二维到高维
我们刚刚描述的是二维空间的情况,使用一条直线(一维超平面)进行分割。
对于n维空间(n>2),我们可以使用一个(n-1)维的超平面来分割空间。例如,在三维空间中,我们使用一个平面进行分割。线性支持向量机的原理可以完美地推广到高维空间。
线性不可分与非线性SVM简介
然而,有时即使在二维空间中,蓝色点和黄色点也会混杂在一起,无法用一条直线完美分割。
下一节我们将简要介绍非线性支持向量机。其核心思想是:
- 步骤一:通过一个非线性映射函数,将原始数据从当前维度变换到一个更高维度的空间。
- 步骤二:在这个更高维的空间中,数据可能变得线性可分。此时,我们再应用之前所学的线性支持向量机方法,找到一个超平面来进行分割。

这就好比在二维平面上交织在一起的两类点,当我们将它们“抬升”到三维空间后,或许就能用一个平面轻松分开了。关于非线性映射的具体细节,大家可以在专门的机器学习课程中深入学习。

总结

本节课中我们一起学习了线性支持向量机的基础知识。我们了解了其目标是寻找一个最大化分类间隔的超平面,并将该问题形式化为一个二次规划优化问题。我们还简要提到了当数据线性不可分时,可以通过映射到高维空间来处理,这引出了非线性支持向量机的概念。
014:神经网络(第1部分)
在本节课中,我们将要学习神经网络的基本概念。神经网络是一种受人类大脑启发的计算模型,它由大量相互连接的简单处理单元(神经元)构成。我们将从单个神经元的工作原理开始,逐步理解其如何通过调整连接权重来学习和记忆信息,并最终介绍多层感知机的基本思想。
从人脑到人工神经元
上一节我们介绍了支持向量机等分类模型,本节中我们来看看神经网络。
神经网络是一种由简单且高度互连的处理元素组成的计算系统。这些处理元素被称为神经元或单元。这种方法受到大脑处理信息方式的启发,与我们之前学习的决策树等传统计算机处理方式完全不同。
信息处理发生在许多相同且简单的处理单元(神经元)中。神经元之间的连接具有权重,这些权重用于存储知识,类似于大脑中化学物质的含量。
神经网络有两个主要优势:
- 并行处理:每个神经元可以独立且同时地操作。
- 容错性:即使少量神经元失效,整个系统仍能运行,只是性能略有下降。
单个神经元的结构与激活函数
了解了神经网络的灵感来源后,本节中我们来看看单个神经元是如何工作的。
一个神经元通常分为前侧和后侧。前侧接收输入并进行计算,后侧则通过一个激活函数产生输出。
以下是神经元前侧的计算公式:
net = w1*x1 + w2*x2 + b
其中,x1 和 x2 是输入,w1 和 w2 是连接权重,b 是偏置项。计算得到的 net 值将传递给激活函数。
激活函数将 net 值映射到最终的输出 y。常见的激活函数包括:
- 阶跃函数(硬极限函数):如果
net > 0,则y = 1;否则y = 0。 - 线性函数(恒等函数):
y = net。 - 修正线性单元:
y = max(0, net)。这是目前非常常用的激活函数。 - Sigmoid函数:
y = 1 / (1 + e^(-net))。其输出值在0到1之间。 - 双曲正切函数:
y = (e^(2*net) - 1) / (e^(2*net) + 1)。其输出值在-1到1之间。
选择哪种激活函数通常取决于我们希望输出值落在哪个范围内。
神经元的训练:权重更新
知道了神经元如何计算输出后,本节中我们来看看它如何通过学习来调整自己。
训练过程就是根据预测输出与期望输出之间的误差,来更新权重 w1、w2 和偏置 b 的过程。这模拟了大脑中化学物质(记忆)根据经验增强或减弱的过程。
权重更新遵循以下公式:
w1_new = w1_old + α * (d - y) * x1
w2_new = w2_old + α * (d - y) * x2
b_new = b_old + α * (d - y)
其中:
α是学习率,控制每次更新的幅度。d是期望输出(目标值)。y是神经元的实际输出。(d - y)是误差。
如果预测正确(y 等于 d),则误差为0,权重不会更新。如果预测错误,权重就会根据误差大小和输入值进行相应调整。
训练过程示例:学习“或”运算
为了更直观地理解,本节我们通过一个具体例子来演示神经元如何学习简单的“或”逻辑运算。
假设我们的训练数据如下:
| x1 | x2 | 目标输出 (d) |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
我们使用Sigmoid函数作为激活函数,并设置初始权重 w1 = 1, w2 = 1, 偏置 b = 0,学习率 α = 0.1。
训练一个“周期”的步骤如下:
- 输入前向传播:取第一条数据
(0, 0, 0)。- 计算
net = 1*0 + 1*0 + 0 = 0。 - 计算输出
y = sigmoid(0) ≈ 0.5。
- 计算
- 误差反向传播:比较输出
y≈0.5与期望输出d=0。- 误差
(d - y) = 0 - 0.5 = -0.5。 - 更新权重:
w1_new = 1 + 0.1 * (-0.5) * 0 = 1w2_new = 1 + 0.1 * (-0.5) * 0 = 1b_new = 0 + 0.1 * (-0.5) = -0.05
- 误差
- 用更新后的参数,对数据集中剩下的
(0,1),(1,0),(1,1)重复步骤1和2。
完成对所有数据的一次处理称为一个“周期”。我们可以设置停止条件,例如:
- 达到最大周期数(如100次)。
- 总体误差(如所有数据误差平方和)低于某个阈值(如0.001)。
通过多次周期的学习,神经元的权重会逐渐调整,使其输出越来越接近正确的“或”运算结果。
从单层到多层感知机
我们已经看到单个神经元可以工作,但它有局限性。本节中我们来看看更强大的多层神经网络。
单个神经元只能解决线性可分问题(即可以用一条直线或一个平面将不同类别的点分开)。对于“异或”等非线性可分问题,单个神经元无法解决。
幸运的是,通过组合多个神经元形成多层感知机,我们可以解决非线性问题。一个典型的多层感知机包括:
- 输入层:接收原始数据。
- 一个或多个隐藏层:进行复杂的特征变换。隐藏层通常使用ReLU等激活函数。
- 输出层:产生最终结果。对于分类问题,输出层常使用Sigmoid或Softmax函数。
理论研究证明,具有至少一个隐藏层的多层感知机是一个通用函数逼近器,理论上可以拟合任何复杂的函数。
当网络层数非常多(例如超过10层)时,我们称之为深度网络。使用深度网络进行训练和学习的过程,就是深度学习。深度学习因其强大的能力,在学术界和工业界都备受关注。
多层网络的前向与反向传播
对于多层网络,训练的核心思想仍然是前向传播和反向传播,只是过程更复杂。
以下是多层网络训练一个周期的流程:
- 前向传播:
- 从输入层开始,数据依次通过每个隐藏层,最终到达输出层,计算出预测值
y。 - 在每一层,每个神经元都执行我们之前介绍过的
net计算和激活函数映射。
- 从输入层开始,数据依次通过每个隐藏层,最终到达输出层,计算出预测值
- 反向传播:
- 计算输出层的预测值
y与目标值d之间的误差。 - 这个误差从输出层开始,反向逐层传播回前面的网络层。传播过程中,会使用链式法则等优化方法计算每一层神经元对总误差的“贡献度”(梯度)。
- 根据计算得到的梯度,按照
权重 = 权重 + 学习率 * 梯度的规则,从输出层到输入层依次更新所有权重和偏置。
- 计算输出层的预测值
通过反复迭代这个过程,整个网络的参数得到优化,从而能够学习输入和输出之间复杂的映射关系。



本节课中我们一起学习了神经网络的基本原理。我们从人脑的启发开始,理解了单个神经元的结构、激活函数以及通过权重更新进行学习的过程。通过示例,我们看到了神经元如何训练。我们也认识到单个神经元的局限性,并由此引出了强大的多层感知机模型,了解了其基本结构和前向/反向传播的训练思想。神经网络,特别是深度学习,是当前数据挖掘和机器学习领域的核心工具之一。
015:循环神经网络 (RNN) 概述
在本节课中,我们将要学习循环神经网络。这是一种特殊的神经网络,能够处理数据记录之间存在依赖关系的情况,例如时间序列数据。我们将从基本概念入手,逐步了解其工作原理,并介绍两种重要的变体:LSTM和GRU。
基本循环神经网络 (Basic RNN)
上一节我们介绍了传统神经网络假设数据记录之间是独立的。然而,在许多实际场景中,当前记录与之前的记录是相关的。例如,股票价格、温度读数等时间序列数据,当前值往往依赖于过去的值。为了捕捉这种依赖性,我们引入了循环神经网络。
循环神经网络的核心思想是在网络中引入一个“循环”或“记忆”机制。这使得网络在处理当前输入时,能够参考之前步骤的信息。
以下是RNN的基本结构和工作原理:
- 结构:一个基本的RNN单元包含一个内部状态变量
S_t,用于存储记忆。在每个时间步t,它接收当前输入X_t和上一个时间步的内部状态S_{t-1},经过一个激活函数(如tanh或ReLU)处理后,产生当前输出Y_t和新的内部状态S_t。 - 公式:基本RNN的核心计算可以表示为:
S_t = activation_function(W * [X_t, S_{t-1}] + b)Y_t = S_t(有时会经过另一个线性变换)
其中,W是权重矩阵,b是偏置项,[X_t, S_{t-1}]表示将两个向量拼接起来。
- 训练:RNN的训练也分为前向传播和反向传播两个步骤。前向传播按时间顺序依次计算每个时间步的输出和状态。反向传播则通过时间(Backpropagation Through Time, BPTT)算法来更新权重,这与传统神经网络的反向传播类似,但需要考虑时间维度上的梯度流动。
基本RNN结构简单,但也存在一些局限性,例如难以学习长期依赖关系(梯度消失/爆炸问题),并且由于结构相对简单,模拟复杂记忆模式的能力有限。
长短期记忆网络 (LSTM)
上一节我们介绍了基本RNN及其局限性。为了解决这些问题,研究者提出了长短期记忆网络。LSTM通过引入更复杂的“门”结构,能够更有效地学习和记忆长期依赖关系。
LSTM的设计灵感来源于人脑的记忆过程。它主要包含三个关键特性,并通过六个组件来实现:
- 遗忘特性:决定从内部状态(记忆)中丢弃哪些旧信息。由“遗忘门”实现。
- 输入特性:决定将多少新信息存入内部状态。这分为两步:1) “输入门”决定更新哪些值;2) “输入激活门”(通常使用tanh)创建一个新的候选值向量。
- 输出特性:基于当前的内部状态,决定输出什么。这同样分为两步:1) “输出门”决定输出内部状态的哪些部分;2) 将内部状态通过tanh激活并与输出门相乘得到最终输出。
以下是LSTM在一个时间步 t 的计算公式:
- 遗忘门:
f_t = σ(W_f · [h_{t-1}, x_t] + b_f) - 输入门:
i_t = σ(W_i · [h_{t-1}, x_t] + b_i) - 候选记忆:
\tilde{C}_t = tanh(W_C · [h_{t-1}, x_t] + b_C) - 更新细胞状态:
C_t = f_t * C_{t-1} + i_t * \tilde{C}_t - 输出门:
o_t = σ(W_o · [h_{t-1}, x_t] + b_o) - 最终输出:
h_t = o_t * tanh(C_t)
其中,σ 是sigmoid函数,* 表示逐元素相乘,h_{t-1} 是上一个时间步的输出(也作为当前输入的一部分),C_t 是细胞状态(长期记忆)。
LSTM的结构比基本RNN复杂,因此能捕捉数据中更复杂的模式,记忆更长的序列,但相应的训练时间也更长。
门控循环单元 (GRU)
上一节我们介绍了强大的LSTM。为了在保持性能的同时降低模型复杂性,研究者提出了门控循环单元。GRU可以看作是LSTM的一个简化变体,它将遗忘门和输入门合并为一个“更新门”,并混合了细胞状态和隐藏状态。
GRU同样模拟了记忆过程,但组件更少,主要包含:
- 重置特性:通过“重置门”来决定如何将新的输入与过去的记忆(以上一时刻的输出
h_{t-1}为参考)结合。这决定了哪些过去信息需要被“忽略”。 - 输入特性:决定当前输入信息的重要性(相当于输入权重),通过“输入激活门”实现。注意,GRU没有单独的“输入比例门”。
- 更新特性:通过“更新门”来平衡过去记忆
h_{t-1}和当前候选记忆\tilde{h}_t对当前输出h_t的贡献比例。这是GRU的核心,它决定了保留多少旧记忆和加入多少新记忆。
以下是GRU在一个时间步 t 的计算公式:
- 重置门:
r_t = σ(W_r · [h_{t-1}, x_t] + b_r) - 更新门:
z_t = σ(W_z · [h_{t-1}, x_t] + b_z) - 候选激活:
\tilde{h}_t = tanh(W · [r_t * h_{t-1}, x_t] + b) - 最终输出:
h_t = (1 - z_t) * h_{t-1} + z_t * \tilde{h}_t
GRU由于参数更少,结构更简单,通常训练速度比LSTM更快,且在某些任务上能用更少的数据达到相近的效果。它和LSTM一样,也可以构建多层网络并在每层使用多个记忆单元。
总结



本节课中我们一起学习了循环神经网络。我们从基本RNN开始,了解了它如何通过内部状态处理序列依赖。接着,我们探讨了更强大的LSTM,它通过精细设计的遗忘门、输入门和输出门,有效地解决了长期依赖问题。最后,我们学习了GRU,它是LSTM的一种简化版本,通过合并门结构和参数,在保持性能的同时提高了计算效率。这三种模型是处理序列数据(如自然语言、时间序列预测)的基石,理解它们的原理对于深入学习深度学习至关重要。
016:引言

在本节课中,我们将要学习数据仓库的基本概念,特别是其核心思想——预计算。我们将了解数据仓库如何通过提前存储查询结果来加速查询响应,并探讨如何高效地选择要预计算的查询以减少存储开销。
数据仓库与在线分析处理
上一节我们介绍了数据挖掘的广阔领域,本节中我们来看看数据仓库这一具体应用。数据仓库是用于数据分析的集中式存储库。在外部世界中,一些学生也在外部工作,这也被称为OL。有些人仍然称其为OL,其含义是在线分析处理。OLAP即在线分析处理。通常人们不会说“在线分析处理”,而是说“OLAP”。许多公司使用数据仓库进行数据分析。

让我们看一个例子。这是我们的第一个示例图示。这是用户,这是数据库。如果我们有一些查询,提出查询后,我们可能需要等待很长时间才能获得结果。这就是我们学过的查询过程,可能需要很长时间才能知道结果。而在数据仓库中,我们想说的是,让我也用白板来图示说明。
查询延迟问题
以下是查询延迟的具体例子。
- 查询一:查找居住在例如香港科技大学,并且来自例如香港的学生名单。数据库可能非常庞大,查询可能非常复杂。我们可能需要等待一天才能获得答案,例如Raymond、Peter、Mary等。
- 查询二:查找居住在科大,但来自例如中国大陆的学生名单。我们可能获得另一个答案,例如John等。同样,由于数据库庞大且查询结构复杂,我们可能也需要等待一天。
一般来说,我们可能有Q个查询,例如多达1000个。如果每个用户都提出这样的查询,那么他们可能需要等待很长时间才能获得结果。
数据仓库的预计算思想
我想说的是,在数据仓库中,在实际用户提出查询之前,数据库管理员或公司经理会提前计算这个查询的答案,并将其存储在硬盘中。在用户触发这个查询之前,答案已经存在于我的硬盘里了。
现在我们有整个故事。查询以及其答案被存储在硬盘中。这被称为数据仓库。数据仓库预计算了结果,在用户提问之前,答案就已经存储好了。
因此,当用户提出这个问题时,由于答案已在硬盘中,我立即查找表格并读取这个答案。我们可能只需要一秒钟就能找到答案,然后将其返回给学生或用户。所以优势在于查询速度快,响应时间短。
核心问题:高效预计算
现在让我来阐述问题。实际上,我们想要解决的问题是:目前,如果我们理解到存在许多许多可能的查询,若为每一个可能的查询都存储答案,这将非常臃肿,会占用硬盘大量空间,这是不可取的。
在接下来的内容中,我们希望找到一些智能技术来选择一些具有代表性的查询进行预计算,这样我只需在硬盘中存储少量数据,同时仍然能够非常快速地回答查询。
数据立方体示例
让我们看看我想说什么。问题如下:我们从供应商处购买零件,然后以销售价格卖给客户。这是表T,包含零件、供应商、客户和销售价格。
- 零件P1由供应商S1供应,卖给客户C1,这是销售价格。
- 这是表格。
通常,这类数据仓库通常以立方体的形式呈现。让我们看看,我们有三个维度,这是度量维度。让我用动画或PowerPoint中的标注来说明。
以下是数据立方体的构建过程:
- 第一个数据点:P1, S1, C1, 值为4。
- 第二个数据点:P3, S1, C2, 值为3。

你理解了这一点。我有一个数据仓库中的技术术语,这被称为数据立方体,就像一个立方体。
总结


本节课中我们一起学习了数据仓库的基本原理。我们了解到,数据仓库通过预计算查询结果来显著提升查询响应速度。同时,我们也认识到,为所有可能的查询进行预计算会带来巨大的存储开销。因此,核心挑战在于如何智能地选择一部分代表性的查询进行预计算,从而在查询速度和存储成本之间取得平衡。我们还通过一个销售数据的例子,初步认识了数据立方体这一数据仓库中常见的多维数据结构。
017:基本概念 第一部分

在本节课中,我们将学习数据仓库中的一个核心概念:物化视图及其增益计算。我们将通过一个简单的销售数据表例子,理解如何通过SQL的GROUP BY和聚合操作生成不同粒度的汇总视图,并计算物化特定视图所带来的性能增益。


概述与背景
上一节我们介绍了数据仓库的基本背景,本节中我们来看看一个具体的例子。假设我们有一张销售记录表 T,包含以下字段:part(零件)、customer(客户)、supplier(供应商)和 selling_price(售价)。其内容如下:
| part | customer | supplier | selling_price |
|---|---|---|---|
| P1 | C1 | S1 | 4 |
| P3 | C2 | S1 | 3 |
| P2 | C1 | S3 | 7 |
理解基础查询与分组


首先,我们执行一个基础的SQL查询。以下是按part和customer分组并计算总售价的语句:
SELECT part, customer, SUM(selling_price)
FROM T
GROUP BY part, customer;
这个查询的含义是:从表 T 中,按照part和customer的组合进行分组,并对每个组内的selling_price求和。对于我们的示例数据,分组和计算结果如下:
(P1, C1)组:售价总和为 4。(P3, C2)组:售价总和为 3。(P2, C1)组:售价总和为 7。
因此,查询结果是一个包含3行数据的新视图,我们将其记为 PC 视图(代表Part-Customer),其大小为3。
接下来,我们看另一个查询,它只按customer分组:


SELECT customer, SUM(selling_price)
FROM T
GROUP BY customer;
这个查询的结果是:
C1组:售价总和为 4 + 7 = 11。C2组:售价总和为 3。
我们得到包含2行数据的 C 视图(代表Customer)。
一个重要的概念是:高层级的视图可以从低层级的视图推导出来。例如,要得到 C 视图,我们不仅可以从原始表 T 计算,也可以从已经计算好的 PC 视图推导(通过对相同的customer进行聚合)。显然,从数据量更小的 PC 视图(3行)进行计算,比从原始表 T(3行,本例中虽相同,但理论上原始表可能巨大)更高效。
数据立方体与物化视图
我们可以将不同分组组合的视图组织成一个格结构。顶点是包含所有维度的最详细视图(如 PSC),底部是没有任何维度的总计视图(如 (),表示所有售价的总和)。边表示“可以从哪个视图推导出哪个视图”。
假设我们有一个巨大的原始表 PSC,其记录数为 6M(6百万)。通过分组聚合,我们可以得到一系列其他视图及其预估大小:
- PC: 4M
- PS: 0.8M
- SC: 2M
- P: 0.2M
- S: 0.01M
- C: 0.1M
- (): 1 (单行总计)
物化视图 是指将某个视图的查询结果实际存储在硬盘上。物化视图可以加速查询,因为查询可以直接读取物化好的结果,而无需重新扫描和计算原始数据。但是,物化所有视图会占用大量存储空间。
我们定义回答一个查询的成本为:为了得到该查询的答案,需要从硬盘读取的数据行数。
计算物化视图的增益
我们通过一个场景来理解“增益”的计算。

场景一:只物化顶层视图(PSC)
此时,所有其他视图都需要通过扫描原始的 PSC(6M行)来计算。
- 回答 PC 查询的成本:6M
- 回答 P 查询的成本:6M
- ...(其他视图成本均为6M)
场景二:物化顶层视图(PSC)和 PS 视图
现在,PS 视图(0.8M行)已被物化并存储在硬盘上。
- 回答 PC 查询的成本:仍需扫描 PSC,成本为6M。
- 回答 P 查询的成本:现在有两种选择:1) 扫描 PSC (6M);2) 扫描已物化的 PS (0.8M) 并从中聚合出 P。智能的系统会选择成本更小的方案,即0.8M。
- 回答 S 查询的成本:同样可以从 PS (0.8M) 中聚合得到,成本为0.8M。
- 回答 C 查询的成本:PS 视图中没有
customer信息,因此仍需扫描 PSC,成本为6M。

增益 定义为:由于额外物化了某个(些)视图,使得回答所有查询的总成本降低的数值。
比较场景二和场景一:
- 对于 P 查询,成本从 6M 降为 0.8M,增益为 5.2M。
- 对于 S 查询,成本从 6M 降为 0.8M,增益为 5.2M。
- 对于 C 查询,成本没有变化(6M),增益为 0。
- 对于 PC 等视图,成本没有变化,增益为 0。


因此,物化 PS 视图带来的总增益是 5.2M + 5.2M + 0 + ... = 10.4M(此例中)。通常我们忽略对顶层视图和总计视图的增益计算。

选择性物化问题
由此引出了选择性物化问题:在存储空间有限(即只能物化 K 个额外视图)的前提下,选择哪 K 个视图进行物化,才能使得到的总增益最大化?
这是一个需要优化算法来解决的问题。为了巩固理解,请尝试完成以下课堂练习。
课堂练习
假设原始视图 PSC 大小为 6M,其他视图大小如下:PC=4M, PS=0.8M, SC=2M, P=0.2M, S=0.01M, C=0.1M。
- 如果只物化 PSC,回答所有查询(PC, PS, SC, P, S, C)的总成本是多少?
- 如果物化 PSC, PS 和 SC,回答所有查询的总成本是多少?相比只物化 PSC,总增益是多少?
(练习解析:根据上述增益计算原理,第一问总成本为 6M * 6 = 36M。第二问中,P和S可从PS获得,成本为0.8M和0.01M;C可从SC获得,成本为0.1M;PC仍需扫描PSC,成本6M;PS和SC已物化,成本即其自身大小0.8M和2M。总成本为 6 + 0.8 + 2 + 0.2 + 0.01 + 0.1 = 9.11M。总增益为 36M - 9.11M = 26.89M。)
总结


本节课中我们一起学习了数据仓库中物化视图的核心概念。我们通过SQL分组聚合的例子,理解了视图之间的推导关系。我们重点掌握了物化视图如何通过预计算和存储中间结果来提升查询性能,并定义了查询成本和物化增益。最后,我们引出了选择性物化问题,即在资源约束下如何最优选择要物化的视图集合以最大化性能增益。这是构建高效数据仓库系统的关键基础。
018:问题定义与NP-hard证明

在本节课中,我们将学习数据仓库中视图选择问题的形式化定义,并证明该问题在计算上是困难的,即NP-hard问题。
问题定义
上一节我们介绍了数据仓库中物化视图的概念。在了解其收益计算方式后,我们明确要解决的问题是:从所有可能的视图中选择一个子集进行物化,使得总收益最大化。
问题公式化:给定一个视图格(Lattice)和物化视图的数量限制K,目标是选择一个包含K个视图的集合V,使得总收益Gain(V)最大化。


证明视图选择问题是NP-hard
作为计算机科学家,我们需要判断这个问题是否非常困难。与关联规则挖掘类似,我们也想证明这个问题是NP-hard的。我们将使用一个已知的NP完全问题来进行归约证明。
我们首先将上述最大化问题转化为一个决策问题。在NP-hard证明中,通常使用决策问题。决策问题的答案是“是”或“否”。
选择性物化决策问题:给定一个整数K和一个实数J,是否存在一个包含K个视图的集合V,使得其信息增益至少为J?
我们的目标是证明这个决策问题是NP-hard的。
使用已知的NP完全问题:精确3覆盖
证明方法与关联规则挖掘中学过的类似。我们使用一个已知的NP完全问题:“精确3覆盖”(Exact Cover by 3-Sets, X3C)。
X3C问题定义:给定一个包含3q个元素的集合X,以及一个由X的3元素子集构成的集合C。问:C中是否包含一个精确覆盖C‘(C‘是C的子集),使得X中的每个元素在C’中恰好出现一次?
为了让定义更清晰,请看以下示例。
示例一(答案是“是”):
- 集合 X =
- 集合 C = { {A, B, C}, {B, C, D}, {D, E, F} }
我们可以找到子集 C‘ = { {A, B, C}, {D, E, F} }。X中的每个元素(A, B, C, D, E, F)在C’中都恰好出现一次。因此答案是“是”。

示例二(答案是“否”):
- 集合 X =
- 集合 C = { {A, B, C}, {B, C, D}, {A, E, F} }

无法找到满足条件的子集C‘。例如,如果选择{A, B, C}和{A, E, F},则元素A出现了两次;如果选择{B, C, D}和{A, E, F},则元素B、C、D、E、F都只出现一次,但元素A没有出现。因此答案是“否”。
精确3覆盖(X3C)是一个已被证明的NP完全问题。
从X3C到视图选择问题的归约
现在,我们将X3C问题归约到我们的选择性物化决策问题。以下是归约步骤的概述,随后将通过一个具体例子进行解释。
归约构造如下:
- 创建一个根节点,大小为200(称为“魔法数字”),位于第1层。
- 创建一个底层节点,大小为1,位于第4层。
- 对于X中的每个元素x,创建一个节点N_x,大小为50,位于第3层。在N_x和底层节点之间创建一条边。
- 对于C中的每个3元素子集A = {x, y, z},创建一个节点N_A,大小为100,位于第2层。创建N_A到根节点的边,以及N_A到N_x、N_y、N_z的边。
- 在我们的决策问题中,设K = q(即X中元素组数)。
- 设决策阈值 J = 400 * q。
你可能对其中出现的数字感到疑惑。接下来,我们通过一个例子来具体说明。
归约示例
我们使用示例一的X3C实例进行归约:
- X = {A, B, C, D, E, F}, 所以 q = 2。
- C = { {A, B, C}, {B, C, D}, {D, E, F} }。
根据归约步骤:
- K = q = 2。
- J = 400 * q = 800。
- 构建的视图格结构如下图所示,节点旁的数字为其“大小”属性。

现在,考虑我们的选择性物化问题:除了顶层的根视图必须物化外,我们还需要选择K=2个视图进行物化,使得总收益至少达到J=800。
根据收益计算规则(物化一个视图的收益等于其祖先视图中未被物化的最小祖先的大小),我们可以计算各个候选视图的收益:
- 物化“ABC”视图的收益是100。
- 物化“BCD”视图的收益是100。
- 物化“DEF”视图的收益是100。
那么,选择哪两个视图能使总收益最大化呢?答案是选择“ABC”和“DEF”。
- 选择“ABC”:它能为底层A、B、C三个元素的查询各节省100,总收益300(严格计算是覆盖了其下4个节点,收益为4*100=400,此处为简化理解)。
- 选择“DEF”:它能为底层D、E、F三个元素的查询各节省100,总收益300。
- 两者总收益为600(按简化计算)或800(按图中结构精确计算,每个物化视图为其4个后代节点各贡献100收益)。
无论如何计算,选择“ABC”和“DEF”都能使总收益达到最大值,并且至少为800,满足决策问题的要求。
归约的正确性与魔法数字的含义
关键点在于:在这个构造的实例中,能够达到收益阈值J=800的物化方案(选择“ABC”和“DEF”),恰好对应了原X3C问题的一个解({ {A, B, C}, {D, E, F} })。
魔法数字(200, 100, 50, 1)的设置是为了确保:
- 只有物化那些完全覆盖三个独立底层元素(且不与其他物化视图覆盖的元素重叠)的第2层节点(即C中的子集对应的节点),才能获得最大收益。
- 收益阈值J(400*q)被设置为只有当物化的q个节点恰好构成一个精确覆盖时才能达到的值。
这些数字并非固定不变。例如,若将根节点大小改为500,第2层节点大小改为200,那么相应的J值应变为 (500-200)*4 * q = 1200 * q。其核心原理是保持收益计算的比例关系,使得“精确覆盖”对应的物化方案具有最大且唯一的收益值。
因此,如果我们能解决这个选择性物化决策问题,就等于解决了X3C问题。由于X3C是NP完全的,所以选择性物化决策问题至少是NP-hard的。进而,最初的最大化收益视图选择问题也是NP-hard的。

实例的物理意义
最后,让我们回顾一个更具体的例子,理解视图格中节点的物理意义。

考虑一个视图格,其属性包括:零件(P)、供应商(S)、客户(C)。节点“PC”表示按零件和客户分组聚合的视图。




在数据库理论中,这通常与函数依赖有关。例如,图中“PC”视图的大小与“PSC”视图相同,这可能暗示着一种函数依赖:(P, C)可以唯一确定S。这意味着在原始数据中,给定一个零件和一个客户,对应的供应商是唯一的。这种语义约束会影响视图的大小,从而影响物化视图的选择策略。

总结


本节课中,我们一起学习了数据仓库视图选择问题的形式化定义。我们通过将已知的NP完全问题——精确3覆盖(X3C)——归约到视图选择的决策问题,证明了该问题是一个NP-hard问题,这意味着在多项式时间内找到最优解是极其困难的。最后,我们还探讨了视图格结构中可能蕴含的数据库语义(如函数依赖)。理解问题的计算复杂性是设计高效启发式算法或近似算法的基础。
019:视图物化选择算法

概述
在本节课中,我们将学习数据仓库中一个重要的优化问题:如何从众多可能的物化视图中,选择一部分进行物理存储,以最小化查询的总成本。我们将重点介绍解决此问题的贪心算法,并通过一个具体例子来演示其计算过程。最后,我们将探讨该算法的性能表现。
算法介绍
上一节我们介绍了视图物化选择问题的背景。本节中,我们来看看解决该问题的核心算法——贪心算法。该算法思路非常简单直接。
首先,我们需要定义一个关键概念:收益。给定一个视图集合 S(代表已选择物化的视图),我们定义选择某个视图 v 进行物化的收益 B(v, S) 如下:
公式:
B(v, S) = ∑ (对于每个能被 v 或其物化后代回答的视图 w,计算:未物化 v 时回答 w 的最小成本 - 物化 v 后回答 w 的最小成本)
简单来说,收益就是物化视图 v 后,能为整个查询系统节省的总成本。
基于收益的定义,贪心算法的步骤如下:
算法伪代码:
输入:需要物化的视图数量 k
1. 初始化选择集合 S = {顶层视图} // 顶层视图总是被物化
2. FOR i = 1 TO k DO
3. 对于每一个不在 S 中的视图 v,计算其收益 B(v, S)
4. 选择收益 B(v, S) 最大的视图 v_max
5. 将 v_max 加入集合 S:S = S ∪ {v_max}
6. END FOR
7. 输出最终的选择集合 S
算法示例
为了帮助理解,我们通过一个具体的例子来演示贪心算法的执行过程。
假设我们有一个数据立方体,其视图的依赖关系及查询成本如下图所示。我们的目标是选择 k=2 个视图(除了顶层视图)进行物化。

我们通常会绘制一个收益计算表来辅助决策。初始时,只有顶层视图被物化。
以下是第一轮迭代(选择第一个视图)的收益计算过程:
- 视图 PC:它会影响自身以及其父视图 P 和 C。物化前,回答 PC 查询的成本是 6M。物化后,成本变为 6M(因为物化成本等于查询成本)。因此,对自身的收益为 0。对于 P 和 C,由于物化 PC 并不能提供比现有顶层视图更优的路径来回答 P 和 C 的查询,收益也为 0。总收益为 0。
- 视图 PS:它会影响自身以及 P 和 S。物化前,回答 PS 查询的成本是 6M。物化后,成本变为 0.8M。因此,对自身的收益为 5.2M。对于 P 和 S,同样因为无法提供更优路径,收益为 0。总收益为 5.2M。
- 视图 SC:与 PC 对称,总收益为 0。
- 视图 P:它只影响自身。物化前,通过顶层视图回答 P 的成本是 6M。物化后,成本变为 0.2M。因此,收益为 5.8M。
- 视图 S:与 P 类似,收益为 5.99M。
- 视图 C:与 P 类似,收益为 5.9M。
第一轮收益计算结果如下表所示:
| 候选视图 | 收益 (B) |
|---|---|
| PC | 0 |
| PS | 5.2M |
| SC | 0 |
| P | 5.8M |
| S | 5.99M |
| C | 5.9M |
根据贪心策略,我们选择收益最大的视图。在本轮中,视图 S 的收益最大(5.99M),因此我们物化视图 S。
现在进入第二轮迭代(选择第二个视图)。此时,物化集合 S 已包含 {顶层视图, S}。
以下是第二轮迭代的收益计算要点(需考虑已物化的视图 S 的影响):
- 视图 PC:物化 PC 主要影响自身和 C。对于 P,由于已有物化视图 S(通过 S 回答 P 的成本为 0.8M),这比通过 PC 路径(6M)更优,因此物化 PC 对 P 无收益。最终计算出的总收益为 0。
- 视图 PS:此时 PS 已被考虑?注意,PS 是 S 的父视图。物化 PS 会影响自身和 P。对于 S,已有物化视图 S(成本 0.1M)是最优的,因此无收益。计算后,物化 PS 的总收益为 0.6M。
- 视图 SC:与第一轮类似,收益为 0。
- 视图 P:物化 P 只影响自身。现在回答 P 的最优成本是通过已物化的 S(0.8M)。物化 P 后,成本降至 0.2M。因此收益为 0.6M。
- 视图 C:物化 C 只影响自身。回答 C 的最优成本目前是通过顶层视图(6M)。物化后成本降至 0.1M。因此收益为 5.9M。


第二轮收益计算结果如下:
| 候选视图 | 收益 (B) |
|---|---|
| PC | 0 |
| PS | 0.6M |
| SC | 0 |
| P | 0.6M |
| C | 5.9M |
在第二轮中,视图 C 的收益最大(5.9M)。因此,我们选择物化视图 C。
最终,贪心算法选择的物化视图集合是:顶层视图、S 和 C。获得的总收益(节省的总成本)为第一轮收益与第二轮收益之和:5.99M + 5.9M = 11.89M。
算法性能分析
上一节我们通过例子学习了贪心算法的步骤。本节中,我们来看看这个算法的性能如何。我们知道,视图物化选择问题本身是 NP 难问题,贪心算法是一种启发式方法,它可能无法得到最优解。
这意味着贪心算法在某些情况下表现可能不佳。我们可以构造一个特例来说明这一点。
假设有一个视图依赖结构,其中顶层视图下有一些特定成本和关联关系的视图。通过详细计算(具体计算过程可课后自行推导),贪心算法可能会选择某两个视图(例如 B 和 C),并获得一个总收益值。


然而,存在一个“神奇”的最优算法(我们假设其能找到绝对最优解),它可能会选择另一组视图(例如 B 和 D),并获得更高的总收益。
比较贪心算法的收益与最优算法的收益,我们得到一个比值。如果这个比值接近 1,说明贪心算法结果接近最优;如果比值接近 0,说明贪心算法结果远差于最优解。
那么,贪心算法的这个性能比值是否有下限保证呢?答案是肯定的。理论研究证明,贪心算法对于视图物化选择问题的解,其收益至少能达到最优解收益的 63%(即比值下限约为 0.63)。
这意味着,尽管贪心算法不能保证总是找到最佳方案,但它能保证找到的方案不会太差,至少是最优方案的 63% 以上。这个结论的完整证明可以在相关研究论文中找到。



总结
本节课中,我们一起学习了数据仓库中视图物化选择的贪心算法。我们首先定义了“收益”作为选择视图的关键度量,然后详细阐述了算法的步骤。接着,我们通过一个具体的计算示例,一步步演示了如何应用贪心算法做出选择。最后,我们分析了算法的性能,了解到虽然它是启发式方法,但在最坏情况下也有不低于 63% 的性能保证。这使我们在实际应用中能够有信心地使用该算法来处理这类复杂的优化问题。
020:HITS算法第一部分

在本节课中,我们将要学习一种重要的网页排名算法——HITS算法。该算法通过分析网页之间的链接关系,来评估网页的重要性。我们将从基本概念入手,逐步理解其工作原理和计算步骤。
概述与背景
在互联网搜索中,如何快速准确地找到相关网页是一个核心问题。例如,在搜索引擎中输入“Raymond Wong”进行搜索,会返回大量相关网页。了解搜索引擎的排名机制,有助于我们优化网页,使其在搜索结果中获得更好的位置。
HITS算法是两种主要排名方法之一,另一种是Google目前使用的PageRank算法。HITS算法的核心思想是区分两种类型的网页:枢纽(Hub)和权威(Authority)。
核心概念:枢纽与权威

一个网页可以同时拥有枢纽权重和权威权重。
- 权威(Authority):如果一个网页被许多其他网页链接,那么它就是一个好的权威。权威权重(A)衡量的是指向该网页的链接数量和质量。
- 公式:对于一个网页
v,其权威权重A(v)是所有指向它的网页的枢纽权重之和。即:
A(v) = Σ H(u),其中u是所有指向v的网页。
- 公式:对于一个网页
- 枢纽(Hub):如果一个网页包含许多指向其他高质量网页的链接,那么它就是一个好的枢纽。枢纽权重(H)衡量的是该网页指向外部的链接数量和质量。
- 公式:对于一个网页
v,其枢纽权重H(v)是所有它指向的网页的权威权重之和。即:
H(v) = Σ A(u),其中u是所有被v指向的网页。
- 公式:对于一个网页
简单来说,好的权威被好的枢纽所链接,而好的枢纽则链接向好的权威。
HITS算法步骤


HITS算法主要包含两个步骤:采样(Sampling)和迭代(Iteration)。

第一步:采样(构建基础集合)
给定一个包含若干关键词的用户查询(例如“Raymond Wong”),算法首先需要确定一个待分析的网页集合,称为基础集合(Base Set)。构建过程如下:
- 收集根集合(Root Set):检索并收集所有包含查询关键词的网页。这些网页构成了根集合。
- 扩展为基集(Base Set):
- 将所有根集合中的网页加入基础集合。
- 将所有链接到根集合中任一网页的网页加入基础集合。
- 将所有被根集合中任一网页链接到的网页加入基础集合。
经过以上步骤,我们得到了一个围绕查询主题的、由相关网页及其紧密链接邻居构成的基础集合。后续的排名计算将仅在这个集合内进行。
第二步:迭代计算权重
在获得基础集合后,目标是为其中的每个网页计算其枢纽权重和权威权重。这通过一个迭代过程完成。
首先,我们需要用图来表示基础集合中网页的链接关系。每个网页是一个节点,每个超链接是一条有向边。
假设我们有一个简单的网络,包含三个网页:Netscape (N), Microsoft (MS), Amazon (A)。它们的链接关系如下图所示(假设N指向MS和A,MS指向A):
N -> MS
N -> A
MS -> A
我们可以用邻接矩阵 M 来表示这个图。如果网页 i 链接到网页 j,则 M[i][j] = 1,否则为0。
根据之前的核心概念公式,我们可以将枢纽和权威权重的计算表示为矩阵运算。
- 令
h为所有网页的枢纽权重向量。 - 令
a为所有网页的权威权重向量。
那么,迭代公式可以写作:
a = M^T * h(权威权重等于所有指向它的网页的枢纽权重之和)h = M * a(枢纽权重等于所有它指向的网页的权威权重之和)
将公式2代入公式1,可以得到 a = M^T * M * a。这意味着权威权重向量 a 是矩阵 M^T * M 的特征向量。同理,枢纽权重向量 h 是矩阵 M * M^T 的特征向量。
在实际计算中,我们采用迭代逼近法来求解:
- 初始化:将所有网页的枢纽权重和权威权重设为1(或任何相同的正数)。
- 进行以下迭代直到收敛:
a. 根据当前h,利用公式a = M^T * h更新所有a。
b. 对a进行标准化(例如,使其各分量之和为1或固定值),以防止数值过大。
c. 根据更新后的a,利用公式h = M * a更新所有h。
d. 对h进行标准化。 - 当连续两次迭代的权重向量变化小于一个极小阈值时,认为算法已收敛,停止迭代。
最终,我们得到每个网页稳定的枢纽权重和权威权重。搜索引擎可以根据这些权重对结果进行排序,例如按权威权重降序排列,或按枢纽与权威权重的综合得分排序。
总结


本节课我们一起学习了HITS算法的第一部分。我们首先了解了网页排名的重要性,然后引入了HITS算法的两个核心概念:枢纽和权威。接着,我们详细讲解了算法的两个主要步骤:采样(如何构建待分析的基础网页集合)和迭代(如何通过矩阵运算和迭代逼近来计算每个网页的枢纽与权威权重)。理解这些基础是掌握HITS算法以及对比其他排名算法(如PageRank)的关键。在下一部分,我们将通过更具体的例子和细节来深化理解。
021:PageRank算法第一部分

概述
在本节课中,我们将要学习PageRank算法的基本原理。PageRank是Google搜索引擎早期用于网页排序的核心算法。我们将了解它如何通过一个单一的“重要性”概念来评估网页,并学习其背后的随机过程思想。
PageRank算法简介
上一节我们介绍了基于“枢纽”和“权威”两个概念的排序算法。本节中我们来看看PageRank算法,它只使用一个概念来对网页进行排名,这使得算法更加简洁。
PageRank算法采用了一种随机方法来评估网页。如果你熟悉数学,你会知道这涉及到随机矩阵和随机过程的概念。如果不熟悉也没关系,可以将其理解为一种概率方法。
让我们看一个例子,假设有三个网页:Na cap、Amazon和Microsoft,它们之间的链接关系如下图所示。

构建随机矩阵
此时,我们需要定义一个关键矩阵——随机矩阵。这里需要强调,这个矩阵是按列归一化的,这与我们之前接触的邻接矩阵(按行)不同,很多学生会在这里犯错。
按列归一化的含义是:矩阵的每一列元素之和为1,每个元素的值表示从该列对应的网页跳转到其他网页的概率。
以下是构建步骤:
- Na cap列:Na cap有2条出链(指向Amazon和Microsoft)。因此,跳转到每个目标页面的概率是
1/2 = 0.5。 - Amazon列:Amazon有1条出链(指向Na cap)。因此,跳转到Na cap的概率是
1/1 = 1,跳转到其他页面的概率为0。 - Microsoft列:Microsoft有1条出链(指向Amazon)。因此,跳转到Amazon的概率是
1/1 = 1,跳转到其他页面的概率为0。
由此,我们得到随机矩阵 M:
M = [ [0.0, 1.0, 0.0],
[0.5, 0.0, 1.0],
[0.5, 0.0, 0.0] ]
(假设行顺序为 [Na cap, Amazon, Microsoft])
PageRank迭代计算
PageRank算法非常简单,其核心迭代公式与枢纽权威值算法类似:
r_new = M * r_old
其中 r 是一个向量,代表每个网页的重要性分数。
让我们开始迭代计算:
- 初始化:假设所有网页初始重要性相等。设初始向量 r0 = [1, 1, 1]。
- 第一次迭代:计算 r1 = M * r0。
- 计算过程:
r1 = [0*1 + 1*1 + 0*1, 0.5*1 + 0*1 + 1*1, 0.5*1 + 0*1 + 0*1] = [1, 1.5, 0.5] - 此时,所有网页重要性总和为
1 + 1.5 + 0.5 = 3。
- 计算过程:
- 第二次迭代:计算 r2 = M * r1 = [1.25, 0.75, 1]。
- 重要性总和仍为
1.25 + 0.75 + 1 = 3。
- 重要性总和仍为
- 继续重复此过程,直到向量 r 不再发生显著变化(收敛)。我们会发现,在每次迭代中,所有网页的重要性总和始终保持不变。
总和不变性的证明
为什么在PageRank迭代中,重要性总和能保持不变?而之前的枢纽值算法却需要手动归一化?这是一个重要的考点。
口头解释:因为随机矩阵 M 是列归一化的。可以想象,初始时我们有1个单位的“重要性”分布在各个网页。经过矩阵 M 的转换,这个单位的“重要性”只是被重新分配,而不会凭空增加或减少。
数学证明:
假设我们有n个网页,当前的重要性向量为 r_old = [r1, r2, ..., rn],其总和为 S_old = r1 + r2 + ... + rn。
随机矩阵 M 满足一个性质:每一列的元素之和为1。即对于任意列j,有 M[1][j] + M[2][j] + ... + M[n][j] = 1。

计算新的重要性向量 r_new = M * r_old。其第i个元素为:
r_new[i] = M[i][1]*r1 + M[i][2]*r2 + ... + M[i][n]*rn

那么新的总和 S_new 为所有 r_new[i] 相加:
S_new = 所有i的 (M[i][1]*r1 + M[i][2]*r2 + ... + M[i][n]*rn) 之和
交换求和顺序,先对i求和:
S_new = r1*(M[1][1]+M[2][1]+...) + r2*(M[1][2]+M[2][2]+...) + ... + rn*(M[1][n]+M[2][n]+...)
由于矩阵 M 每列之和为1,即 (M[1][j]+M[2][j]+...+M[n][j]) = 1,代入上式:
S_new = r1*1 + r2*1 + ... + rn*1 = r1 + r2 + ... + rn = S_old
因此,重要性总和在迭代中保持不变。

蜘蛛陷阱问题及其影响
根据上述计算,Microsoft的排名可能较低。假设Microsoft公司对此不满,它可以通过修改自己网站的链接结构来操纵排名。
例如,Microsoft可以移除指向Amazon的链接,改为只链接到自己。这样,网络结构就变成了下图所示:

相应的随机矩阵也会改变。如果使用PageRank算法进行迭代,最终会发现Microsoft的重要性分数变得非常高,成为最重要的网页。
这种行为创建了一个蜘蛛陷阱。
以下是蜘蛛陷阱的定义:
- 蜘蛛陷阱是指一个或多个网页组成的群体,这些网页没有指向群体外部的链接。
- 在这个例子中,Microsoft的页面只指向自己,形成了一个只有一页的蜘蛛陷阱。
其影响是:在随机游走模型中,一旦“重要性”或“随机冲浪者”进入这个陷阱,就会永远在里面循环,无法离开。最终,整个网络几乎所有的重要性都会被这个陷阱页面吸收。
解决方案:引入阻尼因子
Google当然知道这种操纵手法。在实际的PageRank算法中,他们引入了一个修正项来避免这个问题。
基本思想是:在每次跳转时,冲浪者不一定完全按照链接前进。他有一定概率(例如15%)随机跳转到网络中的任何一个网页,而只有剩余概率(例如85%)按照当前页面的出链进行跳转。
修正后的PageRank公式通常表示为:
r_new = β * M * r_old + (1 - β) * e / N
其中:
- β 是阻尼因子(通常取0.85),表示跟随链接的概率。
- M 是原始的随机矩阵。
- e 是一个所有元素都为1的向量。
- N 是网页总数。
- (1 - β) * e / N 项代表了“随机跳转到任意网页”的部分,这保证了即使存在蜘蛛陷阱,重要性也不会被完全困住。
引入阻尼因子后,即使Microsoft只链接自己,其最终的重要性分数也会被限制在一个更合理的范围内,而不会吸收掉所有重要性。此外,Google的排名算法还结合了关键词匹配、网站权威性等多种因素,使其更加健壮和难以操纵。



总结
本节课中我们一起学习了PageRank算法的第一部分。我们了解了PageRank如何用单一的“重要性”概念和随机矩阵来对网页排序,学习了其迭代计算过程,并证明了重要性总和的不变性。我们还探讨了算法的一个弱点——蜘蛛陷阱,即网站可以通过特定的链接结构操纵排名。最后,我们简要介绍了Google如何通过引入阻尼因子(随机跳转)来解决这个问题,使算法更加公平和健壮。

浙公网安备 33010602011771号