当前位置: 首页 > news >正文

课程10. 聚类问题

课程10. 聚类问题

  • 聚类
  • 此类表述的难点
  • K 均值法
    • 让我们推广到几个集群的情况
    • 如果我们选择其他起始近似值会怎样?
  • 结论
    • 在 sklearn 中的实现
  • 如何处理已发现的问题?
    • 层次聚类
    • Lance-Williams 算法
    • Lance-Williams 公式
    • 在Scipy中实现
  • 示例
  • DBSCAN
    • DBSCAN 算法

聚类

上一讲我们开始学习无监督学习问题,并讨论了降维问题。今天我们将继续学习无监督学习问题,并讨论聚类问题。

什么是聚类?
聚类是将原始未标记数据集划分为几组,这些组称为聚类。聚类是一个相当宽泛的概念。以下陈述可以被视为聚类的一个显著特征:

“聚类中对象之间的平均距离明显小于一对对象之间的平均距离,其中一个对象属于该聚类,另一个不属于该聚类。”

让我们正式地表述这个问题。


已知:

X X X 为我们从中收集训练样本的对象空间。

X N X^N XN = { x i } i = 1 N \{x^i\}_{i=1}^N {xi}i=1N 为训练样本。让我们再次注意样本中没有 y y y 个标签。

ρ : X × X → [ 0 , ∞ ) \rho: X × X → [0,∞) ρ:X×X[0,) 是对象之间的距离函数。

注意,与度量算法一样,距离函数反映了我们对“对象接近度”概念的期望。

求:

y i ∈ Y y_i \in Y yiY 是对象所属聚类的标签。对它们的要求:

  • 每个聚类由距离较近的对象组成。
  • 不同聚类中的对象彼此相距较远。

在这里插入图片描述

此类表述的难点

这种聚类问题的表述有些模糊。根据 Hadamard 理论,存在一个关于该问题表述正确性的概念。

根据 Hadamard 理论,如果满足以下条件,则该问题表述正确:

  • 该问题的解存在
  • 该问题的解是唯一的
  • 该问题的解持续依赖于初始数据(即,如果我们稍微更改初始数据,解不会发生太大变化)。

显然,从这个定义的角度来看,聚类问题的表述是错误的。

1) 存在(非平凡)解

在解决聚类问题时,我们经常处理高维数据,这些数据我们无法通过视觉或其他任何概览方式进行分析。这正是我们想要解决这个问题的原因——通过求解该问题,我们可以获得对现有数据的一些建设性描述。在开始解决问题时,我们对我们想要识别的聚类结构的存在做出了一个重要的假设。

但没有人向我们保证聚类结构的存在。很有可能,现有数据是从单一分布中采样的,根本没有真正划分成聚类。在这种情况下,发现的聚类结构要么微不足道,要么无法反映数据的真实结构。

2) 解的唯一性

当数据中某些聚类结构客观存在时,它可能具有模糊性。我们举个例子。

在这里插入图片描述
所有这些让我们意识到,我们面临的任务并不容易,主要是因为它的模糊性。然而,有一些相当有效的方法可以解决这个问题。我们将会了解这些方法。

K 均值法

最流行的聚类方法之一称为K 均值。它被广泛用于解决聚类问题。K 均值算法是更通用的EM 算法的一个特例。

我们首先来了解一下 K 均值算法,然后再看看它如何推广到 EM 算法。为了讨论该算法,我们先来介绍一下聚类中心的概念。

聚类中心是表示分配给聚类的区域的质心的一个点。简而言之,它是该聚类的几何中点。如果我们知道一组属于某个聚类的点,那么确定它的中心就非常简单:我们只需计算每个坐标上所有点的平均值即可。这组坐标将为我们提供一个聚类中心的估计值。

那么,k-means 算法 是什么样的呢?

我们假设现有数据集中的聚类数量预先已知,等于 K K K

需要注意的是,所需的聚类可以唯一地定义为特征空间中的 K K K 个点。

假设所需聚类中心的初始近似值为 Θ 0 = ( θ 1 0 . . . θ k 0 ) \Theta_0 = (\theta_1^0 ... \theta_k^0) Θ0=(θ10...θk0)
直到收敛:

  1. 给定当前近似值 G i G_i Gi,计算现有数据集中的点属于哪些聚类:对于数据集中的所有 x j x_j xj g j i : = arg ⁡ min ⁡ p = 1... k ( ρ ( Θ p i − 1 , x j ) ) g_j^i := \arg\min\limits_{p = 1 ... k}(\rho(Θ_p^{i-1}, x_j)) gji:=argp=1...kmin(ρ(Θpi1,xj))
  1. 根据计算出的数据集按聚类分布 G = ( g 1 i . . . g N i ) g_1^i ... g_N^i) g1i...gNi),我们重新计算新的聚类中心 Θ i = ( θ 1 i . . . θ k i ) \Theta_i = (\theta_1^i ... \theta_k^i) Θi=(θ1i...θki)

注意:提前说明收敛的含义非常重要。我们将收敛理解为这样一种情况:后续每一步都只会导致聚类中心估计值发生极其微小的变化。在下一个例子中,我们将看到从某一步开始,这个估计值根本不会改变。实际上,在许多算法中,我们会设置一个较小的数 ϵ ϵ ϵ,然后将估计值的变化与该值进行比较。如果结果显示,估计值在每一步的变化小于 ϵ ϵ ϵ,我们就说达到了收敛。

让我们用一个例子来解释一下该算法的运作。

首先,我们只考虑两个聚类,并在二维情况下(即特征描述向量为二维时)演示该算法的运作。

from matplotlib import pyplot as plt
import numpy as np
import seaborn as snssns.set_theme()a_x = 3.5 * np.random.randn(50) + 7
a_y = 3.5 * np.random.randn(50) + 7
b_x = 3.5 * np.random.randn(50) - 7
b_y = 3.5 * np.random.randn(50) - 7plt.figure(figsize=(12, 12))
plt.scatter(a_x, a_y)
plt.scatter(b_x, b_y)

输出:
在这里插入图片描述

import numpy as np
import matplotlib.pyplot as plt# 定义距离函数
dist = lambda x1, y1, x2, y2: np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)# 定义“点”类
class point:def __init__(self, x, y):self.x = xself.y = y# 计算当前点与另一个点之间的距离def count_distance(self, p):return dist(self.x, self.y, p.x, p.y)# 设置点所属的聚类def set_cluster(self, cluster):self.cluster = cluster# 绘制点def draw(self, color):plt.scatter([self.x], [self.y], c=color)# 将所有点合并到一个列表中,不填充对象标签信息
points = [point(a_x[i], a_y[i]) for i in range(len(a_x))] + [point(b_x[i], b_y[i]) for i in range(len(b_x))
]# 创建一个大小为 12x12 的图形
plt.figure(figsize=(12, 12))
# 绘制所有点,颜色为黑色
for i in range(len(points)):points[i].draw("black")

输出:
在这里插入图片描述

# 让我们写一个单步函数
def step(points, cluster_center_1, cluster_center_2):for i in range(len(points)):distance_1 = points[i].count_distance(cluster_center_1)distance_2 = points[i].count_distance(cluster_center_2)if distance_1 < distance_2:points[i].set_cluster(1)else:points[i].set_cluster(2)return points
# 聚类中心重新计算函数
def find_centers(points):cl1 = []cl2 = []for i in range(len(points)):if points[i].cluster == 1:cl1.append(points[i])else:cl2.append(points[i])cluster_center_1 = point(np.mean([p.x for p in cl1]),np.mean([p.y for p in cl1]))cluster_center_2 = point(np.mean([p.x for p in cl2]),np.mean([p.y for p in cl2]))return cluster_center_1, cluster_center_2
# 循环的一次迭代
# 更新函数有两种运行模式:在零模式下,它会根据中心数据重新计算每个聚类的点的新分布;在第一个模式下,它会为指定的聚类重新计算新的中心。
# 这些模式由输入变量 rjm 编码,该变量取两个值之一 - 0 或 1。在输出端,我们将此变量的值更改为相反的值。def update(points, cluster_center_1, cluster_center_2, rjm):if rjm:c1 = cluster_center_1c2 = cluster_center_2cluster_center_1, cluster_center_2 = find_centers(points)plt.arrow(c1.x, c1.y, cluster_center_1.x - c1.x, cluster_center_1.y - c1.y, color='black')plt.arrow(c2.x, c2.y, cluster_center_2.x - c2.x, cluster_center_2.y - c2.y, color='black')else:points = step(points, cluster_center_1, cluster_center_2)for p in points:p.draw('r' if p.cluster == 1 else 'b')cluster_center_1.draw('m')cluster_center_2.draw('y')return points, cluster_center_1, cluster_center_2, 1-rjm

此时,一个自然而然的问题出现了——聚类中心的初始近似值是根据什么原则设定的?

一般来说,有一些启发式方法可以帮助使这种选择并非完全随机。但我们不会深入探讨这个问题,而是遵循经典算法,随机选择初始近似值。例如,(-15,10) 和 (15, -10)。

c1 = point(-15,10)
c2 = point(15,-10)
rjm = 0
"""
更新函数仅生成并绘制了算法的一个步骤!
要观察算法的运行,您需要多次执行此单元格(以及所有包含更新函数的单元格)!
"""
plt.figure(figsize=(10,10))
points, c1, c2, rjm = update(points, c1, c2, rjm)

输出:
在这里插入图片描述

让我们推广到几个集群的情况

import collections
from collections import defaultdict
def step(points, centers):for i in range(len(points)):distances = [points[i].count_distance(centers[k]) for k in centers.keys()]cluster = np.argmin(distances) + 1points[i].set_cluster(cluster)return pointsdef find_centers(points):clusters = defaultdict(list)centers = {}for i in range(len(points)):clusters[points[i].cluster].append(points[i])for k in clusters.keys():centers[k] = point(np.mean([p.x for p in clusters[k]]),np.mean([p.y for p in clusters[k]]))return centersdef update(points, centers, rjm, colors_clusters, colors_centers):if rjm:c = centerscenters = find_centers(points)for k in centers.keys():plt.arrow(c[k].x, c[k].y, centers[k].x - c[k].x, centers[k].y - c[k].y, color='black')else:points = step(points, centers)for p in points:p.draw(colors_clusters[p.cluster - 1])for i,k in enumerate(centers.keys()):centers[k].draw(colors_centers[i])return points, centers, 1-rjm
from matplotlib import pyplot  as plt
import numpy as npa_x = 3.*np.random.randn(50) + 8
a_y = 3.*np.random.randn(50) + 8
b_x = 3.*np.random.randn(50)
b_y = 3.*np.random.randn(50) - 8
c_x = 3.*np.random.randn(50) - 8
c_y = 3.*np.random.randn(50) + 8plt.figure(figsize=(10,10))
plt.scatter(a_x, a_y)
plt.scatter(b_x, b_y)
plt.scatter(c_x, c_y)

输出:
在这里插入图片描述

points = ([point(a_x[i], a_y[i]) for i in range(len(a_x))]+ [point(b_x[i], b_y[i]) for i in range(len(b_x))]+ [point(c_x[i], c_y[i]) for i in range(len(c_x))]
)plt.figure(figsize=(10, 10))
for i in range(len(points)):points[i].draw("black")

输出:
在这里插入图片描述

centers = {1: point(-15,-15),2: point(15,-15),3: point(0,15)}
colors_clusters = ['g', 'b', 'r']
colors_centers = ['y', 'm', '#000000']
rjm = 0
plt.figure(figsize=(10,10))
points, centers, rjm = update(points, centers, rjm, colors_clusters, colors_centers)

输出:
在这里插入图片描述

如果我们选择其他起始近似值会怎样?

centers = {1: point(-1, 20),2: point(15,5),3: point(-15,-15)}
colors_clusters = ['g', 'b', 'r']
colors_centers = ['y', 'm', '#000000']
rjm = 0
plt.figure(figsize=(10,10))
points, centers, rjm = update(points, centers, rjm, colors_clusters, colors_centers)

输出:
在这里插入图片描述
如果我们选择了错误的聚类数量会怎么样?

# 2 个集群
centers = {1: point(-1, 20),2: point(15,5)}
colors_clusters = ['g', 'b']
colors_centers = ['y', 'm']
rjm = 0
plt.figure(figsize=(10,10))
points, centers, rjm = update(points, centers, rjm, colors_clusters, colors_centers)

输出:

在这里插入图片描述

# 4个集群centers = {1: point(-1, 20),2: point(15,5), 3: point(-10, -10), 4: point(10,10)}
colors_clusters = ['g', 'b', 'r', '#ff8243']
colors_centers = ['y', 'm', '#000000', "#8b00ff"]
rjm = 0
plt.figure(figsize=(10,10))
points, centers, rjm = update(points, centers, rjm, colors_clusters, colors_centers)

输出:
在这里插入图片描述

结论

  1. 该算法高度依赖于聚类中心的初始近似值。
  2. 如果聚类数量指定错误,我们得到的形式正确的结果可能无法完全反映实际情况。

在 sklearn 中的实现

from sklearn.cluster import KMeans
X = [[p.x, p.y] for p in points]
kmeans = KMeans(n_clusters=3, random_state=0).fit(X)
kmeans.labels_

输出:
在这里插入图片描述

plt.figure(figsize=(10,10))
for i,p in enumerate(X):plt.scatter([p[0]], [p[1]], c=colors_clusters[kmeans.labels_[i]])

输出:
在这里插入图片描述

kmeans.inertia_

输出:2500.5010444312366

如果我们设置不同数量的集群会怎么样?

inertias = []
for i in range(1, 26):kmeans = KMeans(n_clusters=i,random_state=0).fit(X)inertias.append(kmeans.inertia_)
plt.figure(figsize=(15, 7))
plt.title('Dependence of inertia on the number of clusters')
plt.plot(np.arange(1, 26, 1), inertias)

输出:
在这里插入图片描述

kmeans = KMeans(n_clusters=4,random_state=0).fit(X)
plt.figure(figsize=(10,10))colors_clusters = ['g', 'b', 'r', '#ff8243']
for i,p in enumerate(X):plt.scatter([p[0]], [p[1]], c=colors_clusters[kmeans.labels_[i]])

输出:
在这里插入图片描述

plt.figure(figsize=(10,10))kmeans = KMeans(n_clusters=5,random_state=0).fit(X)
colors_clusters = ['g', 'b', 'r', '#ff8243', "#8b00ff"]
for i,p in enumerate(X):plt.scatter([p[0]], [p[1]], c=colors_clusters[kmeans.labels_[i]])

输出:
在这里插入图片描述


补充知识点:EM 算法

EM 算法(期望最大化)是一种在给定一组观测变量 x x x 的情况下,通过引入一些隐藏变量 G G G(即我们无法直接观测,但可以以某种方式估计的变量)的向量来估计模型 Θ Θ Θ 的最优参数的算法。

让我们将其与 k-means 算法进行类比:最优参数 Θ Θ Θ 定义了点在聚类中的分布。它们是期望的聚类标签。隐藏变量 G G G 定义了聚类中心。我们无法直接观测它们,但可以用当前的近似值 Θ Θ Θ 来估计它们。观测变量是数据集中点的坐标。
EM 算法与 K 均值算法类似,包含两个迭代重复的步骤:

0.设置参数 Θ 0 Θ_0 Θ0 的初始近似值

直至收敛:

  1. 期望步骤:给定当前近似值 Θ i − 1 Θ_{i-1} Θi1,计算隐藏变量 G i G_i Gi 的期望值
  2. 最大化步骤:求解给定隐藏变量 G i G_i Gi 时,最大化观测值 x x x 的似然值问题。即 Θ i = a r g m a x ( P ( x ∣ G i , Θ ) ) Θ_i = argmax(P(x|G_i, Θ)) Θi=argmax(P(xGi,Θ))

当参数向量 Θ Θ Θ 的变化在某一步骤变得不显著时,算法将停止工作。


注意:需要注意的是,K-Means 只能检测相当简单的聚类结构。例如,它在检测环状聚类时会遇到问题,这时需要使用其他聚类方法。

如何处理已发现的问题?

  1. 多启动。我们可以使用不同的聚类中心初始近似值多次运行该算法,然后选择每个对象到其聚类质心的距离总和最小的解。

  2. 层次聚类

层次聚类


层次聚类包含两种不同的全局方法——凝聚层次聚类和划分层次聚类。它们之间的区别在于,凝聚聚类涉及不同聚类的顺序合并,而划分聚类涉及顺序划分。在本讲座中,我们将讨论凝聚聚类。


层次聚类的思想是持续执行某种迭代过程(即由多个重复步骤组成的过程),该过程允许基于已知的 N N N 个聚类划分,合并其中最近的一个(或者,相反,将其中一个聚类拆分成两个不同的聚类),从而将样本划分为 N − 1 N-1 N1 个聚类(或 N + 1 N+1 N+1 个)。因此,我们将获得一系列划分成不同数量聚类的样本,并从中选择最佳的聚类。

Lance-Williams 算法

该算法允许我们执行聚类的顺序合并,前提是我们有一个函数可以测量两个聚类之间的距离。我们将此函数称为 R ( U , V ) R(U,V) R(U,V),其中 U U U V V V 是一些聚类。

  1. 假设所有聚类最初都是单元素聚类。也就是说,在初始近似中,样本中的每个对象都是一个单独的聚类。
  2. 重复以下步骤 L − 1 L-1 L1 次,其中 L L L 是样本的大小:
  3. 根据函数 R ( U , V ) R(U, V) R(U,V) 的值,在我们的结构中找到两个最近的聚类,并将它们合并为一个聚类。我们将在此步骤 t t t 找到的聚类结构表示为 C t C_t Ct

在该算法的输出中,我们获得了一系列聚类划分序列,分别为 C 1 . . . C L C_1 ... C_L C1...CL。其中, C 1 C_1 C1 划分为多个独立聚类, C 2 C_2 C2 划分为 L − 1 L-1 L1 个独立聚类和一个包含 2 个点的聚类,以此类推; C L C_L CL 划分为一个包含所有对象的聚类。

为了便于可视化此聚类选项,通常使用一种称为树状图的特殊图表。
在这里插入图片描述

Lance-Williams 公式

如何测量聚类之间的距离?

实际上有很多不同的选择。
例如:

  • 最近邻距离。 R ( U , V ) R(U, V) R(U,V) = min ⁡ x ∈ U , y ∈ V ( ρ ( x , y ) ) \min\limits_{x \in U, y \in V}(\rho(x,y)) xU,yVmin(ρ(x,y))
  • 远邻距离。 R ( U , V ) R(U, V) R(U,V) = max ⁡ x ∈ U , y ∈ V ( ρ ( x , y ) ) \max\limits_{x \in U, y \in V}(\rho(x,y)) xU,yVmax(ρ(x,y))
  • 平均组距离。 R ( U , V ) R(U, V) R(U,V) = 1 N ∑ x ∈ U , y ∈ V ( ρ ( x , y ) ) \frac{1}{N}\sum\limits_{x \in U, y \in V}(\rho(x,y)) N1xU,yV(ρ(x,y))

我们可以基于我们能够形成的启发式方法,结合我们对主题领域的了解或问题的特征,以及通过尝试多个选项并确定哪种聚类能够最小化每个对象到其聚类中心的距离之和,来选择最适合我们任务的选项。

有一个公式可以描述所有这些以及许多其他计算聚类间距离的方法。

我们假设聚类 W W W = U ⋃ V U \bigcup V UV。我们还假设我们知道聚类 R ( U , S ) R(U, S) R(U,S) R ( V , S ) R(V, S) R(V,S) 之间的距离。

那么 R ( W , S ) = α U × R ( U , S ) + α V × R ( V , S ) + β × R ( U , V ) + γ × ∣ R ( U , S ) − R ( V , S ) ∣ R(W, S) = α_U\times R(U,S) + α_V\times R(V,S) + β\times R(U,V) + γ\times |R(U,S) - R(V,S)| R(W,S)=αU×R(U,S)+αV×R(V,S)+β×R(U,V)+γ×R(U,S)R(V,S)

在这个公式中,我们可以选择系数 α U , α V , β , γ α_U, α_V, β, γ αU,αV,β,γ

例如,如果我们设定 α U = α V = 1 2 , β = 0 , γ = − 1 2 α_U = α_V = \frac{1}{2}, β=0, γ=-\frac{1}{2} αU=αV=21,β=0,γ=21,那么我们就得到了最近邻距离的公式。
而通过系数 α U = α V = 1 2 , β = 0 , γ = 1 2 α_U = α_V = \frac{1}{2}, β=0, γ=\frac{1}{2} αU=αV=21,β=0,γ=21,我们就得到了远邻距离。
在这里插入图片描述

在Scipy中实现

from scipy.cluster.hierarchy import dendrogram, linkage
from matplotlib import pyplot as plt
plt.figure(figsize=(10,10))X = np.array([[5,3],[10,15],[15,12],[24,10],[30,30],[85,70],[71,80],[60,78],[70,55],[80,91],])plt.scatter(X[:,0],X[:,1])

输出:
在这里插入图片描述

linked = linkage(X, 'single')
labelList = [f'point_{i}' for i in range(1, len(X)+1)]plt.figure(figsize=(10, 7))
dendrogram(linked,orientation='top',labels=labelList,distance_sort='descending',show_leaf_counts=True)
plt.show()

输出:
在这里插入图片描述

linked

输出:
在这里插入图片描述

示例

在之前的一节课中,我们学习了课程5,该示例利用线性回归模型解决了根据银行客户收入特征预测其存款规模的问题。

通过此示例,我们证明了,如果我们为构成数据集的每个聚类构建单独的模型,那么使用线性模型是合理的。

让我回顾一下问题陈述:

假设我们想根据某人的收入特征预测其在某家银行的存款规模。这家银行的客户分为几类:退休人员、有子女的家庭、青少年、商人和年轻的机器学习专家。

该数据集可从链接获取。

import numpy as np
import pandas as pd
X = pd.read_csv('credit.csv')

让我提醒你,这个数据集包含有关客户月收入和银行账户的信息。

from matplotlib import pyplot as plt
import seaborn
seaborn.set_theme()plt.figure(figsize=(18,10))
plt.scatter(X.Income, X.Account)

输出:
在这里插入图片描述
请注意,现在我们还没有非常方便的标签来帮助我们针对每个类别训练模型。所以我们的例子变得更加现实了。我们需要想出一些方法来解决这个问题。幸运的是,我们现在知道可以使用聚类算法。

from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler# X = StandardScaler().fit_transform(X.Income.values.reshape(-1,1))
kmeans = KMeans(n_clusters=5,random_state=0).fit(X)
plt.figure(figsize=(18,10))
plt.scatter(X.Income, X.Account, c=kmeans.labels_)

输出:
在这里插入图片描述
K-Means 完美地完成了它的任务!
我们将为每个聚类构建其自己的线性回归。

set(kmeans.labels_)

输出:
{np.int32(0), np.int32(1), np.int32(2), np.int32(3), np.int32(4)}

from sklearn.linear_model import LinearRegressionX, y = X.Income.values, X.Account.valuesx_0, y_0 = X[kmeans.labels_ == 0], y[kmeans.labels_ == 0]
x_1, y_1 = X[kmeans.labels_ == 1], y[kmeans.labels_ == 1]
x_2, y_2 = X[kmeans.labels_ == 2], y[kmeans.labels_ == 2]
x_3, y_3 = X[kmeans.labels_ == 3], y[kmeans.labels_ == 3]
x_4, y_4 = X[kmeans.labels_ == 4], y[kmeans.labels_ == 4]LR_0 = LinearRegression().fit(x_0.reshape(-1,1), y_0)
LR_1 = LinearRegression().fit(x_1.reshape(-1,1), y_1)
LR_2 = LinearRegression().fit(x_2.reshape(-1,1), y_2)
LR_3 = LinearRegression().fit(x_3.reshape(-1,1), y_3)
LR_4 = LinearRegression().fit(x_4.reshape(-1,1), y_4)

让我们显示得到的结果

plt.figure(figsize=(18,10))
plt.scatter(X, y, c=kmeans.labels_)plt.plot([100_000,200_000], [LR_0.predict([[100_000]]), LR_0.predict([[200_000]])])
plt.plot([0,30_000], [LR_1.predict([[0]]), LR_1.predict([[30_000]])])
plt.plot([200_000,300_000], [LR_2.predict([[200_000]]), LR_2.predict([[300_000]])])
plt.plot([0,50_000], [LR_3.predict([[0]]), LR_3.predict([[50_000]])])
plt.plot([50_000,100_000], [LR_4.predict([[50_000]]), LR_4.predict([[100_000]])])

输出:
在这里插入图片描述

from sklearn.metrics import r2_score
print(f"r2_score cluster 0: {r2_score(y_0, LR_0.predict(x_0.reshape(-1,1)))}")
print(f"r2_score cluster 1: {r2_score(y_1, LR_1.predict(x_1.reshape(-1,1)))}")
print(f"r2_score cluster 2: {r2_score(y_2, LR_2.predict(x_2.reshape(-1,1)))}")
print(f"r2_score cluster 3: {r2_score(y_3, LR_3.predict(x_3.reshape(-1,1)))}")
print(f"r2_score cluster 4: {r2_score(y_4, LR_4.predict(x_4.reshape(-1,1)))}")

输出:
r2_score cluster 0: 0.2747806800970829
r2_score cluster 1: 0.28099320642424697
r2_score cluster 2: 0.24097422328004658
r2_score cluster 3: 0.006983387523667006
r2_score cluster 4: 0.0006180165841759289

DBSCAN

DBSCAN 算法是另一种流行的聚类方法。它的优势在于,与 KMeans 算法不同,DBSCAN 算法理论上能够识别几乎任意几何形状的聚类结构。例如,KMeans 算法无法识别带状聚类和放射状聚类,而 DBSCAN 算法只要正确选择超参数,就能完美地完成这项任务。DBSCAN 算法还能独立检测数据中的异常值,并将其从已发现的聚类结构中排除。

DBSCAN 算法


数据集中的所有对象都会被聚类为内部边界异常值内部是指位于半径为 ϵ ϵ ϵ 的小邻域内的对象,其中至少有 M M M 个其他对象。边界是指位于内部对象邻域内的对象。异常值是指不位于内部或边界对象任何邻域内的对象。

  1. 设置算法的超参数:整数值 M M M 和较小的 ϵ ϵ ϵ
  2. 设置样本 U = { x i ∣ i = 0... N } U = \{x_i| i = 0...N\} U={xii=0...N} 个未标记对象
  3. 当样本中存在未标记对象时:
  1. 随机选择一个未标记对象 x x x
  2. 如果 x x x 的邻域内有超过 M M M 个对象,则形成一个新的聚类 K K K,并将 x x x 邻域内的所有对象(包括 x x x 本身)标记为聚类 K K K 的对象。
  3. x x x 邻域内的所有对象执行相同操作。
  4. 否则 x x x 标记为潜在异常值。

DBSCAN 算法可以在同一个 sklearn.cluster 模块中找到。让我们来看看它在著名的 moons 数据集上是如何工作的。

from matplotlib import pyplot as plt
from sklearn.datasets import make_moons
import seaborn as sns
sns.set_theme()
x, y = make_moons(n_samples=200, shuffle=True, noise=5e-2)
plt.scatter(x[:, 0], x[:, 1], c=y)

输出:
在这里插入图片描述
该算法“看待”此数据集的方式有所不同:它没有初始划分为黑白两类聚类。让我们应用 DBSCAN 来获取实际的聚类标签。

plt.scatter(x[:, 0], x[:, 1])

输出:
在这里插入图片描述

from sklearn.cluster import DBSCAN
clustering = DBSCAN(eps=0.25, min_samples=2).fit(x)# 要访问聚类结果,需要访问 clustering.labels_ 字段
clust = clustering.labels_
plt.scatter(x[:, 0], x[:, 1], c=clust)

输出:
在这里插入图片描述

聚类结果非常理想。但需要注意的是,这很大程度上取决于 eps 参数的正确选择。例如,如果我们稍微降低 eps,我们得到的聚类结果会比预期多得多:

clustering = DBSCAN(eps=0.1, min_samples=2).fit(x)
clust = clustering.labels_
plt.scatter(x[:, 0], x[:, 1], c=clust)

输出:
在这里插入图片描述如果我们稍微增加它,那么所有的点将被分配到一个集群。

clustering = DBSCAN(eps=0.5, min_samples=2).fit(x)
clust = clustering.labels_
plt.scatter(x[:, 0], x[:, 1], c=clust)

输出:
在这里插入图片描述
这是“DBSCAN”的一个重要限制。需要记住的是,与“KMeans”相比,更改超参数集并不能减轻我们与选择超参数相关的工作。尽管存在这种复杂性,“DBSCAN”仍然是一种非常有用的聚类算法,它使我们能够识别具有复杂规律性的聚类。

相关文章:

课程10. 聚类问题

课程10. 聚类问题 聚类此类表述的难点K 均值法让我们推广到几个集群的情况如果我们选择其他起始近似值会怎样&#xff1f; 结论在 sklearn 中的实现 如何处理已发现的问题&#xff1f;层次聚类Lance-Williams 算法Lance-Williams 公式在Scipy中实现 示例DBSCANDBSCAN 算法 聚类…...

深度学习中的数据增强:提升食物图像分类模型性能的关键策略

深度学习中的数据增强&#xff1a;提升食物图像分类模型性能的关键策略 在深度学习领域&#xff0c;数据是模型训练的基石&#xff0c;数据的数量和质量直接影响着模型的性能表现。然而&#xff0c;在实际项目中&#xff0c;获取大量高质量的数据往往面临诸多困难&#xff0c;…...

QT设计权限管理系统

Qt能够简单实现系统的权限设计 首先我们需要一个登陆界面 例如这样 然后一级权限&#xff0c;可以看到所有的内容&#xff0c;不设置菜单栏的隐藏。 然后其他权限&#xff0c;根据登陆者的身份进行菜单栏不同的展示。 菜单栏的隐藏代码如下&#xff1a; ui->actionuser-…...

从上帝视角看文件操作

1.为什么使用文件? 如果没有文件,我们写的程序中的数据是存储在电脑的内存中,当程序退出时,内存被回收后,数据就丢失了,等下次运行程序,是无法看到上次程序的数据的。(比如我们在程序中写通讯录时,联系人的相关数据都是放在内存中的,当程序退出时,这些数据也会随之消…...

【51单片机6位数码管显示时间与秒表】2022-5-8

缘由数码管 keil proteus 为什么出现这种情况呢&#xff1f;-编程语言-CSDN问答 #include "reg52.h" unsigned char code smgduan[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0,64}; //共阴0~F消隐减号 unsigned char cod…...

从头训练小模型: 4 lora 微调

1. LoRA (Low-Rank Adaptation) LoRA是一种高效的参数高效微调&#xff08;Parameter-Efficient Fine-Tuning, PEFT&#xff09;方法&#xff0c;原理是通过低秩分解的方式对预训练模型进行微调。 相比于全参数微调&#xff08;Full Fine-Tuning&#xff09;&#xff0c;LoRA…...

前端开发,文件在镜像服务器上不存在问题:Downloading binary from...Cannot download...

问题与处理策略 问题描述 在 Vue 项目中&#xff0c;执行 npm i 下载依赖时&#xff0c;报如下错误 Downloading binary from https://npm.taobao.org/mirrors/node-sass//v4.14.1/win32-x64-72_binding.node Cannot download "https://npm.taobao.org/mirrors/node-sa…...

Debezium Binlog协议与事件转换详解

Debezium Binlog协议与事件转换详解 1. MySQL Binlog通信机制 1.1 连接建立流程 #mermaid-svg-eE88YFqcTG9kUWaZ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-eE88YFqcTG9kUWaZ .error-icon{fill:#552222;}#mer…...

【PostgreSQL数据分析实战:从数据清洗到可视化全流程】4.1 日期时间标准化(时区转换/格式统一)

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 PostgreSQL数据分析实战&#xff1a;数据清洗之日期时间标准化&#xff08;时区转换/格式统一&#xff09;4.1 日期时间标准化&#xff1a;从混乱到有序4.1.1 数据乱象&…...

基于Hive + Spark离线数仓大数据实战项目(视频+课件+代码+资料+笔记)

精品推荐&#xff1a;基于Hive Spark离线数仓大数据实战项目&#xff0c;共23节课&#xff0c;供学习参考。 项目介绍项目中 docker 使用项目环境搭建项目数仓分层项目业务分析sqoop 数据采集python 数据采集项目 ODS 层创建DWD 层构建DWS 层构建项目回顾&#xff08;一&…...

【深入浅出MySQL】之数据类型介绍

【深入浅出MySQL】之数据类型介绍 MySQL中常见的数据类型一览为什么需要如此多的数据类型数值类型BIT&#xff08;M&#xff09;类型INT类型TINYINT类型BIGINT类型浮点数类型float类型DECIMAL(M,D)类型区别总结 字符串类型CHAR类型VARCHAR(M)类型 日期和时间类型enum和set类型 …...

从入门到登峰-嵌入式Tracker定位算法全景之旅 Part 4 |IMU 死算与校正:惯性导航在资源受限环境的落地

Part 4 |IMU 死算与校正:惯性导航在资源受限环境的落地 本章聚焦 ESP32-S3 平台上如何利用 LSM6DS3 IMU 实现 死算(Dead Reckoning),并结合 零速更新(ZUPT) 或 磁力计辅助 进行 漂移校正,最终通过 EKF/UKF 融合提升定位精度。 一、传感器简介与校准 LSM6DS3 主要参数 加速…...

【iOS】 方法交换

【iOS】 方法交换 method-swizzling 文章目录 【iOS】 方法交换 method-swizzling前言什么是method-swizzling相关API方法交换的风险在load方法中保证只加载一次要在当前类的方法中进行交换如果方法依赖于cmd 方法交换的应用 前言 之前看过有关于消息转发的内容,这里我们可以简…...

PostgreSQL 的 ANALYZE 命令

PostgreSQL 的 ANALYZE 命令 ANALYZE 是 PostgreSQL 中用于收集数据库对象统计信息的关键命令&#xff0c;这些统计信息对于查询优化器生成高效执行计划至关重要。 一 ANALYZE 命令 1.1 基本语法 ANALYZE [ ( option [, ...] ) ] [ table_and_columns [, ...] ] ANALYZE [ …...

初识 iOS 开发中的证书固定

引言 在移动应用安全领域&#xff0c;HTTPS/TLS 是数据传输的第一道防线&#xff0c;但仅依赖系统默认的证书验证仍有被中间人&#xff08;MITM&#xff09;攻击的风险。Certificate Pinning&#xff08;证书固定&#xff09;通过将客户端信任“钉”在指定的服务器证书或公钥上…...

2025 年如何使用 Pycharm、Vscode 进行树莓派 Respberry Pi Pico 编程开发详细教程(更新中)

micropython 概述 micropython 官方网站&#xff1a;https://www.micropython.org/ 安装 Micropython 支持固件 树莓派 Pico 安装 Micropython 支持固件 下载地址&#xff1a;https://www.raspberrypi.com/documentation/microcontrollers/ 选择 MicroPython 下载 RPI_PIC…...

设计模式每日硬核训练 Day 17:中介者模式(Mediator Pattern)完整讲解与实战应用

&#x1f504; 回顾 Day 16&#xff1a;责任链模式小结 在 Day 16 中&#xff0c;我们学习了责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;&#xff1a; 将请求沿链传递&#xff0c;节点可选择处理或传递下一节点。实现了请求发送者与多个处理者的解耦…...

文章记单词 | 第63篇(六级)

一&#xff0c;单词释义 vegetable [ˈvedʒtəbl] n. 蔬菜&#xff1b;植物人&#xff1b;生活单调乏味的人&#xff1b;adj. 蔬菜的&#xff1b;植物的faint [feɪnt] adj. 模糊的&#xff1b;微弱的&#xff1b;虚弱的&#xff1b;v. 昏倒&#xff0c;昏厥&#xff1b;n. 昏…...

ES类的索引轮换

通过以下请求方法创建一个名为 “tiered-storage-policy” 的 ISM policy&#xff1a; PUT _plugins/_ism/policies/tiered-storage-policy {"policy": {"description": "Changes replica count and deletes.","schema_version": 1,…...

小白机器人假想:分布式关节控制——机器人运动的未来模式?

引言 在机器人技术快速发展的今天&#xff0c;控制架构的创新往往能带来突破性进展。作为一名机器人爱好者&#xff0c;我最近思考了一个大胆的设想&#xff1a;如果机器人的每个关节都配备独立的动作存储器和处理器&#xff0c;并通过高速光纤网络与中央"驱动总脑"…...

LangChain4j +DeepSeek大模型应用开发——9 优化硅谷小鹿

1.预约业务的实现 这部分我们实现硅谷小鹿的查询订单、预约订单、取消订单的功能 创建MySQL数据库表 CREATE DATABASE xiaolu; USE xiaolu; -- 创建预约表 appointment CREATE TABLE appointment (id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主键ID&#xff0c;自增, -- 主…...

Oracle VirtualBox 在 macOS 上的详细安装步骤

Oracle VirtualBox 在 macOS 上的详细安装步骤 一、准备工作1. 系统要求2. 下载安装包二、安装 VirtualBox1. 挂载安装镜像2. 运行安装程序3. 处理安全限制(仅限首次安装)三、安装扩展包(增强功能)四、配置第一个虚拟机1. 创建新虚拟机2. 分配内存3. 创建虚拟硬盘4. 加载系…...

Day110 | 灵神 | 二叉树 | 根到叶路径上的不足节点

Day110 | 灵神 | 二叉树 | 根到叶路径上的不足节点 1080.根到叶路径上的不足节点 1080. 根到叶路径上的不足节点 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者一开始没看懂&#xff0c;只能通过部分的例子&#xff0c;原因是把路径和小于limit的都给删了…...

超详细讲解C语言转义字符\a \b \r \t \? \n等等

转义字符 C语言有一组字符很特殊&#xff0c;叫做转义字符&#xff0c;顾名思义&#xff0c;改变原来的意思的字符。 1 \? ??)是一个三字母词&#xff0c;在以前的编译器它会被编译为] (??会被编译为[ 因此在以前输入(are you ok ??)就会被编译为are you ok ] 解决这个…...

TensorFlow 多卡训练 tf多卡训练

目录 export TF_GPU_ALLOCATORcuda_malloc_async &#x1f527; 具体作用 优势 &#x1f9e9; 依赖条件 ✅ 设置方式&#xff08;Linux/macOS&#xff09; export TF_GPU_ALLOCATORcuda_malloc_async 是设置 TensorFlow 使用 CUDA 异步内存分配器 的环境变量。这个设置可…...

数据结构--树状数组

树状数组&#xff08;Fenwick Tree&#xff09; 概述 树状数组是一种用于高效处理动态数组中前缀和查询的数据结构。它能够在 O ( l o g n ) O(log n) O(logn) 时间复杂度内完成以下操作&#xff1a; 更新数组中的元素O(logn)查询数组前缀和O(logn) 数组&#xff1a; O(1)…...

如何使用python保存字典

在Python中&#xff0c;可以通过多种方式将字典&#xff08;dict&#xff09;保存到文件中&#xff0c;并能够随时读取恢复。以下是几种常见的方法&#xff1a; 1. 使用 json 模块&#xff08;推荐&#xff09; 适用场景&#xff1a;需要人类可读的文件格式&#xff0c;且数据不…...

C和指针——预处理

预处理是编译前的过程&#xff0c;主要对define&#xff0c;include以及一些编译器定义的内容进行替换 #define的本质就是替换 1、例子 #define FOREVER for(;;) 2、例子 #define TEMPD "1231231231\ 123123123" \\如果太长了&#xff0c;可以用\换行 3、例子——可…...

windows python ta-lib安装

https://github.com/TA-Lib/ta-lib/releases windows安装ta-lib指令 pip install --no-cache-dir https://github.com/cgohlke/talib-build/releases/download/v0.6.3/ta_lib-0.6.3-cp310-cp310-win_amd64.whl...

机器学习+多目标优化的算法如何设计?

一、核心问题与设计思路 机器学习&#xff08;ML&#xff09;与多目标优化&#xff08;MOO&#xff09;的结合旨在解决两类核心问题&#xff1a; 利用ML提升MOO算法的性能&#xff1a;通过机器学习模型预测解的质量、优化搜索方向或加速收敛&#xff1b;利用MOO优化ML模型的多…...

爬虫管理平台-最新版本发布

TaskPyro 是什么&#xff1f; TaskPyro 是一个轻量级的 Python 任务调度平台&#xff0c;专注于提供简单易用的任务管理和爬虫调度解决方案。它能够帮助您轻松管理和调度 Python 任务&#xff0c;特别适合需要定时执行的爬虫任务和数据处理任务。 官方文档&#xff1a;https:/…...

SpringCloud教程 — 无废话从0到1逐步学习

目录 什么是微服务&#xff1f;​ 微服务与单体架构的区别 微服务主要用法概念 远程调用 服务注册/发现&注册中心 配置中心 服务熔断&服务降级 1&#xff09;服务熔断 2&#xff09;服务降级 API 网关 环境准备 Nacos OpenFeign Gateway Sentinel Sea…...

Webug4.0通关笔记12- 第17关 文件上传之前端拦截(3种方法)

目录 一、文件上传前端拦截原理 二、第17关 文件上传(前端拦截) 1.打开靶场 2.构造php脚本 3.源码分析 &#xff08;1&#xff09;js源码 &#xff08;2&#xff09;服务器源码 &#xff08;3&#xff09;总结 4.渗透实战 &#xff08;1&#xff09;禁用js法 &#…...

使用synchronized关键字同步Java线程

问题 在Java多线程编程中&#xff0c;你需要保护某些数据&#xff0c;防止多个线程同时访问导致数据不一致或程序错误。 解决方案 在需要保护的方法或代码段上使用synchronized关键字。 讨论 synchronized关键字是Java提供的同步机制&#xff0c;用于确保在同一时刻只有一…...

从头训练小模型: 2 监督微调SFT

简介 从头训练小模型是我个人对大语言模型(LLM)学习中的重要部分。 通过对一个小规模模型的最小化复现实践&#xff0c;我不仅能够深入理解模型训练的基本流程&#xff0c;还可以系统地学习其中的核心原理和实际运行机制。这种实践性的学习方法让我能够直观地感受模型训练的每…...

【QT】QT中http协议和json数据的解析-http获取天气预报

QT中http协议和json数据的解析 1.http协议的原理2.QT中http协议的通信流程2.1 方法步骤 3.使用http协议&#xff08;通过http下载图片和获取天气预报信息&#xff09;3.1 http下载网络上的图片(下载小文件)3.1.1 示例代码3.1.2 现象 3.2 获取网络上天气预报3.2.1 免费的天气预报…...

PiscTrace针对YOLO深度适配:从v8到v12

一、YOLO简介&#xff1a;目标检测的核心技术 YOLO&#xff08;You Only Look Once&#xff09;是近年来最为流行的目标检测模型&#xff0c;凭借其实时性与高精度&#xff0c;广泛应用于自动驾驶、视频监控、安防检测等多个领域。YOLO系列模型自v1问世以来&#xff0c;经过不…...

前端面试每日三题 - Day 24

这是我为准备前端/全栈开发工程师面试整理的第24天每日三题练习&#xff0c;涵盖了&#xff1a; JavaScript 中的 Promise.all()、Promise.race() 和 Promise.allSettled() 的实际应用和性能差异React 中的 Concurrent Rendering 和 useTransition API如何设计一个高并发的在线…...

正态分布习题集 · 题目篇

正态分布习题集 题目篇 全面覆盖单变量正态、多变量正态、参数估计、假设检验、变换以及应用&#xff0c;共 20 题&#xff0c;从基础到进阶。完成后请移步《答案与解析篇》。 1. 基础定义与性质&#xff08;5题&#xff09; 1.1 密度函数 写出正态分布 N ( μ , σ 2 ) N(…...

Three.js在vue中的使用(二)-动画、材质

一、Three.js 动画原理与实现 1. 基本原理 Three.js 的动画系统基于 关键帧&#xff08;Keyframe&#xff09; 和 时间轴&#xff08;AnimationClip&#xff09; 实现&#xff1a; THREE.AnimationMixer&#xff1a;管理多个动画片段的播放器THREE.AnimationClip&#xff1a…...

【办公类-99-04】20250504闵豆统计表excle转PDF,合并PDF、添加中文字体页眉+边框下划线

需求说明 督导检查&#xff0c;各条线都要收集资料。 今天去加班&#xff0c;遇到家教主任&#xff0c;她让我用保教主任的彩色打印机打印这套活跃度表格。&#xff08;2023学年上学期下学期-2024学年上学期&#xff0c;就是202309-202504&#xff09; 每个excle都是内容在A4一…...

ES类迁移方法

快照(s3 file FS)跨集群迁移es-dumpremote-reindexLogstash Elasticsearch 迁移方法 Elasticsearch 迁移是将数据、索引和配置从一个 Elasticsearch 集群转移到另一个集群的过程。以下是几种常见的迁移方法&#xff1a; 1. 快照和恢复 (Snapshot and Restore) 这是最推荐的…...

智能合约部署之全国职业院校技能大赛“区块链技术应用”赛项—“航班延误险案例”

智能合约部署之全国职业院校技能大赛“区块链技术应用”赛项—“航班延误险案例” 1.启动虚拟机上的区块链 (1)打开VMware虚拟机,在桌面中点击右键,选择Open Terminal打开命令行窗口。 (2)使用"cd geth_local/"命令,切换至区块链根目录,输入下面的命令启动…...

STM32外设-GPIO输入(仅数字)

STM32外设-GPIO输入 一&#xff0c;输入的三种类型1. 上拉 (Pull-up)输入2. 下拉 (Pull-down)输入3. 浮空 (Floating / High-Impedance)输入 二&#xff0c;下拉电阻的作用 学完基础的led&#xff0c;接下来学习key即按键&#xff0c;但在连接按键之前&#xff0c;我们必须了解…...

QT开发工具对比:Qt Creator、Qt Designer、Qt Design Studio

前端开发工具—Qt Designer Qt Designer是Qt框架的一部分&#xff0c;是一个图形用户界面设计工具。它允许开发者通过可视化方式设计和布局GUI组件&#xff0c;而无需手动编写UI代码。设计完成后&#xff0c;Qt Designer生成UI文件&#xff08;通常以.ui为扩展名&#xff09;&…...

(ADC)数模转换器的不同类型对比

&#xff08;ADC&#xff09;数模转换器的不同类型对比 数模转换器&#xff08;ADC&#xff09;类型详解1. **并行比较型ADC&#xff08;Flash ADC&#xff09;****工作原理****优缺点****应用场景** 2. **逐次逼近型ADC&#xff08;SAR ADC&#xff09;****工作原理****优缺点…...

MOS管极间电容参数学习

文章目录 前言1. 输入电容&#xff08;Ciss&#xff09;2. 输出电容&#xff08;Coss&#xff09;3. 反向转移电容&#xff08;Crss&#xff09;4&#xff0c;测试条件解读总结 前言 MOS管在电路设计中非常常用&#xff0c;用途包括DC-DC&#xff0c;电平转换等&#xff0c;所…...

Webug4.0靶场通关笔记14- 第18关 文件上传之Nginx解析缺陷

目录 第18关 渗透实战 1.打开靶场 2.构造php脚本 3.源码分析 &#xff08;1&#xff09;客户端源码 &#xff08;2&#xff09;服务的源码 4.Nginx解析法渗透 &#xff08;1&#xff09;缺陷原因 &#xff08;2&#xff09;缺陷条件 &#xff08;3&#xff09;构造脚…...

外观模式(Facade Pattern)

非常好&#xff01;现在我们来讲解结构型设计模式之一&#xff1a;外观模式&#xff08;Facade Pattern&#xff09;。 我会通过&#xff1a; ✅ 简洁定义 &#x1f3af; 为什么需要 &#x1f40d; Python 代码&#xff08;含注释&#xff09; &#x1f9ed; 流程图 应用场…...

Javase 基础加强 —— 03 集合

本系列为笔者学习Javase的课堂笔记&#xff0c;视频资源为B站黑马程序员出品的《黑马程序员JavaAI智能辅助编程全套视频教程&#xff0c;java零基础入门到大牛一套通关》&#xff0c;章节分布参考视频教程&#xff0c;为同样学习Javase系列课程的同学们提供参考。 集合是一种容…...