【机器学习】NMF(非负矩阵分解)

article/2025/9/21 14:36:06

写在篇前

  本篇文章主要介绍NMF算法原理以及使用sklearn中的封装方法实现该算法,最重要的是理解要NMF矩阵分解的实际意义,将其运用到自己的数据分析中!

理论概述

  NMF(Non-negative matrix factorization),即对于任意给定的一个非负矩阵V,其能够寻找到一个非负矩阵W和一个非负矩阵H,满足条件V=W*H,从而将一个非负的矩阵分解为左右两个非负矩阵的乘积。**其中,V矩阵中每一列代表一个观测(observation),每一行代表一个特征(feature);W矩阵称为基矩阵,H矩阵称为系数矩阵或权重矩阵。这时用系数矩阵H代替原始矩阵,就可以实现对原始矩阵进行降维,得到数据特征的降维矩阵,从而减少存储空间。**过程如下图所示:

在这里插入图片描述

  nmf更详尽的原理可以参考Non-negative matrix factorization - Wikipedia,这里我主要列出我很关注的损失函数(lossFunction or objective function):

  • squared frobenius norm
    a r g    m i n ⎵ W , H 1 2 ∣ ∣ A − W H ∣ ∣ F r o 2 + α ρ ∣ ∣ W ∣ ∣ 1 + α ρ ∣ ∣ H ∣ ∣ 1 + α ( 1 − ρ ) 2 ∣ ∣ W ∣ ∣ F r o 2 + α ( 1 − ρ ) 2 ∣ ∣ H ∣ ∣ F r o 2 \underbrace{arg\;min}_{W,H}\frac{1}{2}||A-WH||_{Fro}^2 +\alpha\rho|| W||_1+\alpha\rho|| H||_1+\frac{\alpha(1-\rho)}{2}|| W||_{Fro}^2 + \frac{\alpha(1-\rho)}{2}|| H||_{Fro}^2 W,H argmin21AWHFro2+αρW1+αρH1+2α(1ρ)WFro2+2α(1ρ)HFro2
    ​ 其中:
    1 2 ∣ ∣ A − W H ∣ ∣ F r o 2 = 1 2 ∑ i , j ( A i j − W H i j ) 2 \frac{1}{2} ||A - WH||_{\mathrm{Fro}}^2 = \frac{1}{2} \sum_{i,j} (A_{ij} - {WH}_{ij})^2 21AWHFro2=21i,j(AijWHij)2
    α \alpha α为L1&L2正则化参数,而\rho为L1正则化占总正则化项的比例。||*||_1为L1范数。

  • Kullback-Leibler (KL)
    d K L ( X , Y ) = ∑ i , j ( X i j log ⁡ ( X i j Y i j ) − X i j + Y i j ) d_{KL}(X, Y) = \sum_{i,j} (X_{ij} \log(\frac{X_{ij}}{Y_{ij}}) - X_{ij} + Y_{ij}) dKL(X,Y)=i,j(Xijlog(YijXij)Xij+Yij)

  • Itakura-Saito (IS)

d I S ( X , Y ) = ∑ i , j ( X i j Y i j − log ⁡ ( X i j Y i j ) − 1 ) d_{IS}(X, Y) = \sum_{i,j} (\frac{X_{ij}}{Y_{ij}} - \log(\frac{X_{ij}}{Y_{ij}}) - 1) dIS(X,Y)=i,j(YijXijlog(YijXij)1)
​ 实际上,上面三个公式是beta-divergence family中的三个特殊情况(分别是当 β = 2 , 1 , 0 \beta = 2, 1, 0 β=2,1,0),其原型是:
d β ( X , Y ) = ∑ i , j 1 β ( β − 1 ) ( X i j β + ( β − 1 ) Y i j β − β X i j Y i j β − 1 ) d_{\beta}(X, Y) = \sum_{i,j} \frac{1}{\beta(\beta - 1)}(X_{ij}^\beta + (\beta-1)Y_{ij}^\beta - \beta X_{ij} Y_{ij}^{\beta - 1}) dβ(X,Y)=i,jβ(β1)1(Xijβ+(β1)YijββXijYijβ1)

代码实现

代码解读

   在sklearn封装了NMF的实现,可以非常方便我们的使用,其实现基本和前面理论部分的实现是一致的,但是注意sklearn中输入数据的格式是(samples, features):

from sklearn.decomposition import NMF
from sklearn.datasets import load_irisX, _ = load_iris(True)# can be used for example for dimensionality reduction, source separation or topic extraction
# 个人认为最重要的参数是n_components、alpha、l1_ratio、solver
nmf = NMF(n_components=2,  # k value,默认会保留全部特征init=None,  # W H 的初始化方法,包括'random' | 'nndsvd'(默认) |  'nndsvda' | 'nndsvdar' | 'custom'.solver='cd',  # 'cd' | 'mu'beta_loss='frobenius',  # {'frobenius', 'kullback-leibler', 'itakura-saito'},一般默认就好tol=1e-4,  # 停止迭代的极限条件max_iter=200,  # 最大迭代次数random_state=None,alpha=0.,  # 正则化参数l1_ratio=0.,  # 正则化参数verbose=0,  # 冗长模式shuffle=False  # 针对"cd solver")# -----------------函数------------------------
print('params:', nmf.get_params())  # 获取构造函数参数的值,也可以nmf.attr得到,所以下面我会省略这些属性# 下面四个函数很简单,也最核心,例子中见
nmf.fit(X)
W = nmf.fit_transform(X)
W = nmf.transform(X)
nmf.inverse_transform(W)
# -----------------属性------------------------
H = nmf.components_  # H矩阵
print('reconstruction_err_', nmf.reconstruction_err_)  # 损失函数值
print('n_iter_', nmf.n_iter_)  # 实际迭代次数

注意点:

  • init参数中,nndsvd(默认)更适用于sparse factorization,其变体则适用于dense factorization.
  • solver参数中,如果初始化中产生很多零值,Multiplicative Update (mu) 不能很好更新。所以mu一般不和nndsvd使用,而和其变体nndsvdanndsvdar使用。
  • solver参数中,cd只能优化Frobenius norm函数;而mu可以更新所有损失函数

案例1

  第一个案例很简单,目的是理解分解出来的这两个矩阵能用来干嘛,分别是什么意思,但是其实我在文章第一部分已经解释了,直接看例子:

>>> import numpy as np
>>> X = np.array([[1, 1], [2, 1], [3, 1.2], [4, 1], [5, 0.8], [6, 1]])
>>> from sklearn.decomposition import NMF
>>> model = NMF(n_components=2, init='random', random_state=0)
>>> W = model.fit_transform(X)
>>> H = model.components_
>>> X_new = np.array([[1, 0], [1, 6.1], [1, 0], [1, 4], [3.2, 1], [0, 4]])
>>> W_new = model.transform(X_new)
>>> W_new  # 输出 W_new

array([[0.35919303],
​ [0.86264547],
​ [0.35919303],
​ [0.68932578],
​ [1.23195088],
​ [0.33013275]])

  ok,这个小例子就说明了我们通过NMF获得系数矩阵H,并用系数矩阵H获得新矩阵W_new的基矩阵,实现W_new的数据降维(or 特征提取)。实际上,这时W_new = model.transform(X_new)做的工作相当于:

np.mat(X_new)*(np.mat(H).I)

matrix([[0.35919303],
​ [0.86264547],
​ [0.35919303],
​ [0.68932578],
​ [1.23195088],
​ [0.33013275]])

案例2

  这里再举一个NMF在图像特征提取的应用,来自官方示例,根据我的需要改动了一些:

from time import time
from numpy.random import RandomState
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_olivetti_faces
from sklearn import decompositionn_row, n_col = 2, 3
n_components = n_row * n_col
image_shape = (64, 64)
rng = RandomState(0)# #############################################################################
# Load faces data
dataset = fetch_olivetti_faces('./', True,random_state=rng)
faces = dataset.datan_samples, n_features = faces.shapeprint("Dataset consists of %d faces, features is %s" % (n_samples, n_features))def plot_gallery(title, images, n_col=n_col, n_row=n_row, cmap=plt.cm.gray):plt.figure(figsize=(2. * n_col, 2.26 * n_row))plt.suptitle(title, size=16)for i, comp in enumerate(images):plt.subplot(n_row, n_col, i + 1)vmax = max(comp.max(), -comp.min())plt.imshow(comp.reshape(image_shape), cmap=cmap,interpolation='nearest',vmin=-vmax, vmax=vmax)plt.xticks(())plt.yticks(())plt.subplots_adjust(0.01, 0.05, 0.99, 0.93, 0.04, 0.)# #############################################################################
estimators = [('Non-negative components - NMF',decomposition.NMF(n_components=n_components, init='nndsvda', tol=5e-3))
]# #############################################################################
# Plot a sample of the input dataplot_gallery("First centered Olivetti faces", faces[:n_components])# #############################################################################
# Do the estimation and plot itfor name, estimator in estimators:print("Extracting the top %d %s..." % (n_components, name))t0 = time()data = facesestimator.fit(data)train_time = (time() - t0)print("done in %0.3fs" % train_time)components_ = estimator.components_print('components_:', components_.shape, '\n**\n', components_)plot_gallery('%s - Train time %.1fs' % (name, train_time),components_)
plt.show()#---------------------------其他注释---------------------------
V矩阵:400*4096
W矩阵:400*6
H矩阵:6*4096

  下面是script运行结果:

在这里插入图片描述
在这里插入图片描述

写在篇后

  NMF最早由科学家D.D.Lee和H.S.Seung提出的一种非负矩阵分解方法,并在Nature发表文章《Learning the parts of objects by non-negative matrix factorization》。随后也有了很多NMF变体,应用也越发广泛,包括文本降维、话题提取、图像处理等。这里必须指出,我看到一份NMF非常完整的资料,但是精力有限,不能全面cover,有兴趣的同学可以参考nimfa。


http://chatgpt.dhexx.cn/article/ZTd6x3R2.shtml

相关文章

vs快捷键与vs自定义快捷键

文章目录 :star: 主题:VS快捷键1.常用的默认快捷键2.自定义快捷键2.1 添加快捷键2.2 移除快捷键2.3 重置快捷键,恢复默认 :bookmark: 小结 ⭐️ 主题:VS快捷键 📍 来自:中南林业科技大学软件协会学术部:谢…

vs注释与反注释快捷键

使用VS C语言编译器的快捷注释按键: 选中部分注释: Ctrl KD (按住Ctrl然后先按K再按D) 注释前: 注释后: 反注释: Ctrl KU (按住Ctrl然后先按K再按U) 操作完就恢复了…

VS(visual studio)注释快捷键及自定义设置

注释: CtrlKC 取消注释: CtrlKU 【工具】→【选项】→【环境】→【键盘】→【搜索注释】 点击【编辑.注释选定内容】→【移除】 输入快捷键,点击【分配】→【确定】 取消注释的自定义快捷键同理设置即可,注释和取消注释不…

Visual Studio Code2022无法使用注释快捷键

用了一个月vscode,使用ctrl/发现注释始终无法使用,最开始一直以为是系统或者版本问题,因为之前机器做过一次修改机器码的操作。 今天尝试解决了一下,发现问题可以通过键盘映射方案进行解决 文件->账户设置或者右上角头像图标 搜…

vs2019注释快捷键设置

vs2019默认的注释快捷键为ctrl+k+c 取消注释快捷键为ctrl+k+u 我们也可以自己设置 当然,也可以设置自己习惯的快捷键

VS中的设置和快捷键

一.相关设置 1.设置主题颜色 【工具】-》【选项】-》【常规】,选择主题颜色为浅色,点击确定。 2.设置背景颜色 【工具】-》【选项】-》【字体和颜色】,项背景颜色那里,点击自定义。 HSB(HSL)&#xff1a…

VS注释快捷键整理

在 Visual Studio IDE 中使用快捷键注释代码,无论是行注释还是块注释,第一步一定是选中要注释的内容(取消注释同样要先选中)! 当然,如果是行注释,不必选取整行,将光标定位到该行即可…

javassh客户端_简单的Java SSH客户端

javassh客户端 可以使用jcabi-ssh在Java中通过几行代码通过SSH执行shell命令: String hello = new Shell.Plain(new SSH("ssh.example.com", 22,"yegor", "-----BEGIN RSA PRIVATE KEY-----...") ).exec("echo Hello, world!"); jca…

Java打造一款SSH客户端,而且已开源

点击上方“Java基基”,选择“设为星标” 做积极的人,而不是积极废人! 源码精品专栏 原创 | Java 2020 超神之路,很肝~中文详细注释的开源项目RPC 框架 Dubbo 源码解析网络应用框架 Netty 源码解析消息中间件 RocketMQ 源码解析数…

最新版本spring框架下载

首先spring的各种好就不说了;主要是最近spring将官网地址www.springsource.org改为了http://spring.io/(新网站设计的比较舒服,这难道是奔商业化的节奏去的吗?!);同时spring将原来比较容易找到的…

用 Java 打造一款 SSH 客户端,这个太强了。。

前言 最近由于项目需求,项目中需要实现一个WebSSH连接终端的功能,由于自己第一次做这类型功能,所以首先上了GitHub找了找有没有现成的轮子可以拿来直接用,当时看到了很多这方面的项目,例如:GateOne、webssh、shellinabox等。 这些项目都可以很好地实现webssh的功能,但…

Java 打造一款 SSH 客户端,已开源~

来源:https://blog.csdn.net/NoCortY/article/details/104772431 前言 最近由于项目需求,项目中需要实现一个WebSSH连接终端的功能,由于自己第一次做这类型功能,所以首先上了GitHub找了找有没有现成的轮子可以拿来直接用&#x…

官网下载最新版本Spring

目录 官网下载步骤官网下载地址 官网下载步骤 官网地址:https://spring.io/projects/spring-framework 1.点击右上角 Git 图标 2. 进入Spring的Git仓库 3. 进入Spring Framework Artifacts后点击"https://repo.spring.io" 4.进入Spring repository&a…

SSH框架整合demo

Struts、Spring、Hibernate整合 一、创建web工程,搭建Struts框架开发环境: 这里只导入了项目中所需要的重要的jar包,以后根据业务要求继续导入相关的包。 步骤1::导入struts框架所需的jar包步骤2:在web.xml中配置stru…

Spring的下载

Spring是一个独立的框架,他不需要依赖于任何Web服务器或容器,既可以在独立的javaSE项目中使用,也可以在JavaEE项目中使用,在使用Spring之前需要获取它的JAR包,下面就是Spring下载的详细过程。 1.使用浏览器访问Spring…

Web SSH 客户端工具

webssh简介 如何在浏览器web页面登录我们的linux机器,这个工具是使用Python开发 官网:https://pypi.org/project/webssh/ webssh这个工具可以干啥?? 在linux机器上安装python环境,并且使用命令pip3 install webssh,…

web版ssh工具

本系统后端使用springboot框架,持久层使用mybatis,jsch实现ssh,sftp连接,前端使用xterm.js,vue,elementplus框架,使用vue3-sfc-loader加载vue文件,无需使用npm包管理器 系统登录 系统注册 登录后主机资源树…

SSH服务详解(七)– SSH 连接 Github

SSH 连接 Github SSH服务详解(一)–Linux SSH 服务器与客户端的安装与启动 SSH服务详解(二)–使用私钥登录 SSH 服务器(免密登录) SSH 服务详解 (三)-- 使用 SSH 代理 SSH 服务详解 (四)-- 本地调用远程主机的命令 SSH 服务详解 (五)-- 远程文件拷贝 SSH 服务详解 (六)--…

Java打造一款SSH客户端,已开源!

最近由于项目需求,项目中需要实现一个WebSSH连接终端的功能,由于自己第一次做这类型功能,所以首先上了GitHub找了找有没有现成的轮子可以拿来直接用,当时看到了很多这方面的项目,例如:GateOne、webssh、she…

SSH框架---Spring官网下载各版本jar包

1:浏览器输入官网地址:http://spring.io/projects 2:点击如图树叶页面按钮。 3:点击如图小猫图片按钮。 4:查找downloading spring artifacts 链接点击。 5:查找Manually downloading Spring distributions 下面的 http://repo.spring.io.链接点击。 6:鼠标…