Python使用稀疏矩阵节省内存实例

作者:junjie 时间:2021-03-31 17:58:19 

推荐系统中经常需要处理类似user_id, item_id, rating这样的数据,其实就是数学里面的稀疏矩阵,scipy中提供了sparse模块来解决这个问题,但scipy.sparse有很多问题不太合用:

1、不能很好的同时支持data[i, ...]、data[..., j]、data[i, j]快速切片;
2、由于数据保存在内存中,不能很好的支持海量数据处理。

要支持data[i, ...]、data[..., j]的快速切片,需要i或者j的数据集中存储;同时,为了保存海量的数据,也需要把数据的一部分放在硬盘上,用内存做buffer。这里的解决方案比较简单,用一个类Dict的东西来存储数据,对于某个i(比如9527),它的数据保存在dict['i9527']里面,同样的,对于某个j(比如3306),它的全部数据保存在dict['j3306']里面,需要取出data[9527, ...]的时候,只要取出dict['i9527']即可,dict['i9527']原本是一个dict对象,储存某个j对应的值,为了节省内存空间,我们把这个dict以二进制字符串形式存储,直接上代码:

'''
Sparse Matrix
'''
import struct
import numpy as np
import bsddb
from cStringIO import StringIO
 
class DictMatrix():
    def __init__(self, container = {}, dft = 0.0):
        self._data  = container
        self._dft   = dft
        self._nums  = 0
 
    def __setitem__(self, index, value):
        try:
            i, j = index
        except:
            raise IndexError('invalid index')
 
        ik = ('i%d' % i)
        # 为了节省内存,我们把j, value打包成字二进制字符串
        ib = struct.pack('if', j, value)
        jk = ('j%d' % j)
        jb = struct.pack('if', i, value)
 
        try:
            self._data[ik] += ib
        except:
            self._data[ik] = ib
        try:
            self._data[jk] += jb
        except:
            self._data[jk] = jb
        self._nums += 1
 
    def __getitem__(self, index):
        try:
            i, j = index
        except:
            raise IndexError('invalid index')
 
        if (isinstance(i, int)):
            ik = ('i%d' % i)
            if not self._data.has_key(ik): return self._dft
            ret = dict(np.fromstring(self._data[ik], dtype = 'i4,f4'))
            if (isinstance(j, int)): return ret.get(j, self._dft)
 
        if (isinstance(j, int)):
            jk = ('j%d' % j)
            if not self._data.has_key(jk): return self._dft
            ret = dict(np.fromstring(self._data[jk], dtype = 'i4,f4'))
 
        return ret
 
    def __len__(self):
        return self._nums
 
    def __iter__(


测试代码:


import timeit
timeit.Timer('foo = __main__.data[9527, ...]', 'import __main__').timeit(number = 1000)

消耗1.4788秒,大概读取一条数据1.5ms。
采用类Dict来存储数据的另一个好处是你可以随便用内存Dict或者其他任何形式的DBM,甚至传说中的Tokyo Cabinet….

好了,码完收工。

标签:Python,稀疏矩阵
0
投稿

猜你喜欢

  • Python drop()删除行列的操作方法

    2022-10-27 17:12:41
  • Python之Pygame的Draw绘图

    2022-11-29 18:51:18
  • Python使用MD5加密算法对字符串进行加密操作示例

    2021-06-23 16:30:25
  • js对象基础实例分析

    2023-09-03 12:07:56
  • Python+Django搭建自己的blog网站

    2022-02-24 16:32:45
  • Oracle存储过程之数据库中获取数据实例

    2009-03-04 10:57:00
  • ASP获取当前页面URL地址(带参数)的方法

    2010-01-14 19:40:00
  • Python实现TCP协议下的端口映射功能的脚本程序示例

    2021-07-26 13:59:01
  • Python中的jquery PyQuery库使用小结

    2023-05-27 11:08:15
  • Python文件的应用之序列化与反序列化详解

    2021-06-19 22:20:45
  • 详解如何使用Pytorch进行多卡训练

    2023-08-02 06:43:29
  • python3 flask实现文件上传功能

    2022-11-19 18:42:10
  • 关于jupyter lab安装及导入tensorflow找不到模块的问题

    2023-05-13 18:03:32
  • Python递归及尾递归优化操作实例分析

    2022-06-17 16:09:10
  • Python使用pylab库实现绘制直方图功能示例

    2022-12-07 04:48:56
  • 获取Django项目的全部url方法详解

    2022-09-08 23:06:27
  • Python 程序员必须掌握的日志记录

    2021-11-05 06:17:20
  • 实用301转向到另一域名相应页面的asp代码

    2011-04-18 10:42:00
  • JavaScript中Infinity(无穷数)的使用和注意事项

    2023-08-21 00:59:13
  • JavaScript 全半角转换

    2010-02-04 17:14:00
  • asp之家 网络编程 m.aspxhome.com