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

学习日记_20241123_聚类方法(高斯混合模型)续

前言

提醒:
文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。
其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展及意见建议,欢迎评论区讨论交流。

文章目录

  • 前言
  • 续:
  • 手动实现
    • 代码分析
      • def __init__(self, n_components, max_iter=100, tol=1e-6)
      • def initialize_parameters(self, X)
      • def e_step(self, X)
      • def m_step(self, X)
      • 数学背景
      • fit(self, X)
      • predict(self, X)


续:

学习日记_20241117_聚类方法(高斯混合模型)
在这里插入图片描述

手动实现

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normalclass GaussianMixtureModel:def __init__(self, n_components, max_iter=100, tol=1e-6):self.n_components = n_componentsself.max_iter = max_iterself.tol = toldef initialize_parameters(self, X):n_samples, n_features = X.shapeself.weights = np.ones(self.n_components) / self.n_componentsself.means = X[np.random.choice(n_samples, self.n_components, replace=False)]self.covariances = np.array([np.cov(X, rowvar=False)] * self.n_components)def e_step(self, X):n_samples = X.shape[0]self.responsibilities = np.zeros((n_samples, self.n_components))for k in range(self.n_components):pdf = multivariate_normal(mean=self.means[k], cov=self.covariances[k])self.responsibilities[:, k] = self.weights[k] * pdf.pdf(X)self.responsibilities /= self.responsibilities.sum(axis=1, keepdims=True)def m_step(self, X):n_samples, n_features = X.shapeeffective_n = self.responsibilities.sum(axis=0)self.means = np.dot(self.responsibilities.T, X) / effective_n[:, np.newaxis]self.covariances = np.zeros((self.n_components, n_features, n_features))for k in range(self.n_components):X_centered = X - self.means[k]self.covariances[k] = (self.responsibilities[:, k][:, np.newaxis] * X_centered).T @ X_centeredself.covariances[k] /= effective_n[k]self.weights = effective_n / n_samplesdef fit(self, X):self.initialize_parameters(X)log_likelihood_old = 0for iteration in range(self.max_iter):self.e_step(X)self.m_step(X)log_likelihood = 0for k in range(self.n_components):pdf = multivariate_normal(mean=self.means[k], cov=self.covariances[k])log_likelihood += np.sum(self.responsibilities[:, k] * np.log(self.weights[k] * pdf.pdf(X) + 1e-10))if np.abs(log_likelihood - log_likelihood_old) < self.tol:print(f"Converged at iteration {iteration}")breaklog_likelihood_old = log_likelihooddef predict(self, X):n_samples = X.shape[0]likelihoods = np.zeros((n_samples, self.n_components))for k in range(self.n_components):pdf = multivariate_normal(mean=self.means[k], cov=self.covariances[k])likelihoods[:, k] = self.weights[k] * pdf.pdf(X)return np.argmax(likelihoods, axis=1)# 可视化结果
def plot_results(X, labels, means, covariances):plt.figure(figsize=(8, 6))unique_labels = np.unique(labels)colors = ['r', 'g', 'b', 'c', 'm', 'y']for i, label in enumerate(unique_labels):plt.scatter(X[labels == label, 0], X[labels == label, 1], s=20, color=colors[i % len(colors)], label=f"Cluster {label + 1}")# 绘制高斯分布的等高线mean = means[label]cov = covariances[label]x, y = np.meshgrid(np.linspace(X[:, 0].min() - 1, X[:, 0].max() + 1, 100),np.linspace(X[:, 1].min() - 1, X[:, 1].max() + 1, 100))pos = np.dstack((x, y))rv = multivariate_normal(mean, cov)plt.contour(x, y, rv.pdf(pos), levels=5, colors=colors[i % len(colors)], alpha=0.5)plt.title("Gaussian Mixture Model Clustering")plt.xlabel("Feature 1")plt.ylabel("Feature 2")plt.legend()plt.show()# 测试
if __name__ == "__main__":np.random.seed(42)X1 = np.random.normal(0, 1, (100, 2))X2 = np.random.normal(5, 1, (100, 2))X3 = np.random.normal(10, 1, (100, 2))X = np.vstack((X1, X2, X3))plt.scatter(X[:, 0], X[:, 1])plt.title("Original Data")plt.xlabel("Feature 1")plt.ylabel("Feature 2")gmm = GaussianMixtureModel(n_components=3)gmm.fit(X)labels = gmm.predict(X)plot_results(X, labels, gmm.means, gmm.covariances)

数据与结果为
在这里插入图片描述
在这里插入图片描述

代码分析

def init(self, n_components, max_iter=100, tol=1e-6)

class GaussianMixtureModel:def __init__(self, n_components, max_iter=100, tol=1e-6):self.n_components = n_components self.max_iter = max_iter  self.tol = tol 
  • n_components:高斯混合模型中的组件数,即聚类的数量。
  • max_iter:最大迭代次数,防止算法不收敛时无限循环。
  • tol:收敛的容忍度,用于判断算法是否收敛。

def initialize_parameters(self, X)

    def initialize_parameters(self, X):n_samples, n_features = X.shapeself.weights = np.ones(self.n_components) / self.n_componentsself.means = X[np.random.choice(n_samples, self.n_components, replace=False)]self.covariances = np.array([np.cov(X, rowvar=False)] * self.n_components)

self.weights = np.ones(self.n_components) / self.n_components
K K K 为高斯混合模型中的组件数(即 n_components)则每个组件的初始权重 π k \pi_k πk 为: π k = 1 K \pi_k = \frac{1}{K} πk=K1,其中 k k k 的取值范围是 1 1 1 K K Kself.weights 为一个长度为 n_components 的数组:
π 1 = π 2 = ⋯ = π K = 1 K \pi_1 = \pi_2 = \cdots = \pi_K = \frac{1}{K} π1=π2==πK=K1

self.means = X[np.random.choice(n_samples, self.n_components, replace=False)]
X X X 为数据集,其中包含 n n n 个样本(即 n_samples),每个样本是一个特征向量。设 K K K 为高斯混合模型中的组件数(即 n_components)。
从数据集 X X X 中随机选择 K K K 个不重复的样本作为初始均值向量。用数学表达式表示就是:
μ k = X i k \mu_k = X_{i_k} μk=Xik
其中:

  • μ k \mu_k μk 是第 k k k 个组件的初始均值向量。
  • X i k X_{i_k} Xik 是数据集 X X X 中的第 i k i_k ik 个样本。
  • i k i_k ik 是从集合 { 1 , 2 , … , n } \{1, 2, \ldots, n\} {1,2,,n} 中随机选择的不重复的 K K K 个整数。
    具体地,可以表示为:
    μ 1 , μ 2 , … , μ K = X i 1 , X i 2 , … , X i K \mu_1, \mu_2, \ldots, \mu_K = X_{i_1}, X_{i_2}, \ldots, X_{i_K} μ1,μ2,,μK=Xi1,Xi2,,XiK
    其中 { i 1 , i 2 , … , i K } \{i_1, i_2, \ldots, i_K\} {i1,i2,,iK} 是从 { 1 , 2 , … , n } \{1, 2, \ldots, n\} {1,2,,n} 中随机选择的不重复的 K K K 个整数。
    在代码中,np.random.choice(n_samples, self.n_components, replace=False) 实现了从 n n n 个样本中随机选择 K K K 个不重复的样本索>引,然后通过这些索引从数据集 X X X 中提取相应的样本作为初始均值向量。
    在这里插入图片描述

self.covariances = np.array([np.cov(X, rowvar=False)] * self.n_components)
这行代码的目的是初始化高斯混合模型(Gaussian Mixture Model,GMM)中每个组件的协方差矩阵。让我们逐步分析这行代码:

  1. np.cov(X, rowvar=False): 这个函数计算输入数据 X 的协方差矩阵。参数 rowvar=False 表示每一列代表一个变量,而每一行代表一个观测值。这是在多维数据中常见的设置,其中每一维(或特征)存储在单独的列中。
  2. [np.cov(X, rowvar=False)] * self.n_components: 这部分代码创建了一个列表,其中包含 self.n_components 个相同的协方差矩阵。self.n_components 是GMM中的组件数。
  3. np.array(...): 最后,这个列表被转换成一个NumPy数组,使得 self.covariances 成为一个二维数组,其中每个元素都是一个协方差矩阵。

def e_step(self, X)

    def e_step(self, X):n_samples = X.shape[0]self.responsibilities = np.zeros((n_samples, self.n_components))for k in range(self.n_components):pdf = multivariate_normal(mean=self.means[k], cov=self.covariances[k])self.responsibilities[:, k] = self.weights[k] * pdf.pdf(X)self.responsibilities /= self.responsibilities.sum(axis=1, keepdims=True)

self.responsibilities = np.zeros((n_samples, self.n_components))
这行代码在高斯混合模型(Gaussian Mixture Model, GMM)中用于初始化一个责任矩阵(responsibility matrix)。

  • (n_samples, self.n_components) 指定了数组的形状,其中 n_samples 是输入数据集中样本的数量,self.n_components 是模型中高斯成分的数量。
  • 责任矩阵 self.responsibilities 的每一行对应于一个样本,而每一列对应于一个高斯成分。
  • 矩阵中的每个元素 self.responsibilities[i, j] 表示样本 i 属于高斯成分 j 的责任值(即概率)。它衡量了样本 i 在当前模型参数下属于成分 j 的可能性。
    这段代码是高斯混合模型(Gaussian Mixture Model, GMM)中 E 步骤(Expectation Step)的一部分。它的主要作用是计算每个样本属于每个高斯成分的责任值(responsibility),并进行归一化处理。我们来逐行分析这段代码的含义:

for k in range(self.n_components): 这里的循环遍历所有的高斯成分
kself.n_components 是高斯成分的数量。

pdf = multivariate_normal(mean=self.means[k], cov=self.covariances[k]) 使用 scipy.stats.multivariate_normal
创建一个多元高斯分布对象 pdf,其均值为 self.means[k],协方差矩阵为self.covariances[k]。这表示当前成分 k 的概率密度函数(PDF)。

self.responsibilities[:, k] = self.weights[k] * pdf.pdf(X)

  • 这一行计算每个样本在高斯成分 k 下的责任值,并将其存储在责任矩阵 self.responsibilities 的第 k 列中。
  • self.weights[k] 是成分 k 的混合权重,表示该成分在总体中占的比例。
  • pdf.pdf(X) 计算所有输入样本 X 在成分 k 下的概率密度值。
  • self.weights[k] * pdf.pdf(X) 计算每个样本在成分 k 下的加权概率密度(即责任值)。

self.responsibilities /= self.responsibilities.sum(axis=1, keepdims=True)

  • 这行代码对责任矩阵进行归一化处理,使得每个样本在所有成分上的责任值之和为 1。
  • self.responsibilities.sum(axis=1, keepdims=True) 计算每个样本在所有成分上的总责任值。
  • 将责任矩阵每一行的值除以该行的总和,确保每个样本的责任值在所有成分之间是一个概率分布。

def m_step(self, X)

    def m_step(self, X):n_samples, n_features = X.shapeeffective_n = self.responsibilities.sum(axis=0)self.means = np.dot(self.responsibilities.T, X) / effective_n[:, np.newaxis]self.covariances = np.zeros((self.n_components, n_features, n_features))for k in range(self.n_components):X_centered = X - self.means[k]self.covariances[k] = (self.responsibilities[:, k][:, np.newaxis] * X_centered).T @ X_centeredself.covariances[k] /= effective_n[k]self.weights = effective_n / n_samples

effective_n = self.responsibilities.sum(axis=0)
这行代码的作用是计算每个高斯成分的有效样本数量(effective number of samples),并将其存储在变量 effective_n 中。我们来详细分析这一行代码的含义。

  1. self.responsibilities
    • 这是之前提到的责任矩阵,形状为 (n_samples, n_components),其中每一行对应一个样本,每一列对应一个高斯成分。矩阵中的每个值表示样本对某个成分的责任。
  2. self.responsibilities.sum(axis=0)
    • sum(axis=0) 表示对责任矩阵的列进行求和。
    • 这将返回一个一维数组,长度等于高斯成分的数量(n_components)。
    • 数组中的每个元素 effective_n[k] 表示第 k 个高斯成分的有效样本数量,即所有样本在该成分上的责任值之和。
  • 有效样本数量:有效样本数量反映了每个高斯成分在当前模型下的“重要性”或“权重”。如果某个成分的有效样本数量很小,说明这个成分对当前数据的解释能力较弱。

self.means = np.dot(self.responsibilities.T, X) / effective_n[:, np.newaxis]
这行代码用于更新高斯混合模型中每个高斯成分的均值(means)。让我们逐步分析这行代码及其背后的逻辑。

  1. self.responsibilities.T
    • self.responsibilities 是一个形状为 (n_samples, n_components) 的矩阵,表示每个样本对每个高斯成分的责任值。
    • self.responsibilities.T 是将责任矩阵进行转置,得到一个形状为 (n_components, n_samples) 的矩阵。
  2. np.dot(self.responsibilities.T, X)
    • X 是输入数据矩阵,形状为 (n_samples, n_features),表示 n_samples 个样本的特征。
    • 执行矩阵乘法 np.dot(self.responsibilities.T, X) 将会产生一个形状为 (n_components, n_features) 的矩阵。
    • 这里,每一行对应一个高斯成分,表示该成分加权后的特征总和。具体来说,这些特征是根据每个样本在该成分上的责任值加权后的结果。
  3. effective_n[:, np.newaxis]
    • effective_n 是一个一维数组,表示每个高斯成分的有效样本数量(我们在之前的讨论中提到过)。
    • 使用 np.newaxiseffective_n 转换为形状为 (n_components, 1) 的列向量,这样可以在后续的除法运算中进行广播。
  4. 最后的除法
    • 将加权特征总和除以每个成分的有效样本数量,得到加权均值。
    • 这一步的结果将更新 self.means,即每个高斯成分的新均值。

数学背景

在高斯混合模型中,均值的更新可以用以下公式表示:
μ k = ∑ i = 1 N γ i k x i ∑ i = 1 N γ i k \mu_k = \frac{\sum_{i=1}^{N} \gamma_{ik} x_i}{\sum_{i=1}^{N} \gamma_{ik}} μk=i=1Nγiki=1Nγikxi
其中:

  • μ k \mu_k μk是第 k k k个高斯成分的均值。
  • γ i k \gamma_{ik} γik是样本 i i i对成分 k k k的责任值。
  • x i x_i xi 是样本 i i i的特征向量。
    这行代码正是这个公式的实现形式,通过矩阵运算来有效地更新每个成分的均值。

在这里插入图片描述
这段代码的目的是为高斯混合模型中的每个高斯成分计算协方差矩阵,并更新权重。

  1. self.covariances = np.zeros((self.n_components, n_features, n_features))
    这一行初始化每个高斯成分的协方差矩阵为零矩阵,形状为 (n_components, n_features, n_features),即为每个成分分配一个 n features × n features n_{\text{features}} \times n_{\text{features}} nfeatures×nfeatures 的协方差矩阵。
  2. for k in range(self.n_components):
    这个循环遍历每一个高斯成分,从 0 到 self.n_components - 1
  3. X_centered = X - self.means[k]
    这行代码计算每个样本相对于当前成分均值的偏差。X_centered 是一个包含所有样本的矩阵,其中每个样本的特征值都减去了该成分的均值。
  4. self.covariances[k] = (self.responsibilities[:, k][:, np.newaxis] * X_centered).T @ X_centered
    这里计算协方差矩阵的主要部分:
    • self.responsibilities[:, k][:, np.newaxis]:提取第 k k k 个成分的责任值,并将其转换为列向量。
    • * X_centered:将责任值与居中后的数据相乘,以加权样本。
    • (.T @ X_centered):进行矩阵乘法,计算加权样本的外积,从而得到一个 n features × n features n_{\text{features}} \times n_{\text{features}} nfeatures×nfeatures 的矩阵。
  5. 协方差计算
  • 计算得到的结果表示了当前成分的加权协方差矩阵,但为了得到正确的协方差矩阵,还需要将其除以该成分的有效样本数量。
    self.covariances[k] /= effective_n[k]
    • 将加权结果除以 effective_n[k],得到第 k k k 个高斯成分的协方差矩阵。
  1. 权重更新
    self.weights = effective_n / n_samples
    • 最后一行代码用于计算每个高斯成分的权重。权重的计算是将每个成分的有效样本数量除以总样本数量 n_samples,从而得到每个成分在整个模型中的比重。

fit(self, X)

    def fit(self, X):self.initialize_parameters(X)log_likelihood_old = 0for iteration in range(self.max_iter):self.e_step(X)self.m_step(X)log_likelihood = 0for k in range(self.n_components):pdf = multivariate_normal(mean=self.means[k], cov=self.covariances[k])log_likelihood += np.sum(self.responsibilities[:, k] * np.log(self.weights[k] * pdf.pdf(X) + 1e-10))if np.abs(log_likelihood - log_likelihood_old) < self.tol:print(f"Converged at iteration {iteration}")breaklog_likelihood_old = log_likelihood

这段代码实现了高斯混合模型(GMM)中的 fit 方法。它通过期望最大化(EM)算法来拟合模型,计算对数似然(log likelihood)。

  1. 初始化参数
    Initialize  μ k , Σ k , and  π k for all components  k \text{Initialize } \mu_k, \Sigma_k, \text{ and } \pi_k \text{ for all components } k Initialize μk,Σk, and πk for all components k
  2. E步(期望步)
    在E步中,计算每个数据点对每个成分的责任(即每个组件生成该数据点的概率):
    r n k = π k ⋅ N ( x n ∣ μ k , Σ k ) ∑ j = 1 K π j ⋅ N ( x n ∣ μ j , Σ j ) r_{nk} = \frac{\pi_k \cdot \mathcal{N}(x_n | \mu_k, \Sigma_k)}{\sum_{j=1}^{K} \pi_j \cdot \mathcal{N}(x_n | \mu_j, \Sigma_j)} rnk=j=1KπjN(xnμj,Σj)πkN(xnμk,Σk)
    其中, r n k r_{nk} rnk 是数据点 x n x_n xn 对于成分 k k k 的责任值, N ( x n ∣ μ k , Σ k ) \mathcal{N}(x_n | \mu_k, \Sigma_k) N(xnμk,Σk) 是多元正态分布的概率密度函数。
  3. M步(最大化步)
    在M步中,更新模型参数,即均值、协方差和权重:
  • 更新均值:
    μ k = 1 N k ∑ n = 1 N r n k x n \mu_k = \frac{1}{N_k} \sum_{n=1}^{N} r_{nk} x_n μk=Nk1n=1Nrnkxn
  • 更新协方差:
    Σ k = 1 N k ∑ n = 1 N r n k ( x n − μ k ) ( x n − μ k ) T \Sigma_k = \frac{1}{N_k} \sum_{n=1}^{N} r_{nk} (x_n - \mu_k)(x_n - \mu_k)^T Σk=Nk1n=1Nrnk(xnμk)(xnμk)T
  • 更新权重:
    π k = N k N \pi_k = \frac{N_k}{N} πk=NNk
    其中, N k = ∑ n = 1 N r n k N_k = \sum_{n=1}^{N} r_{nk} Nk=n=1Nrnk 是属于成分 k k k 的有效样本数量。
  1. 对数似然计算
    对数似然是整个数据集 X X X 在模型下的对数概率:
    log ⁡ L = ∑ n = 1 N log ⁡ ( ∑ k = 1 K π k ⋅ N ( x n ∣ μ k , Σ k ) ) \log L = \sum_{n=1}^{N} \log \left( \sum_{k=1}^{K} \pi_k \cdot \mathcal{N}(x_n | \mu_k, \Sigma_k) \right) logL=n=1Nlog(k=1KπkN(xnμk,Σk))
    由于在计算中添加了一个小的常数 1 e − 10 1e-10 1e10 以避免对数计算中的数值问题,完整的表达式为:
    log ⁡ L ≈ ∑ n = 1 N ∑ k = 1 K r n k log ⁡ ( π k ⋅ N ( x n ∣ μ k , Σ k ) + 1 e − 10 ) \log L \approx \sum_{n=1}^{N} \sum_{k=1}^{K} r_{nk} \log \left( \pi_k \cdot \mathcal{N}(x_n | \mu_k, \Sigma_k) + 1e-10 \right) logLn=1Nk=1Krnklog(πkN(xnμk,Σk)+1e10)
  2. 收敛检查
    收敛条件是检查当前对数似然与上一轮的对数似然之差是否小于容忍度 tol \text{tol} tol
    ∣ log ⁡ L − log ⁡ L old ∣ < tol |\log L - \log L_{\text{old}}| < \text{tol} logLlogLold<tol

predict(self, X)

    def predict(self, X):n_samples = X.shape[0]likelihoods = np.zeros((n_samples, self.n_components))for k in range(self.n_components):pdf = multivariate_normal(mean=self.means[k], cov=self.covariances[k])likelihoods[:, k] = self.weights[k] * pdf.pdf(X)return np.argmax(likelihoods, axis=1)

这段代码实现了高斯混合模型(GMM)中的 predict 方法,目的是根据已拟合的模型来预测给定数据点 X X X 的每个样本属于哪个组件。

  1. 输入数据
    • X X X 是一个 n × d n \times d n×d 的矩阵,其中 n n n 是样本数量, d d d 是特征维数。
  2. 初始化似然数组
    • 创建一个 n × K n \times K n×K 的矩阵 likelihoods,其中 K K K 是组件的数量。这个矩阵将用于存储每个样本在每个组件下的似然值。
      likelihoods = [ 0 0 … 0 0 0 … 0 ⋮ ⋮ ⋱ ⋮ 0 0 … 0 ] ( n × K ) \text{likelihoods} = \begin{bmatrix} 0 & 0 & \ldots & 0 \\ 0 & 0 & \ldots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \ldots & 0 \end{bmatrix} \quad (n \times K) likelihoods= 000000000 (n×K)
  3. 计算每个组件的似然
    • 对于每个组件 k k k,计算数据点 X X X 在该组件下的加权似然值:
      likelihoods [ : , k ] = π k ⋅ N ( X ∣ μ k , Σ k ) \text{likelihoods}[:, k] = \pi_k \cdot \mathcal{N}(X | \mu_k, \Sigma_k) likelihoods[:,k]=πkN(Xμk,Σk)
      其中:
    • π k \pi_k πk 是组件 k k k 的权重(混合系数)。
    • N ( X ∣ μ k , Σ k ) \mathcal{N}(X | \mu_k, \Sigma_k) N(Xμk,Σk) 是多元正态分布在组件 k k k 下的概率密度函数。
  4. 确定预测标签
    • 对于每个样本,选择具有最大似然值的组件,返回其索引作为预测类别:
      predictions = arg ⁡ max ⁡ k ( likelihoods [ : , k ] ) \text{predictions} = \arg\max_{k}(\text{likelihoods}[:, k]) predictions=argkmax(likelihoods[:,k])
      这意味着,对于每个样本 $ n $,其最终预测标签为:
      y ^ n = arg ⁡ max ⁡ k ( π k ⋅ N ( x n ∣ μ k , Σ k ) ) \hat{y}_n = \arg\max_{k} \left( \pi_k \cdot \mathcal{N}(x_n | \mu_k, \Sigma_k) \right) y^n=argkmax(πkN(xnμk,Σk))
  5. 返回预测结果
    • 结果是一个长度为 n n n 的数组,包含每个样本的预测组件索引。

总结起来,predict 方法通过计算每个样本在每个高斯组件下的加权似然,将样本分配给最可能的组件,从而完成聚类或分类任务。

相关文章:

学习日记_20241123_聚类方法(高斯混合模型)续

前言 提醒&#xff1a; 文章内容为方便作者自己后日复习与查阅而进行的书写与发布&#xff0c;其中引用内容都会使用链接表明出处&#xff08;如有侵权问题&#xff0c;请及时联系&#xff09;。 其中内容多为一次书写&#xff0c;缺少检查与订正&#xff0c;如有问题或其他拓展…...

SpringMVC——简介及入门

SpringMVC简介 看到SpringMVC这个名字&#xff0c;我们会发现其中包含Spring&#xff0c;那么SpringMVC和Spring之间有怎样的关系呢&#xff1f; SpringMVC隶属于Spring&#xff0c;是Spring技术中的一部分。 那么SpringMVC是用来做什么的呢&#xff1f; 回想web阶段&#x…...

文件操作完成后,为什么要关闭文件

原因包括&#xff1a; 释放系统资源&#xff1a;打开文件时&#xff0c;操作系统会分配资源&#xff0c;如文件描述符或句柄&#xff0c;用于管理文件访问。如果文件保持打开状态&#xff0c;这些资源就不会被释放&#xff0c;可能导致资源耗尽。 确保数据完整性&#xff1a;写…...

vue3+echarts+ant design vue实现进度环形图

1、代码 <div> <!-- 目标环形图 --><div id"main" class"chart_box"> </div><div class"text_target">目标</div> </div>// 目标环形图 const onEcharts () > {// 基于准备好的dom&#xff0c;初…...

使用argo workflow 实现springboot 项目的CI、CD

文章目录 基础镜像制作基础镜像设置镜像源并安装工具git下载和安装 Maven设置环境变量设置工作目录默认命令最终dockerfile 制作ci argo workflow 模版volumeClaimTemplatestemplatesvolumes完整workflow文件 制作cd argo workflow 模版Workflow 结构Templates 定义创建 Kubern…...

C++知识点总结(58):序列型动态规划

动态规划Ⅰ 一、基础1. 意义2. 序列 dp 解法 二、例题1. 最大子段和2. 删数最大子段和&#xff08;数据强度&#xff1a;pro max&#xff09;3. 最长上升子序列&#xff08;数据强度&#xff1a;pro max&#xff09;4. 3 或 5 的倍数序列5. 数码约数序列 一、基础 1. 意义 动…...

go interface(接口)使用

在 Go 语言中&#xff0c;接口&#xff08;interface&#xff09;是一种抽象类型&#xff0c;它定义了一组方法&#xff0c;但是不实现这些方法。接口指定了一个对象的行为&#xff0c;而不关心对象的具体实现。接口使得代码更加灵活和可扩展。 定义接口 接口使用 type 关键字…...

【docker】docker commit 命令 将当前容器的状态保存为一个新的镜像

在Docker容器中安装了许多软件&#xff0c;并希望将当前容器的状态保存为一个新的镜像&#xff0c;可以使用docker commit命令来创建一个新的镜像。以下是如何操作的步骤&#xff1a; 找到容器ID或名称&#xff1a; 首先&#xff0c;需要找到想要保存的容器的ID或名称。可以使用…...

使用 Java 中的 `String.format` 方法格式化字符串

前言 在编程过程中&#xff0c;我们经常需要创建格式化的字符串来满足特定的需求&#xff0c;比如生成用户友好的消息、构建报告或是输出调试信息。Java 提供了一个强大的工具——String.format 方法&#xff0c;它可以帮助我们轻松地完成这些任务。 String.format 方法简介 …...

图论最短路(floyed+ford)

Floyd 算法简介 Floyd 算法&#xff08;也称为 Floyd-Warshall 算法&#xff09;是一种动态规划算法&#xff0c;用于解决所有节点对之间的最短路径问题。它可以同时处理加权有向图和无向图&#xff0c;包括存在负权边的情况&#xff08;只要没有负权环&#xff09;。 核心思…...

BERT的中文问答系统39

实现当用户在GUI中输入问题&#xff08;例如“刘邦”&#xff09;且输出的答案被标记为不正确时&#xff0c;自动从百度百科中搜索相关内容并显示在GUI中的功能&#xff0c;我们需要对现有的代码进行一些修改。以下是完整的代码&#xff0c;包括对XihuaChatbotGUI类的修改以及新…...

从 Mac 远程控制 Windows:一站式配置与实践指南20241123

引言&#xff1a;跨平台操作的需求与挑战 随着办公场景的多样化&#xff0c;跨平台操作成为现代开发者和 IT 人员的刚需。从 Mac 系统远程控制 Windows&#xff0c;尤其是在同一局域网下&#xff0c;是一种高效解决方案。不仅能够灵活管理资源&#xff0c;还可以通过命令行简化…...

【Linux学习】【Ubuntu入门】1-5 ubuntu软件安装

1.使用sudo apt-get install vim&#xff1a;安装vim编辑器。 参考安装 安装时可能会遇到的问题 2.deb软件安装命令sudo dpkg -i xxx.deb 下载软件安装包时下载Linux版本&#xff0c;在Ubuntu中双击deb文件或者输入命令sudo dpkg -i xxx.deb&#xff0c;xxx.deb为安装包名称…...

如何自动下载和更新冰狐智能辅助?

冰狐智能辅助的版本更新非常快&#xff0c;如果设备多的话每次手工更新会非常麻烦&#xff0c;现在分享一种免费的自动下载和安装冰狐智能辅助的方法。 一、安装迅雷浏览器 安装迅雷浏览器1.19.0.4280版本&#xff0c;浏览器用于打开冰狐的官网&#xff0c;以便于从官网下载a…...

动态渲染页面爬取

我们可以直接使用模拟浏览器运行的方式来实现&#xff0c;这样就可以做到在浏览器中看到是什么样&#xff0c;抓取的源码就是什么样&#xff0c;也就是可见即可爬。这样我们就不用再去管网页内部的 JavaScript 用了什么算法渲染页面&#xff0c;不用管网页后台的 Ajax 接口到底…...

C++适配器模式之可插入适配器的实现模式和方法

可插入适配器与Adaptee的窄接口 在C适配器模式中&#xff0c;可插入适配器&#xff08;Pluggable Adapter&#xff09;是指适配器类的设计允许在运行时动态地插入不同的Adaptee对象&#xff0c;从而使适配器具有灵活性和可扩展性。这种设计使得适配器不仅限于适配一个特定的Ad…...

每日一练:【动态规划算法】斐波那契数列模型之第 N 个泰波那契数(easy)

1. 第 N 个泰波那契数&#xff08;easy&#xff09; 1. 题目链接&#xff1a;1137. 第 N 个泰波那契数 2. 题目描述 3.题目分析 这题我们要求第n个泰波那契Tn的值&#xff0c;很明显的使用动态规划算法。 4.动态规划算法流程 1. 状态表示&#xff1a; 根据题目的要求及公…...

Hash table类算法【leetcode】

哈希表中关键码就是数组的索引下标&#xff0c;然后通过下标直接访问数组中的元素 那么哈希表能解决什么问题呢&#xff0c;一般哈希表都是用来快速判断一个元素是否出现集合里。 例如要查询一个名字是否在这所学校里。 要枚举的话时间复杂度是O(n)&#xff0c;但如果使用哈希…...

windows实现VNC连接ubuntu22.04服务器

最近弄了一个700块钱的mini主机&#xff0c;刷了ubuntu22.04系统&#xff0c;然后想要在笔记本上通过VNC连接&#xff0c;这样就有了一个linux的开发环境。最后实现的过程为&#xff1a; 安装vnc服务器 安装 VNC 服务器软件&#xff1a; sudo apt update sudo apt install t…...

中国电信星辰大模型:软件工厂与文生视频技术的深度解析

在科技日新月异的今天,人工智能(AI)技术正以惊人的速度改变着我们的生活和工作方式。作为这一领域的领军企业之一,中国电信凭借其强大的研发实力和深厚的技术积累,推出了星辰大模型,旨在为用户带来更加智能、高效、便捷的服务体验。本文将重点介绍中国电信星辰大模型中的…...

项目实战:基于Vue3实现一个小相册

相册的示例效果图 注意看注释... 要实现图片的相册效果&#xff0c;图片命名可以像{img1.jpg,img2.jpg,img3.jpg}类似于这种的命名方式。 CSS部分&#xff1a; <style>/* 伪元素选择器&#xff0c;用于在具有clear_ele类的元素内部的末尾添加一个新的元素 */.clear_ele:…...

macOS安装nvm node

macOS安装nvm macOS安装nvm创建 nvm 工作目录配置环境变量使用 nvm查看可用的 Node.js 版本安装特定版本 macOS安装nvm brew install nvm创建 nvm 工作目录 mkdir ~/.nvm配置环境变量 vim ~/.zshrc# nvm export NVM_DIR"$HOME/.nvm" [ -s "/opt/homebrew/opt…...

解决整合Django与Jinja2兼容性的问题

提问 解决整合Django与Jinja2时遇到了一些兼容性问题。已经按照常规步骤在我的settings.py中配置了Jinja2作为模板引擎&#xff0c;同时保留了Django默认的模板设置。然而尝试同时使用Django和Jinja2时&#xff0c;系统报错提示我没有指定模板。如果我尝试移除Django的默认模板…...

Elasticsearch面试内容整理-高级特性

Elasticsearch 提供了一系列高级特性,这些特性可以极大地增强其搜索、分析和管理能力,使得它在大数据场景中表现出色。以下是 Elasticsearch 的一些重要高级特性: 近实时搜索(Near Real-Time Search) Elasticsearch 的一个关键特性是 近实时搜索(NRT),这意味着数据写入…...

linux通过手工删除文件卸载oracle 11g rac的具体步骤

在linux操作系统中&#xff0c;有些时候我们自己学习和测试会临时搭建的oracle rac。事情完成后&#xff0c;我们想回收资源&#xff0c;需要去卸载oracle rac。为了快速卸载oracle rac&#xff0c;今天我们介绍下如何通过手工删除文件的方式来完成工作&#xff08;操作都需要在…...

【ArcGISPro】根据yaml构建原始Pro的conda环境

使用场景 我们不小心把原始arcgispro-py3的conda环境破坏了,我们就可以使用以下方法进行修复 查找文件 在arcgis目录下找到yaml文件 如果没找到请复制以下内容到新的yaml文件 channels: - esri - defaults dependencies: - anyio=4.2.0=py311haa95532_0 - appdirs=1.4.4=p…...

刷题笔记15

问题描述 小M和小F在玩飞行棋。游戏结束后&#xff0c;他们需要将桌上的飞行棋棋子分组整理好。现在有 N 个棋子&#xff0c;每个棋子上有一个数字序号。小M的目标是将这些棋子分成 M 组&#xff0c;每组恰好5个&#xff0c;并且组内棋子的序号相同。小M希望知道是否可以按照这…...

【LeetCode热题100】队列+宽搜

这篇博客是关于队列宽搜的几道题&#xff0c;主要包括N叉树的层序遍历、二叉树的锯齿形层序遍历、二叉树最大宽度、在每个数行中找最大值。 class Solution { public:vector<vector<int>> levelOrder(Node* root) {vector<vector<int>> ret;if(!root) …...

【阵列信号处理】相干信号和非相干信号生成

文章目录 一、总结二、知识点相干&#xff08;coherent&#xff09;和非相干&#xff08;incoherent&#xff09;信号相干信号生成代码 相关信号&#xff08;correlated signal&#xff09;相关信号生成代码 正交信号定义 本文记录博主的科研日记。如果对博主的其他文章感兴趣&…...

React 组件生命周期

React 组件生命周期 React 组件生命周期是React框架中一个核心概念,它描述了一个组件从创建到销毁的过程。理解组件生命周期对于高效开发React应用至关重要,因为它允许开发者在一个组件的不同阶段执行特定的逻辑。本文将详细介绍React组件的生命周期方法,并解释它们在组件的…...