前言

sklearn调用独热编码函数encoder.fit_transform()返回的是scipy.sparse._csr.csr_matrix类型。
torch的tensor也是一种matrix,各中差别让我感觉混乱。今天梳理一下,网上看到前辈有很好的帖子,翻译转载如下:

简介

稀疏矩阵是大多数元素的值为0的矩阵。如果Number of Non-Zero (NNZ)非零元素个数的占比小于0.5,则矩阵是稀疏的。

存储所有0元素是低效的,因此我们假设未声明的元素都是0。利用这种方法,稀疏矩阵可以比相应的密集矩阵表示方法执行更快的操作,并且使用更少的内存,这在处理数据科学中的大数据集时尤为重要。

今天,我们将研究 SciPy sparse package提供的所有不同实现。这个实现是模仿 np.Matrix 而不是 np.ndarray,因此仅限于2维数组,并且np.matrix里的像 A* B这样的矩阵乘法而不是orch.Tensor里的逐元素相乘

Matrix multiplication(矩阵乘法)和element-wise multiplication(逐元素乘法)是两种不同的矩阵运算。

Matrix multiplication是两个矩阵相乘得到一个新的矩阵,其中第一个矩阵的列数必须等于第二个矩阵的行数。矩阵乘法可以表示为 C = A B C = AB C=AB,其中 A A A和 B B B是两个矩阵, C C C是乘积矩阵。在矩阵乘法中,每个元素的计算都涉及到两个矩阵中的多个元素的加权和,因此这种运算通常会涉及到高复杂度的计算。【np.matrx使用的就是矩阵乘法】

Element-wise multiplication是两个矩阵中的对应元素相乘得到一个新的矩阵,其中两个矩阵必须具有相同的形状。元素乘积可以表示为 C = A ⊙ B C = A \odot B C=A⊙B,其中 A A A和 B B B是两个矩阵, C C C是元素乘积矩阵。在逐元素乘法中,矩阵中的每个元素都是独立计算的,因此计算的复杂度要比矩阵乘法低得多。【而torch.Tensor使用的就是逐元素相乘】

n [0]: from scipy import sparseIn [1]: import numpy as npIn [2]: spmatrix = sparse.random(10, 10)In [3]: spmatrix
Out[3]:
<10x10 sparse matrix of type '<class 'numpy.float64'>'with 1 stored elements in COOrdinate format>In [4]: spmatrix.nnz / np.product(spmatrix.shape)  # sparsity
Out[4]: 0.01

构造矩阵

不同的稀疏矩阵格式各有优缺点。一个好的起点是寻找对构造这些矩阵有效的格式。一般来说你都是从其中一种格式开始,然后转换成另一种格式用于计算。

坐标矩阵(Coordinate Matrix)

要理解的最简单的稀疏格式可能是 COO 格式(Coordinate Matrix)。此变体使用三个子数组来存储元素值及其坐标位置。

In [5]: row = [1, 3, 0, 2, 4]In [6]: col = [1, 4, 2, 3, 3]In [7]: data = [2, 5, 9, 1, 6]In [8]: coo = sparse.coo_matrix((data, (row, col)), shape=(6, 7))In [9]: print(coo)  # coordinate-value format
# (1, 1)        2
# (3, 4)        5
# (0, 2)        9
# (2, 3)        1
# (4, 3)        6In [10]: coo.todense()  # coo.toarray() for ndarray instead
Out[10]:
matrix([[0, 0, 9, 0, 0, 0, 0],[0, 2, 0, 0, 0, 0, 0],[0, 0, 0, 1, 0, 0, 0],[0, 0, 0, 0, 5, 0, 0],[0, 0, 0, 6, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0]])

随着矩阵大小的增加,节省的内存消耗是相当可观的。在稀疏结构中管理数据的成本是固定的,这与密集矩阵的情况不同。由于需要管理子阵列而产生的开销可以忽略不计,大数据场景下,这种稀疏结构使其成为某些数据集的一个很好的选择。

In [11]: def memory_usage(coo):...:    # data memory and overhead memory...:    coo_mem = (sum(obj.nbytes for obj in [coo.data, coo.row, coo.col])...:               + sum(obj.__sizeof__() for obj in [coo, coo.data, coo.row, coo.col]))...:    print(f'Sparse: {coo_mem}')...:    mtrx = coo.todense()...:    mtrx_mem = mtx.nbytes + mtrx.__sizeof__()...:    print(f'Dense: {mtrx_mem}')In [12]: memory_usage(coo)
# Sparse: 480
# Dense: 448In [13]: coo.resize(100, 100)In [14]: memory_usage(coo)
# Sparse: 480
# Dense: 80112

键值字典矩阵(Dictionary of Keys Matrix)

Dictionary Of Keys (DOK)与 COO 非常相似,只是它的子类 dict 将坐标数据信息存储为键-值对。由于它使用哈希表作为存储,因此在任何给定位置标识值都需要固定的查找时间。如果需要内置字典的功能,可以使用这种格式,但是要注意,哈希表比数组占用更多的内存。

In [15]: dok = sparse.dok_matrix((10, 10))In [16]: dok[(3, 7)] = 42  # store value 42 at coordinate (3, 7)In [17]: dok[(9, 5)]  # zero elements are accessible
Out[17]: 0.0In [18]: dok.keys() | dok.transpose().keys()  # union of key views
Out[18]: {(3, 7), (7, 3)}In [19]: isinstance(dok, dict)
Out[19]: True

注意: 使用从 dict 继承的方法时要小心潜在的问题; 它们并不总是表现良好。

# 例如In [20]: out_of_bounds = (999, 999)  # 定义一个元组,表示矩阵中一个超出范围的索引In [21]: dok[out_of_bounds] = 1  # 此行代码按预期会引发IndexError,因为out_of_bounds是一个超出范围的索引IndexError: Index out of bounds. # 正常执行了In [22]: dok.setdefault(out_of_bounds)  # 该行代码被静默地忽略了,没有抛出异常...In [23]: dok.toarray()  # ...直到这里。该行代码才引发ValueError异常,因为矩阵的行索引超出了矩阵维度的范围。ValueError: row index exceeds matrix dimensions # dok.toarray()返回的异常In [24]: dok.pop(out_of_bounds)  # 通过删除超出范围的点来解决问题In [25]: sparse.dok_matrix.fromkeys([..., ..., ...])  # 一整个无语了就,作者这里原文用了一个don't let me started,就是我都抱怨烦了这个问题。这行代码存在问题,它会提醒我缺少一个必需的参数'arg1'TypeError: __init__() missing 1 required positional argument: 'arg1' # 缺少一个必需的参数'arg1'的报错

链表矩阵(Linked List Matrix)

插入数据的最灵活的格式是使用LInked List (LIL)链表矩阵。可以通过 NumPy 的索引和切片语法来设置数据,从而快速填充矩阵。在作者看来,LIL 是从头构造稀疏矩阵的最酷的稀疏格式。
LIL 将信息存储在 LIL.rows 中,其中每个列表表示一个行索引,列表中的元素匹配列。在并行数组lil.data中,存储 NNZ 值。但是与其他稀疏格式不同的是,这些子数组不能显式地传递给构造函数; LIL 矩阵必须从空状态或从现有的密集或稀疏矩阵中生成。下面是用于构建 LIL 矩阵的各种技术的示例。


In [26]: lil = sparse.lil_matrix((6, 5), dtype=int)  # 创建一个6x5的稀疏矩阵,元素数据类型为int,格式是lil,In [27]: lil[(0, -1)] = -1  # 给一个单独的点复制In [28]: lil[3, (0, 4)] = [-2] * 2  # 设置两个点In [29]: lil.setdiag(8, k=0)  # 设置主对角线上的元素为8In [30]: lil[:, 2] = np.arange(lil.shape[0]).reshape(-1, 1) + 1  # 设置整个第3列In [31]: lil.toarray()  # 将稀疏矩阵转换为密集矩阵输出
Out[31]:
array([[ 8,  0,  1,  0, -1],[ 0,  8,  2,  0,  0],[ 0,  0,  3,  0,  0],[-2,  0,  4,  8, -2],[ 0,  0,  5,  0,  8],[ 0,  0,  6,  0,  0]])

那么缺点是什么?它利用了底层的 (jagged arrays)锯齿数组(又译:不规则数组),这需要 np.dtype (object)。这比矩形数(rectangular array)组消耗更多的内存,所以如果数据足够大,您可能会被迫使用 COO 而不是 LIL。简而言之,IL 矩阵虽然存在一些缺点,但仍然是一个非常棒的选择!

In [32]: lil.rows  # 查看 LIL 矩阵的行索引Out[32]:
array([list([0, 2, 4]), list([1, 2]), list([2]), list([0, 2, 3, 4]),list([2, 4]), list([2])], dtype=object)In [33]: lil.data[:, np.newaxis]  # 展示jagged锯齿结构/不规则结构Out[33]:
array([[list([8, 1, -1])],[list([8, 2])],[list([3])],[list([-2, 4, 8, -2])],[list([5, 8])],[list([6])]], dtype=object)

顺便说一句,链表矩阵LIL是一个用词不当,因为它不使用链表幕后!LIL 实际上使用了 Python 的 List,它是一个动态数组,所以不管文档中怎么说,它实际上应该被称为 List Matrix List。(错过了给它命名为 LOL 的机会…)

In [34]: sparse.lil.__doc__  # 读取lili模块的文档Out[34]: 'LInked List sparse matrix class\n' # 我是一个链表稀疏矩阵唷(其实才不是嘞!)

中断

CSR,CSC的介绍见python中稀疏矩阵的常用表示COO LIL CSR CSC【下篇】

python中稀疏矩阵的常用表示COO LIL CSR CSC【上篇】相关推荐

  1. (numpy)python中Array的常用函数

    python中Array的常用函数 1.unique 2.sum 3.max 1.unique a = np.random.randint(10, size=20).reshape(4,5) a &g ...

  2. Python中random模块常用函数/方法(2)——random.random(),random.randint()和random.uniform()

    1.random.random():生成一个0到1的随机符点数: 0 <= n < 1.0 语法:random.random() #生成一个0~1之间的随机浮点数 print(" ...

  3. python中字典的常用操作命令及注意事项

    目录 1. 使用update()合并字典 2. 使用del删除具有指定键的元素 3. 使用clear清除所有元素 4. 使用in判断是否存在 5. 使用[key]获取元素 6. 使用keys()获取所 ...

  4. python中socket模块常用吗_python中socket模块详解

    socket模块简介 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket.socket通常被叫做"套接字",用于描述IP地址和端口,是一个通信 ...

  5. Python中集合的常用操作

    一.集合的介绍 1.定义:集合是无序的,集合中的元素是唯一的,集合一般用于元组或者列表中的元素去重. 2.特性:集合的目的是将不同的值存放在一起,不同的集合间用来做关系运算,无须纠结于集合中的单个值. ...

  6. python1000个常用代码-介绍Python中几个常用的类方法

    内置方法 说明 __init__(self,...) 初始化对象,在创建新对象时调用 __del__(self) 释放对象,在对象被删除之前调用 __new__(cls,*args,**kwd) 实例 ...

  7. python中字典的常用函数_python中得字典和常用函数总结

    字典是python中一种常见得数据类型,用{}表示,并且以键值对得形式存放数据. dic={},其中得key键值是不可变得,类型可以是字符串.其中,列表,字典不可以作为键,键值是不可变得.字符串,元组 ...

  8. python中定义函数常用关键字_Python 中定义函数的关键字是 _________________ 。_学小易找答案...

    [其它]实验4-串和数组-实验任务书.docx [填空题]表达式 'abc' in ['abcdefg'] 的值为______________. [填空题]已知 x = range(1,4) 和 y ...

  9. Python学习总结(10) python中数据的常用操作之切片和迭代

    1.切片 (slice ) 符号[ : ] 和Matlab中取任意长的数据方式完全一样! (1) 切片的由来: 取一个list或tuple的部分元素是非常常见的操作.比如,一个list如下: > ...

最新文章

  1. 强大的 IDEA 代码生成
  2. LFCS 系列第二讲:如何安装和使用纯文本编辑器 vi/vim
  3. 英语计算机单词mp3,计算机英语会话(MP3+中英字幕) 第1期:计算机系统(1)
  4. centos6 rsync+inotify 数据同步
  5. objective-c 2.0的字面量Literals
  6. 各种java生成word解决方案的优缺点对比
  7. Linux文件系统构成
  8. 并发编程-基础概念介绍
  9. Jfinal的七牛云存储插件:qiniuPlugin for jfinal.
  10. USB之基本协议和数据波形1
  11. android7.1.2安装包,APK.1文件安装器下载-APK.1安装:微信APK安装器下载1.7 安卓版-西西软件下载...
  12. python3多线程进度条_python,多线程_Python:在多线程中使用进度条(progressbar)碰到的问题,python,多线程 - phpStudy...
  13. 蓝字冲销是什么意思_会计记账,贷方红字,贷方蓝字什么意思
  14. 电脑无法进入bios
  15. 最好听的男孩、女孩名字
  16. 北科计算机研究生导师推荐,北京科技大学计算机与通信工程学院-【喜报】我院班晓娟老师荣获第三届“研师亦友——我最喜爱的导师”称号...
  17. 关键字搜索aliexpress商品API接口(速卖通关键词搜索商品接口)
  18. 初中计算机基础考试试题及答案,计算机基础考试试题及答案(三)
  19. 推荐多样性重排算法之MMR
  20. 【ES6闯关】Promise堪比原生的自定义封装then、catch、resolve、reject...

热门文章

  1. html能控制佳能相机吗,佳能EOS R可选镜头多吗 是否支持佳能单反镜头
  2. python爬虫逆向|某手网页滑块逆向分析
  3. 唐宇迪博士实战代码教学视频课程全集,带你一起数据分析、深度学习
  4. 马云高考数学仅1分?!数学的重要性绝对不止跟考试有关
  5. Logger日志级别说明及设置方法
  6. C++学习(一三六)磅和字号的关系
  7. 去除字符串首尾空格【shell】
  8. 简记nodejs下载及安装(windows)
  9. visio是什么软件,能不能免费使用
  10. WebLogic 部署Web应用