I'm not sure I completely follow exactly what processing you're doing to your data. The comments in the code suggest it's meant to be a matrix multiplication, the description you've provided above it suggests it's a cartesian product, but your code looks like does the sum of (flattened) [outer products](http://docs.scipy.org/doc/numpy/reference/generated/numpy.outer.html#numpy.outer) of corresponding rows. I'll proceed on the assumption that your code is doing the right thing, but hopefully you can clarify. There are two general pieces of advice that apply here: 1. Use appropriate data structures. When you're doing linear algebra, that means [numpy][1] arrays. Numpy is a dedicated, LA library that has heavily optimised routines for things like dot products, so you don't need to roll your own. Numpy arrays will also use quite a bit less memory than Python lists. 2. Separation of concerns. You're mingling code to parse your data with code to process it once it is parsed. Instead, parse everything into the appropriate data structures *first*, and *then* do the processing. These things together will make your code easier to follow, more maintainable, and often both faster and shorter. So, start by looking at your core data structure: exp_mat = [line.rstrip().split('\t') for line in ccle] This is a list of lists of strings. For most of the rows, you don't seem to care about column 0 at all. Column 1 contains strings identifying the row, and corresponding to keys in your dictionary `pat_mRNA`. The rest of it is numeric data, currently stored as strings. A better data structure for this would be something more like your `pat_mRNA`: a dictionary mapping the string identifier to a vector of floats (except I would use a numpy array instead of a list to represent the vector). Since the strings are apparently names of genes, I assume they have a standard format and a maximum (or even fixed) length? If that is the case, you could use a numpy record array - essentially a matrix-like structure where the columns can have different types - which may make things a little easier depending if you need to do anything else with this data. It also seems to contain 'header' rows - you only keep one of those around, so presumably you only expect one to be in there. So, in line with point (2) above, let's parse this file into a dictionary mapping strings to np arrays. exp_mat = {} for line in ccle: row = line.rstrip().split('\t') if row[0] == 'Name': ccle_exp_head = row elif row[1] in pat_mRNA: exp_mat[row[1]] = np.array([float(f) for f in row[2:]]) Note that I have modified your conditions a little, since yours seemed slightly off. The `else` branch of your condition effectively says "if the zeroth column is "name" *or* the first column isn't a match, it must be a header" - I've changed it so that instead, an appropriate value in the zeroth column is a header, and a non-matching first column on is ignored. As an aside, as a matter of commonly-accepted Python style (and in accordance with PEP 8), I have placed all of the code for each branch of the `if` in indented blocks, even if it is only one line. At most, you should only put it immediately after the `:` if there is only one branch to the `if` (no `else` or `elif`s), and even then, consider an indented block anyway. I would change `pat_mRNA` to be a matching data structure to this. Fortunately, this is a lot easier - add an appropriate `np.array` call to the code that current builds it, so that each list becomes an array just before it goes in the dict. Once you've done that, you can use numpy features to do your product. As written, your entire strange product becomes this: dot_prod_total = sum(np.outer(exp_mat[key], pat_mRNA[key]).flat for key in exp_mat) Which should be quite a lot faster than trying to do it by list comprehensions, and *may* use multithreading depending on how numpy is compiled. [1]: http://www.numpy.org/