人工智能与机器学习:Python从零实现K-Means 算法

🧠 向所有学习者致敬!

“学习不是装满一桶水,而是点燃一把火。” —— 叶芝


我的博客主页: https://lizheng.blog.csdn.net

🌐 欢迎点击加入AI人工智能社区!

🚀 让我们一起努力,共创AI未来! 🚀


K-Means 可是我超喜欢的机器学习算法呢,因为它能帮我们发现数据里那些隐藏起来的模式呢。要是用得好的话,它能把你数据里的分组或者聚类情况展示得明明白白的,那可都是因为它背后那些严谨的数学原理呢。这在现实生活中可有不少厉害的应用呢。

比如说呀,要是你负责分析一个电商网站的点击流数据呢,你就可以用 K-Means 把顾客按照他们点击的内容、加入购物车的东西,还有购买的东西来分成不同的群组呢。这就能帮你搞出一套个性化策略呢,根据顾客所在的群组,把网站体验调整得更符合他们的需求呢。好啦,现在咱们就来好好研究一下这个算法吧!

K-Means 算法

首先得跟大家说说,K-Means 算法是一种无监督机器学习算法哦。无监督机器学习模型的关键特点就是,咱们的数据里没有目标值或者标签呢。换句话说呢,咱们不是要预测啥东西,而是想给数据贴上标签呢。在 K-Means 算法里呀,咱们的目标就是把数据分成不同的群组或者聚类呢。那怎么做到呢?首先呢,用户可以指定要把数据分成多少个聚类呢。我为啥说“可以指定”呢,其实呢,这还是得讲究一些最佳实践呢。要是聚类数太少呢,可能会错过一些对你用例很有价值的信息呢;要是聚类数太多呢,又会变得冗余啦。在给数据点分配聚类的时候呢,每个数据点都会被分配到离它最近的那个聚类呢。现在呢,还有更多细节要讲,咱们接着往下看吧。

关键概念:欧几里得距离

None

回想一下你以前上过的数学课吧。你可能还记得有个叫勾股定理的东西呢:

a 2 + b 2 = c 2 a² + b² = c² a2+b2=c2

咱们用这个公式来计算直角三角形的斜边长度呢(我以前叫它“长边”)。要是想得到 c 的确切数值呢,就得对 a² + b² 开平方根呢。你可能不知道呢,其实你已经学会了怎么计算坐标平面上两个点之间的距离啦!这其实也是线性代数里的一个概念,叫 L2 范数呢。假设你有一个二维坐标平面,x 是水平轴,y 是垂直轴。给定两个点,(x1,y1) 和 (x2,y2),咱们就可以用这个公式来计算它们之间的欧几里得距离呢:

None

咱们也可以在超过两个维度的情况下计算欧几里得距离呢。比如说,这是计算三维空间中两个点之间距离的公式呢:

None

那这和 K-Means 有啥关系呢?咱们接着往下看下一节就知道啦。

质心:初始化、迭代、收敛

先来举个 K-Means 的简单例子吧。下面这张图呢,是我随便编的一个有两个维度的虚构数据集呢。要是你把单独的数据点都画出来呢,看起来大概就是这样的。你可能觉得,用不着 K-Means 也能把这些数据分成不同的聚类呢,因为它们分组的方式看起来还挺明显的呢。不过呢,我还是会给大家演示一下它是怎么工作的呢。

None

图片来源:作者提供

就像我之前说的呢,咱们可以指定要把数据分成多少个聚类呢。在这个例子里呢,咱们就把它分成 3 个聚类吧。咱们先随机生成三个坐标,当作初始的质心来开始这个过程呢。质心呢,就是用来代表一个聚类中心的坐标呢。咱们用星形来标记这些随机生成的质心吧:

None

图片来源:作者提供

接下来呢,咱们要根据欧几里得距离来给数据点分配质心啦。换句话说呢,就是把每个数据点分配给离它最近的那个质心呢。你是不是已经看出来啦,欧几里得距离在 K-Means 里可起着关键作用呢!

None

图片来源:作者提供

完成初始化步骤之后呢,咱们要计算每个聚类里分配到的点的平均值呢,然后把得到的坐标当作新的质心呢。比如说呢,在这个例子里,有一个聚类里分配到了一组点呢,咱们就取这些点的 x 和 y 坐标的平均值呢,然后用得到的坐标作为新的质心或者聚类中心呢。结果大概会是这样的(注意那个“红色”聚类的质心正好就在一个数据点上,因为那个聚类里只有一个数据点呢):

None

图片来源:作者提供

这些聚类看起来好像不太合理呢,对吧?别担心,咱们还没做完呢。咱们再重复一次给聚类分配数据点的过程吧。首先呢,咱们随机初始化三个质心:

None

图片来源:作者提供

然后呢,根据欧几里得距离把数据点分配给最近的质心呢。

None

最后呢,咱们计算每个聚类里数据点的平均坐标呢,然后把得到的坐标当作新的质心呢。

None

图片来源:作者提供

用肉眼看呢,K-Means 算法好像已经把这个数据集分成三个不同的聚类啦。不过呢,它自己还不知道已经找到了最优解呢。所以呢,咱们还得重复同样的过程,不过这次咱们要检查新的聚类和之前的聚类是不是有很大区别呢。关于这个概念,咱们很快就会展开说呢。先来看看收敛是怎么实现的吧。

你肯定已经知道流程啦,咱们先随机生成质心:

None

图片来源:作者提供

根据欧几里得距离把数据点分配给最近的质心:

None

最后呢,咱们计算每个聚类里数据点的平均坐标呢,然后把得到的坐标当作新的质心呢。同时呢,咱们还要检查新的质心和之前的质心之间的距离是不是低于咱们设定的阈值呢。在这个例子里呢,距离是 0,肯定已经满足咱们的标准啦,算法已经收敛啦:

None

None

寻找最佳聚类数量

给定 k 个聚类数量呢,咱们现在知道怎么把数据分成 k 个聚类啦。不过呢,这还是留下了一个问题:最佳的聚类数量 k 到底是多少呢?

咱们可以用一些方法来解决这个问题呢,在咱们要搭建的 KMeans 对象里呢,咱们会找出来哪个聚类数量能得到最高的轮廓系数呢:

None

图片来源:作者提供

a 是每个聚类里数据点和聚类质心之间的平均距离呢,而 b 是每个聚类质心和最近的相邻聚类质心之间的平均距离呢。更实际地说呢,轮廓系数越高呢,就意味着聚类里的点越能很好地定义到自己的聚类里呢,而且各个聚类之间也分得更清楚呢。

KMeans 类

咱们已经了解了 KMeans 算法的所有必要概念啦!现在呢,该开始搭建咱们的对象啦。咱们先从创建初始化函数开始吧。就像你看到的呢,咱们要用到的库只有 numpy、pandas、tqdm(用来显示进度条)和 scikit-learn 里的 silhouette_score 对象呢(别担心,这是咱们唯一从 sklearn 里用到的东西,这样咱们就能真正从头搭建这个算法啦)。咱们来聊聊这些属性吧。

import numpy as np
import pandas as pd
from sklearn.metrics import silhouette_score
from tqdm import tqdmclass DIYKMeans:def __init__(self, max_k=10, max_iters=100, tol=1e-4, random_state=None):self.max_k = max_kself.max_iters = max_itersself.tol = tolself.random_state = random_stateself.k = Noneself.centroids = Noneself.labels_ = Noneself.X_scaled = Noneself.feature_means = Noneself.feature_stds = Noneself.stable_iterations = 0
  • max_k: 尝试拟合模型时聚类数量的上限。
  • max_iters: 拟合模型时随机初始化质心的最大尝试次数。
  • tol: 计算新旧质心距离时的容差阈值。
  • random_state: 随机状态值,方便复现结果。
  • k, centroids, labels_: 找到基于轮廓系数的最佳 k 后,这些属性就会被赋值。k 是最佳聚类数量,centroids 是最佳 k 对应的质心坐标,labels_ 是每个数据点的聚类标签。
  • X_scaled, feature_means, feature_stds: 数据的标准化值,以及对应的均值和标准差。
  • stable_iterations: 用来记录在容差范围内的迭代次数,默认情况下,这个对象会在连续三次迭代满足容差条件后认为算法已经收敛。

质心操作与标准化

接下来的这些方法呢,会涉及到 K-Means 算法的基本操作呢。这些内容应该都很熟悉啦,毕竟咱们之前已经讲过啦。注意咱们还加了一个标准化数据的方法呢。为啥这个很重要呢?因为咱们的算法要求数据得在同一尺度上呢,不然那些取值范围大的特征就会让算法偏向它们呢。比如说呢,假设咱们想根据卧室数量、浴室数量和价格来聚类房屋数据呢。卧室和浴室的数量平均可能在 1 到 5 之间呢,但价格可能会达到几十万呢。要是不标准化的话,计算距离的时候大部分影响都会来自价格特征呢。所以呢,咱们必须标准化或者归一化数据。在这个例子里呢,咱们的标准化方法用的是均值标准化呢。最后呢,咱们看看收敛方法是怎么实现的吧。我发现这个算法的一个缺点呢,就是确认算法收敛的时候,只要新旧质心之间的距离在容差范围内变化一次就行啦。为了确保更稳定的收敛呢,咱们的方法会在连续三次迭代满足容差条件后才认为算法已经收敛啦。

  • standardize_data: 把每个特征都标准化到同一尺度上。
  • initialize_centroids: 给定数据集的特征数量和 k,它会随机生成 k 个维度和数据集特征数量相同的质心。
  • compute_distances: 利用 numpy 自带的线性代数库呢,这个函数用来计算欧几里得距离呢,也就是两个坐标之间形成的向量的长度。
  • assign_clusters: 给定一个数据点和质心,返回最小距离对应的索引。
  • compute_new_centroids: 把每个质心对应的点取出来呢,计算每个特征的均值呢,然后返回新的质心坐标。
  • has_converged: 给定一个容差值呢,检查新质心和旧质心之间的差异是不是在容差范围内呢。这个方法会检查连续三次迭代是不是都满足容差条件呢。要是满足的话呢,就停止操作,认为算法已经收敛啦。
def standardize_data(self, X):self.feature_means = np.mean(X, axis=0)self.feature_stds = np.std(X, axis=0)self.feature_stds[self.feature_stds == 0] = 1return (X - self.feature_means) / self.feature_stdsdef initialize_centroids(self, X, k):np.random.seed(self.random_state)return X[np.random.choice(X.shape[0], k, replace=False)]def compute_distances(self, X, centroids):return np.linalg.norm(X[:, np.newaxis] - centroids, axis=2)def assign_clusters(self, distances):return np.argmin(distances, axis=1)def compute_new_centroids(self, X, labels, k):return np.array([X[labels == i].mean(axis=0) for i in range(k)])def has_converged(self, old_centroids, new_centroids, stable_threshold=3):if np.linalg.norm(new_centroids - old_centroids) < self.tol:self.stable_iterations += 1else:self.stable_iterations = 0return self.stable_iterations >= stable_threshold

拟合方法

这个方法就是把所有东西都整合到一起啦。根据咱们的 max_k 属性呢,咱们会尝试这个范围内的所有 k 值呢。对于每个 k 呢,咱们会运行迭代过程呢,随机初始化质心,给点分配聚类,然后重新计算质心,直到收敛为止呢。在这个过程中呢,咱们还会计算轮廓系数呢。哪个 k 值能得到最高的轮廓系数呢,咱们就会把数据集分成那个数量的聚类呢。从那以后呢,咱们的 k、centroids 和 labels_ 属性就会被赋上最佳数据啦。

def fit(self, X):X = np.array(X)X = self.standardize_data(X)self.X_scaled = Xbest_k = Nonebest_score = -1best_labels = Nonebest_centroids = Noneprint("Fitting KMeans across different k values:")for k in tqdm(range(2, self.max_k + 1), desc="Searching for optimal k"):centroids = self.initialize_centroids(X, k)self.stable_iterations = 0for _ in range(self.max_iters):distances = self.compute_distances(X, centroids)labels = self.assign_clusters(distances)new_centroids = self.compute_new_centroids(X, labels, k)if self.has_converged(centroids, new_centroids):breakcentroids = new_centroidsscore = silhouette_score(X, labels)if score > best_score:best_k = kbest_score = scorebest_labels = labelsbest_centroids = centroidsself.k = best_kself.centroids = best_centroidsself.labels_ = best_labels

用信用卡数据来测试

现在呢,咱们来用 Kaggle 上的一个 信用卡数据集 来测试一下咱们自己搭建的 KMeans 对象吧。

假设你在一个信用卡公司当数据科学家呢,领导让你找出顾客的分群呢。以前呢,业务团队是根据顾客通常购买的东西和平均月余额来分群的呢。现在呢,领导想扩大这个逻辑,但又不知道怎么搞出一个能扩展的方案呢。这时候呢,咱们自己搭建的 KMeans 对象就派上用场啦。

咱们先从导入数据开始吧。

data = pd.read_csv('CC GENERAL.csv')

这个数据集里有很多特征呢,不过呢,咱们先别一下子把业务团队吓着,所以咱们只保留以下这几列呢。这些定义都是从我下载数据的 Kaggle 页面上直接拿过来的哦:

BALANCE_FREQUENCY: 余额更新的频率,是一个 0 到 1 之间的分数(1 = 经常更新,0 = 不经常更新)

PURCHASES_FREQUENCY: 购买的频率,是一个 0 到 1 之间的分数(1 = 经常购买,0 = 不经常购买)

CREDIT_LIMIT: 用户的信用卡额度

PAYMENTS: 用户支付的金额

PRCFULLPAYMENT: 用户支付全额的比例

TENURE: 用户使用信用卡服务的年限

cols_to_keep = ['BALANCE_FREQUENCY','PURCHASES_FREQUENCY','CREDIT_LIMIT','PAYMENTS','PRC_FULL_PAYMENT','TENURE']
data_for_kmeans = data[cols_to_keep]
data_for_kmeans = data_for_kmeans.dropna()

咱们先来做点简单的探索性分析呢,看看这些特征的一些基本情况吧。以下是这个数据集的一些关键事实呢。

  • 咱们看到的是大约 8600 个有完整数据的顾客样本呢。
  • 购买频率高和购买频率低的顾客各占一半呢。
  • 大多数顾客的信用卡额度都在 6500 美元以下呢。
  • 大多数顾客支付的金额在 2000 美元以下呢,但最高支付金额可以达到 50000 美元呢。
  • 大多数顾客支付的金额只占他们应付款项的 15% 左右呢。
  • 大多数顾客使用信用卡服务的年限是 12 年,而且变化不大呢。
data_for_kmeans.describe()

None

图片来源:作者提供

用咱们自己搭建的 KMeans 模型来拟合

现在咱们已经对数据有了更好的了解啦,那就开始用咱们的模型来拟合它吧。

km = DIYKMeans(max_k=20)
km.fit(X=data_for_kmeans)

None

图片来源:作者提供

print('最佳聚类数量:',km.k)

None

理解聚类结果

太棒啦!咱们自己搭建的 KMeans 对象把数据集分成了 7 个聚类呢。咱们的工作还远远没有结束呢。现在咱们已经从数学上把顾客分成了不同的群组啦,那咱们就来好好探索一下每个群组里的关键模式吧。为了做到这一点呢,我搭建了一个自定义函数呢,它可以输出每个群组的数量呢,还能显示每个特征的平均值呢,还会生成一个热力图呢,这样就能很方便地比较和对比啦。我在咱们的对象的 labels_ 属性基础上给数据集加了一个“Cluster”列呢。以下是我发现的关键模式呢:

  • 除了第 3 个聚类以外,每个聚类都包含使用信用卡服务年限接近 12 年的顾客呢。
  • 第 2 个聚类是唯一一个购买频率高而且支付比例也高的群组呢,它的信用卡额度只是略高于平均水平呢。
  • 第 0 个、第 4 个和第 5 个聚类支付比例都非常低呢;不过呢,第 4 个聚类是这三个聚类里购买频率最低的呢。
  • 第 6 个聚类是高消费群组呢,信用卡额度最高,支付金额也最大呢。
  • 第 5 个聚类和第 6 个聚类在消费方面很相似呢,不过呢,支付金额要低得多呢。

根据这些模式呢,咱们能实施哪些实用的策略或者方法呢?记得哦,信用卡公司是通过收取消费者的支付手续费和利息来赚钱的呢。所以呢,公司可能希望顾客不要一次性把账单都还清呢,这样公司就能赚取利息啦;不过呢,要是顾客欠款太多呢,公司又收不到全额还款啦。所以呢,我有以下几个想法:

  • 让第 5 个聚类的顾客支付比例接近第 6 个聚类呢。
  • 研究一下给第 2 个聚类的顾客提高信用卡额度呢,因为他们大多数都能按时还款呢。
  • 研究一下给第 0 个、第 4 个和第 5 个聚类的顾客降低信用卡额度呢,直到他们的支付比例提高呢。
data_for_kmeans['Cluster'] = km.labels_def summarize_by_cluster_with_heatmap(df, cluster_col='Cluster'):if cluster_col not in df.columns:raise ValueError(f"列 '{cluster_col}' 在 DataFrame 中找不到哦。")value_cols = [col for col in df.select_dtypes(include='number').columns if col != cluster_col]if not value_cols:raise ValueError("除了聚类列以外,没有数值型列可以进行总结呢。")grouped = df.groupby(cluster_col)means = grouped[value_cols].mean().round(2).add_suffix('_mean')counts = grouped.size().to_frame('count')summary = pd.concat([counts, means], axis=1).reset_index()return summary.style.background_gradient(cmap='YlGnBu', subset=summary.columns[1:]).format("{:.2f}")summarize_by_cluster_with_heatmap(df=data_for_kmeans)

None

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/77653.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【神经网络与深度学习】训练集与验证集的功能解析与差异探究

引言 在深度学习模型的训练过程中&#xff0c;训练集和验证集是两个关键组成部分&#xff0c;它们在模型性能的提升和评估中扮演着不可替代的角色。通过分析这两者的区别和作用&#xff0c;可以帮助我们深入理解模型的学习过程和泛化能力&#xff0c;同时为防止过拟合及优化超…

Macos m系列芯片环境下python3安装mysqlclient系列问题

最近学习python3&#xff0c;在安装mysqlclient的时候遇到了一些问题&#xff0c;直接使用哦pip install mysqlclient 直接报错了&#xff0c;记录一下解决方案。 环境信息 设备&#xff1a;Macbook Pro m1 系统&#xff1a;macos Sequoia 15.3.2 最终成功的python版本&#xf…

微信小程序-van-uploader的preview-size

preview-size支持数组格式 修改前修改后1、升级微信小程序里面的van版本:2、 重新构建npm3、重启微信开发工具 修改前 引用van组件的上传文件&#xff0c;设置预览图尺寸&#xff0c;刚开始设置的是preview-size“140”&#xff0c;出来的效果就是一个正方形。 修改后 1、升级…

2. 第一个网页:前端基础入门

第一个网页&#xff1a;前端基础入门 一、网页文件基础认知 1. 文件扩展名 .htm 或 .html 均为网页文件后缀&#xff0c;二者功能完全一致扩展名隐藏方法 系统设置 → 文件夹选项 → 查看 → 取消勾选「隐藏已知文件类型的扩展名」 二、前端发展简史 1. 浏览器战争与标准混…

云原生--核心组件-容器篇-7-Docker私有镜像仓库--Harbor

1、Harbor的定义与核心作用 定义&#xff1a; Harbor是由VMware开源的企业级容器镜像仓库系统&#xff0c;后捐赠给 CNCF (Cloud Native Computing Foundation)。它基于Docker Registry扩展了企业级功能&#xff0c;用于存储、分发和管理容器镜像&#xff08;如Docker、OCI标准…

Java项目与技术栈场景题深度解析

Java项目与技术栈场景题深度解析 在互联网大厂Java求职者的面试中&#xff0c;经常会被问到关于Java项目或技术栈的场景题。本文通过一个故事场景来展示这些问题的实际解决方案。 第一轮提问 面试官&#xff1a;马架构&#xff0c;欢迎来到我们公司的面试现场。请问您对Java…

SpringMVC 静态资源处理 mvc:default-servlet-handler

我们先来看看效果,当我把这一行注释掉的时候&#xff1a; 我们来看看页面&#xff1a; 现在我把注释去掉&#xff1a; 、 可以看到的是&#xff0c;这个时候又可以访问了 那么我们就可以想&#xff0c;这个 <mvc:default-servlet-handler />它控制着我们页面的访问…

【leetcode】最长公共子路径问题

滚动hash 滚动哈希&#xff08;rolling hash&#xff09;也叫 Rabin-Karp 字符串哈希算法&#xff0c;它是将某个字符串看成某个进制下的整数&#xff0c;并将其对应的十进制整数作为hash值。 滚动hash算法的推导 假设有一个长度为n的数组a[0],a[1],a[2],…a[n-1]&#xff0…

【Linux网络】:套接字之UDP

一、UDP和TCP协议 TCP &#xff08;Transmission Control Protocol 传输控制协议&#xff09;的特点&#xff1a; 传输层协议有连接&#xff08;在正式通信前要先建立连接&#xff09;可靠传输&#xff08;在内部帮我们做可靠传输工作&#xff09;面向字节流 UDP &#xff08;U…

React19 useOptimistic 用法

用法 乐观更新 发起异步请求时&#xff0c;先假设请求会成功立即更新 UI 给用户反馈若请求最终失败&#xff0c;再将 UI 恢复到之前的状态 const [optimisticState, addOptimistic] useOptimistic(state, updateFn) 参数 state&#xff1a;实际值&#xff0c;可以是 useSta…

Deepseek-v3+cline+vscode java自动化编程

1、Deepseek DeepSeek 充值后&#xff0c;创建apikey 2、vscode Visual Studio Code - Code Editing. Redefined 3、下载插件cline 4、配置deepeseek-v3 的密钥到cline 5、不可用 在开始的几次调用能正常使用起来&#xff0c;用了几次后&#xff0c;不能使用了&#xff0c;请求…

数据分析案例:环境数据分析

目录 数据分析案例&#xff1a;环境数据分析1. 项目背景2. 数据加载与预处理2.1 数据说明2.2 读取与清洗 3. 探索性数据分析&#xff08;EDA&#xff09;3.1 时序趋势3.2 日内变化3.3 气象与污染物相关性 4. 特征工程4.1 时间特征4.2 滞后与滚动统计4.3 目标变量 5. 模型构建与…

网络原理 - 8

目录 补充 网络层 IP 协议 基本概念&#xff1a; 协议头格式 地址管理 如何解决 IP 地址不够用呢&#xff1f;&#xff1f;&#xff1f; 1. 动态分配 IP 地址&#xff1a; 2. NAT 机制&#xff08;网络地址映射&#xff09; 3. IPv6 网段划分 一些特殊的 IP 地址 …

向量检索新选择:FastGPT + OceanBase,快速构建RAG

随着人工智能的快速发展&#xff0c;RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09;技术日益受到关注。向量数据库作为 RAG 系统的核心基础设施&#xff0c;堪称 RAG 的“记忆中枢”&#xff0c;其性能直接关系到大模型生成内容的精准度与…

dify对接飞书云文档,并且将图片传入飞书文档

前面讲了如何让dify展示图片&#xff0c;但是如果想让智能体回答的带图片的内容生成个文档该怎么弄呢&#xff1f;今天来实践一下。 dify工具带的有飞书云文档&#xff0c;正好&#xff0c;咱们就利用飞书云文档。 1、首先配置飞书云文档的key跟secret 注意要开头左侧的权限&a…

Linux系统之设置开机启动运行桌面环境

Linux 开机运行级别介绍与 Ubuntu 桌面环境配置指南 一、Linux 开机运行级别(Runlevel) 在传统的 Linux 系统(如 SysV init 初始化系统)中,运行级别定义了系统启动时加载的服务和资源。常见的运行级别如下: 运行级别模式用途0Halt(停机模式)关闭系统1Single User Mode…

Spring Cloud Gateway配置双向SSL认证(完整指南)

本文将详细介绍如何为Spring Cloud Gateway配置双向SSL认证,包括证书生成、配置和使用。 目录结构 /my-gateway-project ├── /certs │ ├── ca.crt # 根证书 │ ├── ca.key # 根私钥 │ ├── gateway.crt # 网关证书 │ ├── …

【虚幻5蓝图Editor Utility Widget:创建高效模型材质自动匹配和资产管理工具,从3DMax到Unreal和Unity引擎_系列第二篇】

虚幻5蓝图Editor Utility Widget 一、基础框架搭建背景&#xff1a;1. 创建Editor Utility Widget2.根控件选择窗口3.界面功能定位与阶段4.查看继承树5.目标效果 二、模块化设计流程1.材质替换核心流程&#xff1a;2.完整代码如下 三、可视化界面UI布局1. 添加标题栏2. 构建滚动…

LabVIEW实现DMM与开关模块扫描测量

该程序基于 LabVIEW&#xff0c;用于控制数字万用表&#xff08;DMM&#xff09;与开关模块进行测量扫描。通过合理配置触发源、测量参数等&#xff0c;实现对多路信号的自动化测量与数据获取&#xff0c;在电子测试、工业测量等领域有广泛应用。 ​ 各步骤功能详解 开关模块…

OpenAvatarChat要解决UnicodeDecodeError

错误信息如下 ailed to import handler module client/h5_rendering_client/client_handler_lam Traceback (most recent call last):File "E:\Codes\Python\aigc\OpenAvatarChat\src\demo.py", line 82, in <module>main()File "E:\Codes\Python\aigc\O…