2013-10-11 2 views
2

필자는 scipy 스파 스 벡터가 포함 된 n 개의 문서를 MongoDB에 저장하고 피클 개체로 저장하고 처음에는 scipy.sparse.lil로 만듭니다. 벡터는 모두 같은 크기, 예를 들어 p x 1입니다.mongodb를 파이썬 드문 드문 한 행렬로 만드는 방법, 빨리 만드는 방법?

내가해야 할 일은 이러한 모든 벡터를 파이썬으로 된 희소 한 n x p 매트릭스에 넣는 것입니다. =

다음
class MyClass(Document): 

    vector_text = StringField() 

    @property 
    def vector(self): 
     return cPickle.loads(self.vector_text) 

는 4700 및 P N =와, 내가 지금 뭘하는지의 67 : I는 각 피클 벡터를로드하여 속성을 정의 된 mongoengine를 사용하고

items = MyClass.objects() 
M = items[0].vector 
for item in items[1:]: 
    to_add = item.vector 
    M = scipy.sparse.hstack((M, to_add)) 

로딩 부분 (즉 n 번 속성 호출) 약 1.3s 걸립니다. 스태킹 부분은 약 2.7 초. 미래에 n이 심각하게 증가 할 것이므로 (아마도 수십만 개 이상) 나는 이것이 최적이 아니라고 느낍니다. 모든 것을 빠르게 할 수있는 아이디어가 있습니까? "적재"또는 "적재"만 고정하는 방법을 알고 있다면 나는 그것을 듣게되어 기쁘다. 예를 들어, 아마도 mongoDB에 전체 행렬을 저장하는 것이 해결책일까요? 감사 !

+0

제이미 (Jaime)와 알렉산더 (Alexander)의 답변을 모두 사용하여 프로그램이 정말 빨라졌습니다. 프로그램이 수천 번 같은 방법으로 실행될 때 100 배 더 빨리 말하면, 그것을 말할 필요가 :)). 놀라운 도움, 감사합니다. – cenna75

답변

3

먼저, 사용자가 원하는 것은가 아닌 hstack을 사용해야한다는 것입니다. 어떤 경우 든 스파 스 형식의 선택은 성능 문제의 일부입니다. 다음을 시도하십시오.

n, p = 4700, 67 
csr_vecs = [sps.rand(1, p, density=0.5, format='csr') for j in xrange(n)] 
lil_vecs = [vec.tolil() for vec in csr_vecs] 

%timeit sps.vstack(csr_vecs, format='csr') 
1 loops, best of 3: 722 ms per loop 

%timeit sps.vstack(lil_vecs, format='lil') 
1 loops, best of 3: 1.34 s per loop 

따라서 CSR에 대한 swithcing에서 이미 2 배 향상되었습니다. 또한, scipy.sparse의 스태킹 기능은 매우 최적화 된 것처럼 보이지 않습니다. 확실히 스파 스 벡터가 아닙니다. ,

%timeit csr_stack(csr_vecs) 
100 loops, best of 3: 11.7 ms per loop 

%timeit lil_stack(lil_vecs) 
10 loops, best of 3: 37.6 ms per loop 

%timeit lil_stack(lil_vecs).tolil() 
10 loops, best of 3: 53.6 ms per loop 

: 그럼

>>> np.allclose(sps.vstack(csr_vecs).A, csr_stack(csr_vecs).A) 
True 
>>> np.allclose(csr_stack(csr_vecs).A, lil_stack(lil_vecs).A) 
True 

을 빠르게 실질적이다

def csr_stack(vectors): 
    data = np.concatenate([vec.data for vec in vectors]) 
    indices = np.concatenate([vec.indices for vec in vectors]) 
    indptr = np.cumsum([0] + [vec.nnz for vec in vectors]) 
    return sps.csr_matrix((data, indices, indptr), shape=(len(vectors), 
                  vectors[0].shape[1])) 
import itertools as it 
def lil_stack(vectors): 
    indptr = np.cumsum([0] + [vec.nnz for vec in vectors]) 
    data = np.fromiter(it.chain(*(vec.data[0] for vec in vectors)), 
         dtype=vectors[0].dtype, count=indptr[-1]) 
    indices = np.fromiter(it.chain(*(vec.rows[0] for vec in vectors)), 
          dtype=np.intp, count=indptr[-1]) 
    return sps.csr_matrix((data, indices, indptr), shape=(len(vectors), 
                  vectors[0].shape[1])) 

의미가 있습니다 : 다음 두 가지 기능은 CSR 희소 행렬을 반환, CSR 또는 LIL 벡터의 목록을 쌓아 CSR로 전환하면 성능을 100 배 이상 향상시킬 수 있습니다. LIL을 고수하면 성능 향상은 약 30 배에 불과합니다. 결합 된 매트릭스에서 CSR을 사용할 수 있다면 LIL을 주장 할 때보 다 덜합니다.

+1

정말로 인상적입니다, 나는 확실히 전환하고 있습니다! – cenna75

1

내 생각에, 당신은 벡터를 저장하기 위해 본질적으로 BSON 배열의 파이썬리스트 표현 인 ListField을 사용해야합니다. 이러한 상황에서는 매번 다시 실행할 필요가 없습니다.

class MyClass(Document): 

     vector = ListField() 



    items = MyClass.objects() 
    M = items[0].vector 

내가 그 솔루션에서 볼 수있는 유일한 문제는, 당신은 스파 스 벡터 유형을 scipy하는 파이썬 목록을 변환해야한다는 것입니다,하지만 난 그게 더 빨리해야한다, 생각합니다.

+0

흥미 롭습니다. vector가 numpy 배열이나리스트이면 매력처럼 작동합니다. 스파 스 벡터를 저장하는 것이 더 어려워 보입니다. 그러나 당신이 말했듯이, 나는 언제든지 그것을 나중에 변환 할 수 있습니다. 그건 첫 걸음이야, 속도를 올릴거야, 고마워! – cenna75

관련 문제