当前位置:
首页 > Python基础教程 >
-
一种比较省内存的稀疏矩阵Python存储方案
推荐系统中经常需要处理类似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 l in fp: if 10000000 = = cnt: self ._flush(cache) cnt = 0 cache = {} i, j, v = [ float (i) for i 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 ) s = 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' ), ',' ) |
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比
一款纯 JS 实现的轻量化图片编辑器
关于开发 VS Code 插件遇到的 workbench.scm.
前端设计模式——观察者模式
前端设计模式——中介者模式
创建型-原型模式