[SciPy-User] Dense 3d array as base, sparse 3d as exponent - how to compute do efficiently?
Thu Nov 25 07:35:43 CST 2010
I am trying to compute the the following as fast as possible:
seq_lik = scipy.prod(scipy.prod(T ** C, 1), 1)
T is a m * m 2d array - a transition matrix where each row sums to 1.
C is a n_seq * m * m 3d array of type int - a "transition count" array with
less than 5% nnz. Some C[i,:,:] contain only zeros.
To sum it up, the operation calculates the likelihood seq_lik[i] of a
sequence "i" among n_seq sequences by taking the product of elements in T **
Given, that C is very sparse I figured it is a waste to evaluate for all the
0 expontents. My program spends about 95% of its time at this line.
Scipy.sparse came to mind but there are no 3d sparse arrays and **/pow have
not been implemented. The best I could come up with for now was a solution
where I reshaped the 3d array into a 2d, used scipy.sparse and only
operated on non-zero elements. See here: http://codepad.org/AiAZoioo (also
see script attached to bottom of this post). This gives a speed-up of about
6 times compared to dense, where I assumed 5% nnz. However, if I check
what's been reported in a decade-old paper, a lot more should be possible on
a personal computer.
When it comes to performance, is there something to be gained by
implementing the discussed operation in a C/Cython extension?
Somewhat related, I sometimes get the impression that with SciPy I spend
more time figuring out how I can make clever use of ndarray manipulation
techniques such as dot and tensordot to avoid for-loops than it may (!) take
to just write down all the loops and compile them into a C extension.
Bearing in mind that not all ndarray manipulation functionality is
available/makes sense for sparse matrices, what do you recommend: step up
lin-alg mojo and use SciPy or write an extension? (... granted, there's
potenital for a different kind of head-ache in that).
Thank you in advance, any clues are appreciated - otherwise I try my luck on
Script (just needs scipy):
if __name__ == '__main__':
zero_frac = 0.95
T = scipy.rand(400) # does not sum to one but whatever
C = (scipy.rand(100000,400) > zero_frac).astype(scipy.int16)
C_sparse = scipy.sparse.coo_matrix(C)
sp_coords = C_sparse.nonzero()
sp_data = C_sparse.data
start_time = time.time()
lik_dense = scipy.prod(T ** C, 1)
print('Time dense: %f,' % (time.time() - start_time))
start_time = time.time()
log_results = scipy.log(T[sp_coords] ** sp_data);
lik_sparse = scipy.exp(scipy.sparse.csr_matrix((log_results, sp_coords),
print('Time sparse: %f,' % (time.time() - start_time))
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the SciPy-User