原文:http://www.pythontab.com/html/2014/pythonhexinbiancheng_0522/788.html

推荐系统中经常需要处理类似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以二进制字符串形式存储,直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
'''
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__(self):
        pass
  
    '''
    从文件中生成matrix
    考虑到dbm读写的性能不如内存,我们做了一些缓存,每1000W次批量写入一次
    考虑到字符串拼接性能不太好,我们直接用StringIO来做拼接
    '''
    def from_file(self, fp, sep = 't'):
        cnt = 0
        cache = {}
        for in fp:
            if 10000000 == cnt:
                self._flush(cache)
                cnt = 0
                cache = {}
            i, j, v = [float(i) for in l.split(sep)]
  
            ik = ('i%d' % i)
            ib = struct.pack('if', j, v)
            jk = ('j%d' % j)
            jb = struct.pack('if', i, v)
  
            try:
                cache[ik].write(ib)
            except:
                cache[ik] = StringIO()
                cache[ik].write(ib)
  
            try:
                cache[jk].write(jb)
            except:
                cache[jk] = StringIO()
                cache[jk].write(jb)
  
            cnt += 1
            self._nums += 1
  
        self._flush(cache)
        return self._nums
  
    def _flush(self, cache):
        for k,v in cache.items():
            v.seek(0)
            = v.read()
            try:
                self._data[k] += s
            except:
                self._data[k] = s
  
if __name__ == '__main__':
    db = bsddb.btopen(None, cachesize = 268435456)
    data = DictMatrix(db)
    data.from_file(open('/path/to/log.txt''r'), ',')

测试4500W条rating数据(整形,整型,浮点格式),922MB文本文件导入,采用内存dict储存的话,12分钟构建完毕,消耗内存1.2G,采用示例代码中的bdb存储,20分钟构建完毕,占用内存300~400MB左右,比cachesize大不了多少,数据读取测试:

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

消耗1.4788秒,大概读取一条数据1.5ms。

采用类Dict来存储数据的另一个好处是你可以随便用内存Dict或者其他任何形式的DBM,甚至传说中的Tokyo Cabinet….

好的,码完收工。

一种比较省内存的稀疏矩阵Python存储方案相关推荐

  1. tinyFlash:一种超轻量级的嵌入式单片机flash KV 数据存储方案

    tinyFlash 一种超轻量级的flash KV数据存储方案 Github 地址:https://github.com/ospanic/tinyFlash 设计原理 本方案采用两个扇区轮流使用的方法 ...

  2. 带你了解两种线性规划的方法:稀疏矩阵存储和预处理

    摘要:本文为大家带来线性规划的稀疏矩阵存储和数据预处理. 本文分享自华为云社区<线性规划--稀疏矩阵>,原文作者:Bale10 . 随着AI时代的发展,线性规划问题的规模越来越大是一种必然 ...

  3. python idle 常规命令_Python的3种运行方式:命令行窗口、Python解释器、IDLE的实现

    1 命令行窗口 开始栏搜索command,打开命令提示符,即为命令行窗口. 运行一个Python程序,需要输入:Python + 程序地址 + 程序名.py 如图: 2 Python解释器 开始栏搜索 ...

  4. python内存池机制,python基础—12python内存管理机制

    一.内存池机制 1.对象池 面试题目: python内存管理机制是什么? 1). 由于python中万物皆对象,内存管理机制就是对象的存储问题,Python会分 配一块内存空间去存储对象. 2) 对于 ...

  5. 精华阅读第 13 期 |常见的八种导致 APP 内存泄漏的问题 1

    2019独角兽企业重金招聘Python工程师标准>>> 本期是移动开发精英俱乐部的第13期文章,都是以技术为主,所以这里就不过多的进行赘述了,我们直接看干货内容吧!本文系ITOM管理 ...

  6. python3 urllib 内存泄露_【专家专栏】张昊 | 从urllib2的内存泄露看python的GC

    原标题:[专家专栏]张昊 | 从urllib2的内存泄露看python的GC 惨案回顾 领导:小张啊,安排你个任务,团队需要你做一个功能,提取一批页面上的数据,有问题吗? 小张:当然没问题,您啥时候要 ...

  7. python稀疏矩阵的存储与表示

    参考链接: https://blog.csdn.net/bitcarmanlee/article/details/52668477 https://blog.csdn.net/wangjian1204 ...

  8. android内存池,两种常见的内存管理方法:堆和内存池

    描述 本文导读 在程序运行过程中,可能产生一些数据,例如,串口接收的数据,ADC采集的数据.若需将数据存储在内存中,以便进一步运算.处理,则应为其分配合适的内存空间,数据处理完毕后,再释放相应的内存空 ...

  9. python之路 mysql 博客园_教为学:Python学习之路(二):MySQLdb的几种安装方式,以及用Python测试连接MySql...

    教为学:Python学习之路(二):MySQLdb的几种安装方式,以及用Python测试连接MySql Easy_install安装MySQLdb 很简单,以至于我不晓得该怎么说.一句话. sodu ...

最新文章

  1. 牛客练习赛64 - B Dis2(树,基础图论)
  2. [置顶] 给Fedora修改默认的软件下载源
  3. 学python能赚什么外卖-用python模拟美团外卖骑手推送请求
  4. SpringMVC获取参数的几种方式
  5. InputStream 、 InputStreamReader 、 BufferedReader区别
  6. html怎么建立段落,HTML 段落
  7. kali NETCAT NC的使用
  8. 不同性能极限下的服务器,探求极限性能 服务器测试之ScienceMark
  9. python游戏源码回合制游戏_python game源码下载
  10. python中不可以用来表示字符串_在Python中,不可以用来表示字符串的符号是____________。...
  11. 从头推导与实现 BP 网络
  12. 1.Ubuntu Server下搭建LAMP环境
  13. pytorch项目源码理解
  14. 只需要几行代码就可以轻松实现OCR图片转文字
  15. 软件测试52讲-测试先行:测试驱动开发(TDD)
  16. Iptables-外网地址及端口映射到内网地址及端口
  17. 3dmax 2014加载panda3d插件失败
  18. 数据加密-国密SM2对数据进行加解密
  19. 塔多漫画一直维护服务器,塔多漫画
  20. c语言*p1 什么意思,p1什么意思_p1,意思_词汇大全意思全集

热门文章

  1. php怎么查帮助,需要有关MySQL查询和PHP的帮助
  2. linux 脚本自动编制工具,全自动工具链编译脚本
  3. python条件表达式有哪几个_python条件表达式:多项分支,双向分支
  4. java query类是什么类_java – 从包生成QueryDsl Q类
  5. html 文字倒映效果,HTML图片CSS滤镜—倒影效果
  6. android h5 禁止缩放,vue h5移动端禁止缩放代码
  7. javaee校园信息服务器,基于javaEE服务器 学生考勤管理系统的设计与实现开题报告...
  8. 11月数据库排行:PostgreSQL起飞、三巨头分数持续低迷
  9. K8S面试大通关!赶紧收藏!
  10. 每日一皮:程序员的神逻辑...