基于神经网络的聚类分析

神经网络是一种非常有用的机器学习模型,具有无数的应用。今天,我们将分析一个数据集,看看我们是否可以通过应用无监督聚类技术来查找数据中的模式和隐藏分组,从而获得新的见解。

我们的目标是对复杂数据进行降维,以便我们可以创建无监督的、可解释的集群,如下所示:

图 1:在三维空间中编码的亚马逊手机数据,使用 K 均值聚类定义了八个聚类。

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割

1、数据

我们将研究 2019 年从亚马逊获取的手机和客户评论。该数据集由两个文件组成。

第一个文件 items.csv 包含有关单个产品的数据。它包含以下列:产品 ASIN、产品品牌、产品标题、产品 URL、产品图片 URL、产品平均评分、产品评论页面 URL、产品总评论、产品价格和产品原价。

第二个文件 reviews.csv 包含有关单个评论的数据,可以使用产品 ASIN 列将其链接到 items.csv。reviews.csv 文件的列包含:产品 ASIN、评论者姓名、评论者评分(等级 1 到 5)、评论日期、有效客户、评论标题、评论内容和有用的反馈。

为简洁起见,我们将仅关注 items.csv 文件,但你可以想象在 reviews.csv 上执行非常相似的工作流程,然后可以使用它来分析项目集群与评论者集群。

感谢 Griko Nibras 整理这些数据并将其发布在 Kaggle 上!

2、软件

今天我们将使用 Python 3.7.9 以及机器学习包 TensorFlow。我们将使用 Keras API,这使得构建神经网络变得非常简单。

稍后我们将使用函数 plot_model 来可视化神经网络。在 Windows 10 上运行该函数可能会有问题(至少在撰写本文时)。如果你愿意,可以跳过运行该函数,它会将神经网络图的图像保存到磁盘,这对于可视化很有用,但在其他方面则没有必要。

如果你遇到问题,以下是我让它工作的步骤:

  • 使用 Python 3.7
  • 安装 Graphviz
  • 将 graphviz 添加到你的系统路径,对我来说: C:/Program Files (x86)/Graphviz 2.44.1/bin
  • 安装 python 包 pydot 和 graphviz
  • 将 graphviz 添加到 python 中的路径:
import os
os.environ["PATH"] += os.pathsep + 'C:/Program Files (x86)/Graphviz 2.44.1/bin' 
  • 重新启动你的 python IDE

经过上述操作,我可以用 plot_model 了,但如果你在 Windows 上无法让它工作,我建议你改用 Linux。

3、分析

我们将整个分析流程划分为6个步骤。

3.1 加载 Python 中的库

加载以下库(并安装任何缺少的库)。

import numpy as np  # numpy for math
import pandas       # for dataframes and csv files
import matplotlib.pyplot as plt  # for plotting
from matplotlib import animation  # animate 3D plots
from mpl_toolkits.mplot3d import Axes3D  # 3D plots# Scikit learn
from sklearn.model_selection import train_test_split
from sklearn.cluster import KMeans
from sklearn import manifold# TensorFlow and Keras
import tensorflow as tf
from tensorflow.keras.layers.experimental import preprocessing
from tensorflow import keras

3.2 在 Python 中加载数据

请注意,我已将数据保存到相对目录“./data/”,你需要根据存储数据的位置修改路径。

items_csv = pandas.read_csv("./data/items.csv")
items_csv.head(3) # look at top 3 items
items_csv.shape   # what is the size of the data?
>>> items_csv.head(3)asin     brand  ...  price originalPrice
0  B0000SX2UC       NaN  ...   0.00           0.0
1  B0009N5L7K  Motorola  ...  49.95           0.0
2  B000SKTZ0S  Motorola  ...  99.99           0.0
[3 rows x 10 columns]items_csv.shape
(720, 10)

因此,你会看到我们有 720 行数据,每行包含 10 列信息(如预期)。在继续之前,我们将再做一步:删除所有有缺失数据的行。这是一个有争议的选择,因为我们可以使用插补来填充缺失值,或者在模型中以信息量的方式处理缺失值。为简单起见,我们将从数据集中删除所有有缺失数据的行:

items_features = items_csv.copy().dropna()

3.3 预处理数据

我们的原始数据需要进行转换才能与 Keras 很好地配合使用,因此我们需要对数据进行预处理。我们的一些列是数字,可以进行规范化,而其中一些是字符串(需要特殊处理)。我们将为模型创建一个类似于本教程的预处理层,这将使我们能够适当地使用每个特征列。

首先,我们删除不太可能有用的列:url、image、reviewUrl 和 asin:

# Let's remove these columns as not interesting for us
items_features.pop("url")
items_features.pop("image")
items_features.pop("reviewUrl")
p_labels = items_features.pop("asin")

现在我们将开始创建预处理层。我们为输入特征创建一个字典,其中包含匹配的数据类型:

inputs = {}
for name, column in items_features.items():dtype = column.dtypeif dtype == object:dtype = tf.stringelse:dtype = tf.float32inputs[name] = tf.keras.Input(shape=(1,), name=name, dtype=dtype)inputs
>>> inputs
{'brand': <tf.Tensor 'brand_3:0' shape=(None, 1) dtype=string>, 'title': <tf.Tensor 'title_3:0' shape=(None, 1) dtype=string>, 'rating': <tf.Tensor 'rating_3:0' shape=(None, 1) dtype=float32>, 'totalReviews': <tf.Tensor 'totalReviews_3:0' shape=(None, 1) dtype=float32>, 'price': <tf.Tensor 'price_3:0' shape=(None, 1) dtype=float32>, 'originalPrice': <tf.Tensor 'originalPrice_3:0' shape=(None, 1) dtype=float32>}

你可以看到,输入包含有关数据外观的信息。我们使用它来告诉 Keras 如何将神经网络层连接在一起。

接下来,我们分离出四个数字列,将它们连接成一个特征向量,然后进行规范化:

# deal with numeric features
numeric_inputs = {name: input for name, input in inputs.items() if input.dtype == tf.float32}x = tf.keras.layers.Concatenate()(list(numeric_inputs.values()))
norm = preprocessing.Normalization()
norm.adapt(np.array(items_features[numeric_inputs.keys()]))
all_numeric_inputs = norm(x)
preprocessed_inputs = [all_numeric_inputs]all_numeric_inputs
>>> all_numeric_inputs
<tf.Tensor 'normalization/Identity:0' shape=(None, 4) dtype=float32>

类似地,我们处理字符串特征(我们为每一列创建一个词汇表,并将它们编码为独热编码):

# deal with string features
for name, input in inputs.items():if input.dtype != tf.string:continuelookup = preprocessing.StringLookup(vocabulary=np.unique(items_features[name]))one_hot = preprocessing.CategoryEncoding(max_tokens=lookup.vocab_size())x = lookup(input)x = one_hot(x)preprocessed_inputs.append(x) # append preprocessed feature to features listpreprocessed_inputs
>>> preprocessed_inputs
[<tf.Tensor 'normalization/truediv:0' shape=(None, 4) dtype=float32>, <tf.Tensor 'category_encoding_1/bincount/DenseBincount:0' shape=(None, 12) dtype=float32>, <tf.Tensor 'category_encoding_2/bincount/DenseBincount:0' shape=(None, 716) dtype=float32>]

最后,我们将预处理后的输入连接成一个向量,并创建处理模型,稍后我们可以将其应用于我们的数据,作为神经网络的第一步:

preprocessed_inputs_cat = keras.layers.Concatenate()(preprocessed_inputs)
preprocessing_layer = tf.keras.Model(inputs, preprocessed_inputs_cat, name="ProcessData")# this saves an image of the model, see note regarding plot_model issues
tf.keras.utils.plot_model(model=preprocessing_layer, rankdir="LR", dpi=130, show_shapes=True, to_file="processing.png")

在这里您可以看到我们的处理模型的结果,从每个感兴趣的列的输入开始,到单个特征向量结束:

图 2:数据预处理层的图形可视化。

我们将该层应用到两行数据,以查看预处理层的实际作用:

items_features_dict = {name: np.array(value) for name, value in items_features.items()}# grab two samples
two_sample_dict = {name:values[1:3, ] for name, values in items_features_dict.items()}
two_sample_dict
>>> two_sample_dict
{'brand': array(['Motorola', 'Motorola'], dtype=object), 'title': array(['MOTOROLA C168i AT&T CINGULAR PREPAID GOPHONE CELL PHONE', 'Motorola i335 Cell Phone Boost Mobile'], dtype=object), 'rating': array([2.7, 3.3]), 'totalReviews': array([22, 21], dtype=int64), 'price': array([99.99,  0.  ]), 'originalPrice': array([0., 0.])}
# apply the preprocessing layer
two_sample_fitted = preprocessing_layer(two_sample_dict)two_sample_fitted
>>> two_sample_fitted
<tf.Tensor: shape=(2, 732), dtype=float32, numpy=
array([[-1.4144895 , -0.50023943, -0.67571497, ...,  0.        ,0.        ,  0.        ],[-0.57760113, -0.50619656, -1.1760992 , ...,  0.        ,0.        ,  0.        ]], dtype=float32)>

太棒了!我们现在可以将输入数据处理成有用的张量。现在我们可以继续尝试在数据中找到自然聚类。

3.4 用于降维的自动编码器

我们的模型现在有一个预处理层,它准备原始数据以供使用。但是,一行数据(处理后)由多达 732 个特征表示。我们需要将数据的维度降低到不那么笨重的程度。为了完成这项任务,我们将使用一个简单的自编码器(autoencoder)。你可以在 keras 博客上阅读有关如何实现各种类型的自编码器的更多信息。

这是模型的自动编码器部分:

# This is the size of our input data
full_dim = two_sample_fitted.shape.as_list()[1]# these are the downsampling/upsampling dimensions
encoding_dim1 = 128
encoding_dim2 = 16
encoding_dim3 = 3 # we will use these 3 dimensions for clustering# This is our encoder input
encoder_input_data = keras.Input(shape=(full_dim,))# the encoded representation of the input
encoded_layer1 = keras.layers.Dense(encoding_dim1, activation='relu')(encoder_input_data)
encoded_layer2 = keras.layers.Dense(encoding_dim2, activation='relu')(encoded_layer1)
# Note that encoded_layer3 is our 3 dimensional "clustered" layer, which we will later use for clustering
encoded_layer3 = keras.layers.Dense(encoding_dim3, activation='relu', name="ClusteringLayer")(encoded_layer2)encoder_model = keras.Model(encoder_input_data, encoded_layer3)# the reconstruction of the input
decoded_layer3 = keras.layers.Dense(encoding_dim2, activation='relu')(encoded_layer3)
decoded_layer2 = keras.layers.Dense(encoding_dim1, activation='relu')(decoded_layer3)
decoded_layer1 = keras.layers.Dense(full_dim, activation='sigmoid')(decoded_layer2)# This model maps an input to its autoencoder reconstruction
autoencoder_model = keras.Model(encoder_input_data, outputs=decoded_layer1, name="Encoder")# compile the model
autoencoder_model.compile(optimizer="RMSprop", loss=tf.keras.losses.mean_squared_error)
tf.keras.utils.plot_model(model=autoencoder_model, rankdir="LR", dpi=130, show_shapes=True, to_file="autoencoder.png")

该模型的自编码器层如下所示:

图 3:自编码器层的图形可视化。

3.5 训练模型

现在,我们需要训练模型;目前我们的模型什么都不做!所有模型权重都是随机的,并不是特别有用。

# process the inputs
p_items = preprocessing_layer(items_features_dict)# split into training and testing sets (80/20 split)
train_data, test_data, train_labels, test_labels = train_test_split(p_items.numpy(), p_labels, train_size=0.8, random_state=5)# fit the model using the training data
history = autoencoder_model.fit(train_data, train_data, epochs=1000, batch_size=256, shuffle=True, validation_data=(test_data, test_data))

我们来看看训练进度:

# Investigate training performance:
history_fig, (ax1, ax2) = plt.subplots(2, sharex=True)
history_fig.suptitle('Autoencoder Training Performance')
ax1.plot(range(0,1000), history.history['accuracy'], color='blue')
ax1.set(ylabel='Reconstruction Accuracy')
ax2.plot(range(0,1000), np.log10(history.history['loss']), color='blue')
ax2.plot(range(0,1000), np.log10(history.history['val_loss']), color='red', alpha=0.9)
ax2.set(ylabel='log_10(loss)', xlabel='Training Epoch')
history_fig

图 4:自动编码器模型训练历史。训练部分为蓝色,验证部分为红色。

你可以看到,我们从自动编码器获得了不错的重构效果(训练准确率 76%,验证准确率 65%)。这远非完美重构,还可以做更多工作来改进自动编码器(例如,特征特定编码、更大的编码维度等)。对于我们的目的而言,这已经足够好了。

因此,我们现在有一个编码器,它可以为我们的 732 维数据生成三维表示。它看起来是这样的:

图 5:在 3 维空间中编码的亚马逊手机数据

此时,你可能会想:“我为什么要这样做?这些是 3D 空间中的任意点,我该如何解释这种编码?”。好问题。假设你想知道产品评级如何影响其编码:

图 6:平均用户评分如何影响编码?

我希望你会同意,这出乎意料地容易解释,评分以可预测的方式从高到低分布。你可以制作类似的图表来可视化其他特征对编码的影响。

3.6 聚类

经过所有这些准备,我们终于可以尝试对数据进行聚类了。聚类的方法有很多。我们将使用 K-means 作为最简单的聚类方法之一。我们不仅对原始数据进行聚类,还使用数据的自动编码器表示,以便将问题的维数从 732 维一直降低到 3 维。

第一步,我们需要决定使用多少个聚类!我们将使用elbow方法,如这个 K-means 教程中所示:

encoded_items = encoder_model(p_items)# choose number of clusters K:
Sum_of_squared_distances = []
K = range(1,30)
for k in K:km = KMeans(init='k-means++', n_clusters=k, n_init=10)km.fit(encoded_items)Sum_of_squared_distances.append(km.inertia_)plt.plot(K, Sum_of_squared_distances, 'bx-')
plt.vlines(ymin=0, ymax=150000, x=8, colors='red')
plt.text(x=8.2, y=130000, s="optimal K=8")
plt.xlabel('Number of Clusters K')
plt.ylabel('Sum of squared distances')
plt.title('Elbow Method For Optimal K')
plt.show()

图 7:用于在 K 均值中选择最佳 K 的肘部图

从肘形图来看,K 介于 5 和 10 之间比较合适。我们以 K=8 作为最佳选择。

在这里,我们使用 8 个聚类来拟合 K 均值:

kmeans = KMeans(init='k-means++', n_clusters=8, n_init=10)
kmeans.fit(encoded_items)
P = kmeans.predict(encoded_items)

我们可以在三维表示中轻松地看到这些聚类:

# visualize the clusters:
encoded_fig = plt.figure()
ax = Axes3D(encoded_fig)
p = ax.scatter(encoded_items[:,0], encoded_items[:,1], encoded_items[:,2], c=P, marker="o", picker=True, cmap="rainbow")
plt.colorbar(p, shrink=0.5)
plt.show()angle = 3
ani = animation.FuncAnimation(encoded_fig, rotate, frames=np.arange(0, 360, angle), interval=50)
ani.save('kmeans_fig.gif', writer=animation.PillowWriter(fps=12))

图 8:在三维空间中编码的亚马逊手机数据,使用 K 均值聚类定义了 8 个聚类。

聚类看起来基本合理,但是聚类之间显然存在一些差异,而且 K 均值无法清晰地识别出视觉上清晰的月牙形聚类。对此,可能应该使用更复杂的聚类算法。基于密度的聚类将是我的下一个选择!

4、结论

我们只是触及了该数据集可以做什么的表面,并且有许多不同的技术可以执行聚类(包括监督和无监督)。可以进行额外的工作,分析聚类本身的可解释性(例如,基于聚类的品牌、评级、价格等直方图)。我希望本指南能让你了解如何将这些想法应用于自己的数据!


原文链接:神经网络聚类分析 - BimAnt

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

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

相关文章

mysql面试(一)

前言 从今天开始&#xff0c;更新一些mysql的基础知识&#xff0c;面试会遇到的知识点之类的内容。比如四个隔离级别&#xff0c;mvcc机制&#xff0c;三大日志&#xff0c;索引&#xff0c;B树的形成等等&#xff0c;从数据库的底层来剖析索引和树是怎么形成的&#xff0c;以…

接口自动化测试框架实战-0-项目功能概览

熟悉我CSDN的朋友们应该知道&#xff0c;之前已经更新了requests、pytest、allure2、yaml、jenkins、postman等基础知识的合集。相信大家对接口测试已经有了全面的认识&#xff0c;现在应该迫不及待地想要一个实战项目了。接下来的文章中&#xff0c;我们将把这些知识点串联起来…

C++学习笔记02-结构基础(问题-解答自查版)

前言 以下问题以Q&A形式记录&#xff0c;基本上都是笔者在初学一轮后&#xff0c;掌握不牢或者频繁忘记的点 Q&A的形式有助于学习过程中时刻关注自己的输入与输出关系&#xff0c;也适合做查漏补缺和复盘。 本文对读者可以用作自查&#xff0c;答案在后面&#xff0…

【Linux】HTTP 协议

目录 1. URL2. HTTP 协议2.1. HTTP 请求2.2. HTTP 响应 1. URL URL 表示着是统一资源定位符(Uniform Resource Locator), 就是 web 地址&#xff0c;俗称“网址”; 每个有效的 URL 可以通过互联网访问唯一的资源, 是互联网上标准资源的地址; URL 的主要由四个部分组成: sche…

学习测试10-3自动化 web自动化

web自动化 chrome驱动下载地址&#xff1a; https://registry.npmmirror.com/binary.html?pathchromedriver/ https://googlechromelabs.github.io/chrome-for-testing/#stable观察Google版本&#xff0c;下相应的驱动 运行代码试试&#xff0c;成功Google就会弹出 from se…

华为OD机试2024年C卷D卷 - 山脉的个数/攀登者1 (Java)

华为OD机试&#xff08;C卷D卷&#xff09;2024真题目录 题目描述 攀登者喜欢寻找各种地图&#xff0c;并且尝试攀登到最高的山峰。 地图表示为一维数组&#xff0c;数组的索引代表水平位置&#xff0c;数组的元素代表相对海拔高度。其中数组元素0代表地面。 例如&#xff…

ARM 单片机裸机任务调度框架

前言&#xff1a; 在没有使用操作系统的情况下&#xff0c;一个合理的裸机任务调度方式&#xff0c;可以更好的提供数据的处理&#xff0c;和用户体验&#xff0c;有多种任务调度的方式。 方案 1&#xff1a; 从上到下的任务调度方式&#xff0c;C语言程序的代码是在main函数…

K8S 上部署 Prometheus + Grafana

文章目录 一、使用 Helm 安装 Prometheus1. 配置源2. 下载 prometheus 包3. 安装 prometheus4. 卸载 二、使用 Helm 安装 Grafana1. 配置源2. 安装 grafana3. 访问4. 卸载 一、使用 Helm 安装 Prometheus 1. 配置源 地址&#xff1a;https://artifacthub.io/packages/helm/pro…

[路由器]IP-MAC的绑定与取消

背景&#xff1a;当公司的网络不想与外部人员进行共享&#xff0c;可以在路由器页面配置IP-MAC的绑定&#xff0c;让公司内部人员的手机和电脑的mac&#xff0c;才能接入到公司。第一步&#xff1a;在ARP防护中&#xff0c;启动IP-MAC绑定选项&#xff0c;必须启动仅允许IP-MAC…

linux、windows、macos清空本地DNS缓存

文章目录 Linux&#xff1a;Windows&#xff1a;macOS&#xff1a; Linux&#xff1a; 对于使用systemd的操作系统&#xff08;如CentOS 7、Ubuntu 16.04&#xff09;&#xff0c;可以使用以下命令重启systemd-resolved服务来清除缓存&#xff1a; sudo systemctl restart sys…

【ELK】window下ELK的安装与部署

ELK的安装与部署 1. 下载2. 配置&启动2.1 elasticsarch2.1.1 生成证书2.1.2 生成秘钥2.1.3 将凭证迁移到指定目录2.1.4 改配置2.1.5 启动2.1.6 访问测试2.1.7 生成kibana账号 2.2 kibana2.2.1 改配置2.2.2 启动2.2.3 访问测试 2.3 logstash2.3.1 改配置2.3.2 启动 2.4 file…

你了解你的GD32 MCU系统主频是多少吗 ?

系统时钟是GD32 MCU的时基&#xff0c;可以理解为系统的心跳&#xff0c;片上所有的外设以及CPU最原始的时钟都来自于系统时钟&#xff0c;因而明确当前系统时钟是多少非常重要&#xff0c;只有明确了系统时钟&#xff0c;才能够实现准确的定时、准确的采样间隔以及准确的通信速…

通过QT基于C++实现串口通信

1.软件下载 本文所用到的所有软件都在以下连接可以下载 QT下载&#xff08;注意下载路径最好全英&#xff0c;不要出现中文容易有bug&#xff09; 链接&#xff1a;https://pan.baidu.com/s/1XCPlTBQ8fBOKBYO-H0mSVg?pwdm28f 提取码&#xff1a;m28f 串口工具下载 链接&…

二十、Qt位置相关函数

目录 一、函数概述 二、函数实践 三、总结 一、函数概述 Qt 提供了很多关于获取窗体位置及显示区域大小的函数&#xff0c;如 x()、y()和 pos()、react()、size()、geometry()等&#xff0c;统称为“位置相关函数”或“位置函数”&#xff0c; 如下图所示是几种主要的位置函数…

JS 鼠标拖动实现移动滚动条的滚动效果

效果 现在很多场景都以移动端为基本开发&#xff0c;比如说需要隐藏滚动条&#xff0c;在pc上实现鼠标拖动和手机触摸拖动差不多的效果。 实现 以mdn的overflow属性中范例为基础&#xff0c;内容溢出时候可使用overflow: auto;和overflow: scroll;实现滚动效果。 要实现鼠标…

华为防火墙总部与分支机构建立IPsec VPN涉及NAT穿越

一、IPsec VPN基本概念 1、隧道建立方式&#xff1a;分为手动建立和IKE自动协商&#xff0c;手动建立需要人为配置指定所有IPsec建立的所有参数信息&#xff0c;不支持为动态地址的发起方&#xff0c;实际网络中很少应用&#xff1b;IKE协议是基于密钥管理协议ISAKMP框架设计而…

一文看懂AI的 Transformer 架构!

1 AI的转换器是啥&#xff1f; 转换器&#xff0c;一种将输入序列转换或更改为输出序列的神经网络架构。它们通过学习上下文和跟踪序列组件之间的关系来做到这一点。例如&#xff0c;请考虑以下输入序列&#xff1a;“天空是什么颜色的&#xff1f;” 转换器模型会使用内部数学…

C4D2024软件下载+自学C4D 从入门到精通【学习视频教程全集】+【素材笔记】

软件介绍与下载&#xff1a; 链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1n8cripcv6ZTx4TBNj5N04g?pwdhfg5 提取码&#xff1a;hfg5 基础命令的讲解&#xff1a; 掌握软件界面和基础操作界面。学习常用的基础命令&#xff0c;如建模、材质、灯光、摄像机…

TypeScript体操(一):从基础到进阶

目录 前言Utility Types 是什么&#xff1f;常用 Utility Types前置知识typeofkeyoftypeof 和 keyof 的区别never 关键字extends 关键字结合条件判断infer 类型推断&#xff08;模式匹配&#xff09;判断是与非判断两个类型是否相等或兼容 循环递归嵌套字符串数组协变&#xff…

NMEA2000在船舶控制系统中航空插头插座组件特性

NMEA2000在船舶控制系统中的应用概述 NMEA2000协议是船舶电子设备之间通信的国际标准&#xff0c;广泛应用于船舶导航、监控和自动化系统。它基于CAN&#xff08;Controller Area Network&#xff09;总线技术&#xff0c;以确保在恶劣环境下的可靠性和效率。NMEA2000协议定义了…