파이썬이 희소 행렬을 사용하여 메모리 절약 실례

2946 단어
추천 시스템에서 유사한user 를 처리해야 합니다id, item_id,rating 같은 데이터는 사실 수학의 희소 행렬이다. scipy에서sparse 모듈을 제공하여 이 문제를 해결하지만scipy.sparse는 많은 문제점을 가지고 있습니다.
1、데이터를 동시에 지원할 수 없음 [i,...]데이터 [..., j], 데이터 [i, j]를 빠르게 슬라이스하기;2. 데이터가 메모리에 저장되기 때문에 대량의 데이터 처리를 잘 지원하지 못한다.
데이터 지원[i,...]데이터 [..., j]의 빠른 슬라이딩은 i 또는 j의 데이터를 집중적으로 저장해야 한다.또한 대량의 데이터를 저장하기 위해 데이터의 일부분을 하드디스크에 놓고 메모리로 버퍼를 만들어야 한다.이곳의 해결 방안은 비교적 간단하다. 한 종류의dict로 데이터를 저장하고 특정한 i(예를 들어 9527)에 대한 데이터는 dict['i9527']에 저장한다. 같은 것은 특정한 j(예를 들어 3306)에 대한 모든 데이터는 dict['j3306']에 저장하고 데이터를 꺼내야 한다[9527,...]할 때 dict['i9527']만 꺼내면 된다. dict['i9527']는 원래 하나의 dict 대상이고 특정한 j에 대응하는 값을 저장한다. 메모리 공간을 절약하기 위해 우리는 이 dict를 2진 문자열 형식으로 저장하고 코드를 직접 올린다.
 
   
  

'''
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을 마음대로 사용할 수 있다는 것이다.
됐어, 다 쌓고 끝내자.

좋은 웹페이지 즐겨찾기