Skip to main content
Use pandas instead of directly numpy
Source Link
lvc
  • 1.2k
  • 6
  • 13
  1. 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.

  2. Use appropriate libraries and data structures. When you're doing linear algebra, that means numpy arrays. Numpy is a dedicated, LA library that has heavily optimised routines for things like dotvarious matrix products, so you don't need to roll your own. Numpy arrays will also use quite a bit less memory than Python lists.

  3. Separation of concerns. You're mingling code to parse your data However, what you're working with code to process it onceis labelled data (and some of it is parsed. Insteadlabelled in two dimensions), parse everything intowhich means the appropriatebest data structuresstructure is probably a firstpandas dataframe - it's basically like your dict of strings to lists in pat_mRNA, but much more optimised, and then do the processingfully compatible with numpy's matrix manipulations.

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 labels, 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 containcontains 'header' rows - you only keep one of those around, so presumably you only expect one to be in there. SoI'm guessing that is column labels, which a DataFrame lets you include directly in line with pointthe same data structure.

The only trick parsing this into a DataFrame is that it is a little easier (2and, apparently, more efficient) aboveto swap the columns and rows from how you have them currently. That will affect how it prints, let'sand which methods you call to relabel things, but not much else. This is how I would parse this fileit into a dictionary mapping strings to np arrays.DataFrame:

exp_matdata = {}pd.DataFrame()
headers = []
for line in ccle: 
    row = line.rstrip().split('\t')
    if row[0] == 'Name':
         ccle_exp_headheaders = row
    elif row[1] in pat_mRNA:
        exp_mat[row[1]]data[row[1]] = np.array([float(f) for f in row[2:]]) 

if headers:
   data.index = headers

I've maintained a temporary 'headers' list, because your code is currently robust against those appearing anywhere in the file. A better way to maintain that robustness would be if you know - or, preferably, can parse from your file before now - how many variables you have data for. Then you could do away with that headers list and do this:

data = pd.DataFrame(index=range(nvars))
for line in ccle: 
    row = line.rstrip().split('\t')
    if row[0] == 'Name':
         data.index = row
    elif row[1] in pat_mRNA:
        data[row[1]] = [float(f) for f in row[2:]]

In either case, I am assuming that you have one header for each variable. If that's a bad assumption, you may need to adjust this code.

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 elifs), and even then, consider an indented block anyway.

I would change pat_mRNA to also be a matching data structure to thisDataFrame. FortunatelyYou could change how you currently build it, this is a lot easier - add an appropriateor you could just pass the whole dictionary you have at the moment into nppd.arrayDataFrame() 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 productLA work. As written, your entire strange product becomes this:

dot_prod_total = sum(np.outer(exp_mat[key]data[key], pat_mRNA[key]).flat for key in exp_matdata)
  1. Use appropriate data structures. When you're doing linear algebra, that means numpy 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.

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:]])

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 elifs), 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)
  1. 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.

  2. Use appropriate libraries and data structures. When you're doing linear algebra, that means numpy. Numpy is a dedicated, LA library that has heavily optimised routines for things like various matrix products, so you don't need to roll your own. Numpy arrays will also use quite a bit less memory than Python lists. However, what you're working with is labelled data (and some of it is labelled in two dimensions), which means the best data structure is probably a pandas dataframe - it's basically like your dict of strings to lists in pat_mRNA, but much more optimised, and fully compatible with numpy's matrix manipulations.

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 row labels, and corresponding to keys in your dictionary pat_mRNA. The rest of it is numeric data, currently stored as strings. It also contains 'header' rows - you only keep one of those around, so presumably you only expect one to be in there. I'm guessing that is column labels, which a DataFrame lets you include directly in the same data structure.

The only trick parsing this into a DataFrame is that it is a little easier (and, apparently, more efficient) to swap the columns and rows from how you have them currently. That will affect how it prints, and which methods you call to relabel things, but not much else. This is how I would parse it into a DataFrame:

data = pd.DataFrame()
headers = []
for line in ccle: 
    row = line.rstrip().split('\t')
    if row[0] == 'Name':
         headers = row
    elif row[1] in pat_mRNA:
        data[row[1]] = [float(f) for f in row[2:]] 

if headers:
   data.index = headers

I've maintained a temporary 'headers' list, because your code is currently robust against those appearing anywhere in the file. A better way to maintain that robustness would be if you know - or, preferably, can parse from your file before now - how many variables you have data for. Then you could do away with that headers list and do this:

data = pd.DataFrame(index=range(nvars))
for line in ccle: 
    row = line.rstrip().split('\t')
    if row[0] == 'Name':
         data.index = row
    elif row[1] in pat_mRNA:
        data[row[1]] = [float(f) for f in row[2:]]

In either case, I am assuming that you have one header for each variable. If that's a bad assumption, you may need to adjust this code.

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 elifs), and even then, consider an indented block anyway.

I would change pat_mRNA to also be a DataFrame. You could change how you currently build it, or you could just pass the whole dictionary you have at the moment into pd.DataFrame().

Once you've done that, you can use numpy to do your LA work. As written, your entire strange product becomes this:

dot_prod_total = sum(np.outer(data[key], pat_mRNA[key]).flat for key in data)
added 17 characters in body
Source Link
lvc
  • 1.2k
  • 6
  • 13

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 of corresponding rows. I'll proceed on the assumption that your code is doing the right thing, but hopefully you can clarify.

dot_prod_total = sum(np.outer(exp_mat[key], pat_mRNA[key]).flat for key in exp_mat)

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 outer products of corresponding rows. I'll proceed on the assumption that your code is doing the right thing, but hopefully you can clarify.

dot_prod_total = sum(np.outer(exp_mat[key], pat_mRNA[key]) for key in exp_mat)

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 of corresponding rows. I'll proceed on the assumption that your code is doing the right thing, but hopefully you can clarify.

dot_prod_total = sum(np.outer(exp_mat[key], pat_mRNA[key]).flat for key in exp_mat)
added 133 characters in body
Source Link
lvc
  • 1.2k
  • 6
  • 13

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 laterdepending if you need to do anything else with this data.

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, which may make things a little easier later.

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.

Source Link
lvc
  • 1.2k
  • 6
  • 13
Loading