INF442 Amphi 4: Hierarchical Clustering | Classes (2/2)

一些词汇:

  • agglomerative:凝结的,从小的cluster到大的cluster
  • divisive: 从大的cluster到小的cluster

1. Hierarchical Clustering

目的:
输入n个点,输出k个Homogeneous的子类。

Rq:

  • 我们的类别数量和每一个类别的尺寸有关。
  • 人群,人,人脸,就是不同分类的尺度。

例如,在下面的图中,如果我们尺度小的话看到的就是11个B,大尺度就是一个A。
在这里插入图片描述

因此,我们产生了Hierarchical Clustering,我们引入了dendrogram 系统树图

1.0 Dendrogram

输入一个尺度(scale,下图中的横轴),输出一个partition。
下面的图中每一次partition改进都只改进1。
在这里插入图片描述

1.1 构建Hierarchy的两种方法:AHC,DHC

我们一般用得更多的是AHC

Agglomerative hierarchical clustering (AHC)

  • 从小的cluster到大的cluster
  • 一般从每一个点出发,逐渐变为一个root
  • 有点类似Kruskal’s Minimum Spanning Tree Algorithm

效率分析:

  • 要n-1次merges,因为我们每次将两个分类合并,以减少一个分类。
  • 在第k步的时候,
    • n − k n-k nk个cluster,我们一共有 C n − k 2 C_{n-k}^2 Cnk2种选择将两个分类合并的方法。
    • 因此在第k步的时间复杂度为 Θ ( n 2 ) \Theta(n^2) Θ(n2)

Divisive hierarchical clustering (DHC):

  • 从大的cluster分割到小的cluster
  • 从所有的结果出发直到叶子节点。
  • 类似于kd-tree的构建。(每次换一个dimension选中位数)

效率分析:

  • 要n-1次Divise,因为我们每次将一个分类分裂,以增加一个分类。
  • 在第k步的时候,
    • 我们有k个分类,每个分类有 n 1 , . . . , n k n_1,...,n_k n1,...,nk个元素
    • 一共有 ∑ i = 1 k ( 2 n i − 1 − 1 ) \sum_{i=1}^k(2^{n_i-1}-1) i=1k(2ni11)种分类方法
    • 因此在第k步的时间复杂度为 Θ ( 2 n ) \Theta(2^n) Θ(2n)

1.2 AHC伪代码

我们每次将两个cluster合并为一个cluster,然后提升scale的值。
在这里插入图片描述

  • 为了快速实现合并的操作:我们将使用UnionFind
  • 为了选择cluster和height,我们需要定义两个cluster之间的距离,并将这个距离作为新的height。

1.3 Cluster间距离的定义

  • Single-Linkage: 两个Cluster间所有点对(Pair)的最小值。[生成的树不均衡]
  • Complete-Linkage:两个Cluster间所有点对(Pair)的最大值。[生成的树均衡,但是会受到离群值的影响]
  • Average-Linkage:所有点对的平均距离。
    在这里插入图片描述
    不同距离的比较:
    在这里插入图片描述

1.4 Single-Linkage的AHC

因为两个Cluster之间的距离由他们所含有的点的最小距离确定,因此我们

  • 将所有的点 P P P的边从小到大排序 O ( n 2 l o g n ) O(n^2logn) O(n2logn),因为边的数目上限为 C n 2 ∼ O ( n 2 ) C_n^2\sim O(n^2) Cn2O(n2)
  • 每次取最小的一条边 ( P , P ′ ) (P,P') (P,P)
    • P , P ′ P,P' P,P属于不同的Cluster,则将它们合并为一个。 O ( α ( n ) ) O(\alpha(n)) O(α(n))

因为每条边都要判断一次(find),因此总时间为 O ( n 2 α ( n ) ) O(n^2 \alpha(n)) O(n2α(n))
在这里插入图片描述
引入 C s ( p ) C_s(p) Cs(p):在所有长度都小于s的边都pop掉之后得到的含有p的cluster。显然pop掉越多的边,s越大, C s ( p ) C_s(p) Cs(p)包含p的cluster越大。
在这里插入图片描述
下面的图片说明了connected component,即他们两之间存在一条路。这里的直观想象就是以每一个点为圆心画一个圆,如果两个圆有交集,则这两个类联通。
在这里插入图片描述
Dem:

  • s=0,显然成立
  • 验证每一次改变CC的时候,我们都会满足这一个条件。( d ( p k , p l ) ≤ s d(p_k,p_l)\leq s d(pk,pl)s

Least Common Ancestor (LCA)
合并两个点所属Cluster的最小高度。
在这里插入图片描述

1.5 Ultrametric

感觉就是定义一个distance

d : P × P → R d:P\times P \to \mathbb{R} d:P×PR is an ultrametric on P P P if:

  • non-negativity : d ≥ 0 d\geq 0 d0
  • symmetry : d ( p i , p j ) = d ( p j , p i ) d(p_i,p_j)=d(p_j,p_i) d(pi,pj)=d(pj,pi)
  • identity : d ( p i , p j ) = 0 → d(p_i,p_j)=0 \rightarrow d(pi,pj)=0 p i = p j p_i = p_j pi=pj
  • ultrametric inequality: d ( p i , p k ) ≤ m a x { d ( p i , p j ) , d ( p j , p k ) } d(p_i,p_k) \leq max\{d(p_i,p_j),d(p_j,p_k)\} d(pi,pk)max{d(pi,pj),d(pj,pk)}

我们可以证明在dendrogram中给定一个 t h e t a theta theta,即只考虑 [ 0 , θ ] [0,\theta] [0,θ]的部分,则
d L C A θ ( p i , p j ) : = height of LCA in  θ d_{LCA}^\theta(p_i,p_j):=\text{height of LCA in } \theta dLCAθ(pi,pj):=height of LCA in θ is an ultrametric on P。

Dem:
在这里插入图片描述
因为 p i → p k ⊂ p i → p j → p k p_i \to p_k \subset p_i \to p_j \to p_k pipkpipjpk

几个重要结论:
θ \theta θ到对应的距离 d L C A θ d^\theta_{LCA} dLCAθ是一个bijection。
在这里插入图片描述
对于任意的metrics,对应的 d L C A θ S L d d_{LCA}^{\theta^d_{SL}} dLCAθSLd不会改变太多,height of LCA is stable,但是dendrogram的结构不是稳定的。

1.6 Single-Linkage缺点:Chaining Effect

即:Clusters get merged far earlier than expected.

在这里插入图片描述

1.7 Phylogenetic trees

phylogenetic: 动植物种类史的
展示了动物的进化过程。
在这里插入图片描述

1.8 UPGMA Algorithm | Average-Linkage

输入:n个Species的集合P。
这里的 θ \theta θ类似于上图中的进化时刻。
所以最后输出的高度 d L C A θ A L d ′ d_{LCA}^\theta\\'_{{AL}^d} dLCAθALd是一开始的一半。
在这里插入图片描述

1.9 其他的距离:Ward’s criterion

Weighted版本
在这里插入图片描述
Unweighted版本:
在这里插入图片描述

2. Classes

2.1 引入其他文件中的函数

 // file fact.cpp
int fact (int n) {
	if (n<=0) return 1;
	else return n * fact(n-1);
}

假设我们想要使用上面这个fact.cpp中的代码,我们需要写

#include "fact.cpp"

Rq:

  1. “”表示我们在当前路径下搜索,<>表示在系统路径下搜索。
  2. 每次我们include一个cpp,对应的文件都要重新编译一次

问题一 预先编译和 extern

Sol:预先编译
extern int fact(int);

  • 告诉了编译器fact这个函数在外面被定义了。
  • 但具体在哪里寻找需要在编译的时候指定。````
  • declaration ≠ \neq = definition

总过程:
在这里插入图片描述

// 编译过程 Compilation
// 得到object file xxx.o文件
// 在个文件中如果有extern关键词就会生成一个link,且暂时指向null
g++ -c fact.cpp
g++ -c appli1.cpp
// 链接过程 Link edition
// 将xxx.o文件变为可执行文件
// 在这里把之前null的link用真的函数填上。
g++ -o appli1 appli1.o fact.o

问题二 weak type checking 和header files

⚠️ linker performs weak type checking

  • 有可能会有越界的问题如 int 2^16 -> char 2 8 2^8 28
  • 如果外面是char,内部是extern int i;则会读取非法内存。

Sol: header files

file1.hpp

// file1.hpp
extern char i, j, k, l; // declared but not defined

file1.cpp

// file1.cpp
#include "file1.hpp"  //这里需要include头文件
// redeclared (ok) and defined: 
char i = 1, j = 1, k = 1, l = 1;

file2.cpp

#include "file1.hpp"
int main(){
	std::cout << (int)i; // prints 1
	return 0;
}

具体使用和之前类似:

g++ -c file1.cpp
g++ -o file2 file2.cpp file1.o // 这里file2不是.o而是.cpp

Rq:

  1. 如果我们在引用的文件里面已经定义了一个变量,则我们不能重新再定义其类型了。
    在这里插入图片描述

有函数的header files

  • 普通的函数
    在这里插入图片描述
  • 在一个Class中的函数
    底下的::是一个scope operator。
    在这里插入图片描述

2.2 Static members

Static data members:

  • do not depend on a specific object a1.x==a2.x
  • are shared among all instances of the class

Static变量的两种定义方式

  1. 定义在A.cpp中
  2. 定义在main.cpp中
    但是不能定义在A.hpp中,因为所有引用A.hpp的文件都会使得变量多次定义(int i多次调用)。
    在这里插入图片描述

2.3 Access modifiers | friend func

分为3类:

  • Public : everyone outside class has access
  • Private : no one outside class has access (everyone inside still has access)
  • Protected : used in inheritance mechanism (next lecture)

默认:
public (struct), private (class)
在这里插入图片描述
在这里插入图片描述
Friend Functions

  • 对于指定的一些函数,它可以得到classe内部private的值。
  • declared inside the class (anywhere, access modifiers do not matter)
  • defined outside the class (possibly in other classes)
    在这里插入图片描述
    甚至整个class也可以是friend:
    friend class X; // not transitive nor inherited

2.4 Nested Classes

可以利用A::B b来获取class A中另一个class B中的变量的值。
在这里插入图片描述

2.5 Namespaces

  1. 可以在多个hpp文件中定义MyNameSpace,从而在main函数中只要用MyNameSpace::A,MyNameSpace::B就可以调用对应的类别。
    在这里插入图片描述

  2. Namespaces可以nested
    在这里插入图片描述

  3. 可以使用using namespace XXX来简化代码,后面的函数都来自XXX,如在using namespace std之后,所有打印的代码可以只用cout实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值