HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Python Cartesian Product in a constrained dictonary

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
constrainedproductcartesianpythondictonary

Problem

I want to calculate the Cartesian product of n copies of a small list, marker=[0,1,2]. I want to use these Cartesian product tuples as keys in a dictionary. The value per each key is to be a numpy array with n random floats between 0 and 1.

The only twist is that for each key:value pair in the dictionary, if the key has a non-zero number in its index a, I want the corresponding value np.array to have np.nan for the same index.

Below is the function I wrote for that. My question is whether there is a quicker / more efficient way to get the same result.

import itertools
import numpy as np
def create_constrained_dict(n, markers):
    '''
    Create cartesian product of a the same list repeated n times
    It returns a dictionary whose keys are the cartesian products of the
    input lists. The values of the dictionary are numpy arrays of length 'n'.
    If the corresponding dictionary key element for a value is not zero, we replace the value
    with np.nan.
    Belwo is an example:
    So for some key-value pair, NaN's would be lcoated as follows: 
         d={(0,0,1): np.array([0.1234, 0.7543, np.nan]),
            (1,2,1): np.array([np.nan, np.nan, np.nan]),
            (1,0,1): np.array([np.nan, 0.2634, np.nan]),
    } 

    '''
    d = dict()
    for element in itertools.product(*[markers  for i in xrange(n)]):
        d[element] = np.random.uniform(0, 1,n)
        for i in xrange(n):
            if element[i] !=0:
                d[element][i]= np.nan
    return d

rep_num = 3
marker = [0,1,2]
d = create_constrained_dict(rep_num, marker)


The output looks like this:

```
print d
{
(0, 1, 1): array([ 0.84049621, nan, nan]),
(0, 1, 2): array([ 0.17520962, nan, nan]),
(1, 0, 1): array([ nan, 0.96110224, nan]),
(0, 2, 1): array([ 0.10395044, nan, nan]),
(2, 2, 0): array([ nan, nan, 0.60131589]),
(0, 2, 0): array([ 0.64515576, nan, 0.05946614])

Solution

-
Instead of itertools.product(*[markers for i in xrange(n)]) use itertools.product(markers, repeat=n)

-
Instead of creating three random values and replace it with nan use List Comprehensions.

-
dict([(key, value) for key, value in ...]) creates dict object.

-
[bool and [a] or [b]][0] - safer version of bool and a or b - one-linear version of:

if bool:
    a
else:
    b


And final version:

import itertools
import numpy as np

def create_constrained_dict(n, markers):
    d = dict([(element, np.array([(i == 0 and [np.random.uniform(0, 1)] or [np.nan])[0]
                                  for i in element]))
              for element in itertools.product(markers, repeat=n)])
    return d


EDIT

Version without np.array - 2 times faster (thanks @JoeWallis):

import itertools
import numpy as np

def create_constrained_dict(n, markers):
    d = dict([(element, [(i == 0 and [np.random.uniform(0, 1)] or [np.nan])[0]
                         for i in element]))
              for element in itertools.product(markers, repeat=n)])
    return d

Code Snippets

if bool:
    a
else:
    b
import itertools
import numpy as np

def create_constrained_dict(n, markers):
    d = dict([(element, np.array([(i == 0 and [np.random.uniform(0, 1)] or [np.nan])[0]
                                  for i in element]))
              for element in itertools.product(markers, repeat=n)])
    return d
import itertools
import numpy as np

def create_constrained_dict(n, markers):
    d = dict([(element, [(i == 0 and [np.random.uniform(0, 1)] or [np.nan])[0]
                         for i in element]))
              for element in itertools.product(markers, repeat=n)])
    return d

Context

StackExchange Code Review Q#143810, answer score: 4

Revisions (0)

No revisions yet.