Help on return type(?)

Martin A. Brown martin at linux-ip.net
Sat Jan 9 22:10:42 EST 2016


Hello there,

>> def make_cov(cov_type, n_comp, n_fea):
>>     mincv = 0.1
>>     rand = np.random.random
>>     return {
>>         'spherical': (mincv + mincv * np.dot(rand((n_components, 1)),
>>                                              np.ones((1, n_features)))) **
>>                                              2,
>>         'tied': (make_spd_matrix(n_features)
>>                  + mincv * np.eye(n_features)),
>>         'diag': (mincv + mincv * rand((n_components, n_features))) ** 2,
>>         'full': np.array([(make_spd_matrix(n_features)
>>                            + mincv * np.eye(n_features))
>>                           for x in range(n_components)])
>>     }[cov_type]
>> 
>> Specifically, could you explain the meaning of
>> 
>> {
>> ...    }[cov_type]
>> 
>> to me?
>
>It is a dictionary lookup. { ... } sets up a dictionary with keys
>
>    'spherical'
>    'tied'
>    'diag'
>    'full'
>
>then { ... }[cov_type] extracts one of the values depending on 
>whether cov_type is 'spherical', 'tied', 'diag', or 'full'.

You will see that Steven has answered your question.  I will add to 
his answer.

Your original function could be improved many ways, but especially 
in terms of readability.  Here's how I might go at improving the 
readability, without understanding anything about the actual 
computation.
  
  def make_cov_spherical(mincv, n_components, n_features):
      return (mincv + mincv * np.dot(np.random.random((n_components, 1)), np.ones((1, n_features)))) ** 2
 
  def make_cov_diag(mincv, n_components, n_features):
      return (mincv + mincv * np.random.random((n_components, n_features))) ** 2
 
  def make_cov_tied(mincv, n_components, n_features):
      return make_spd_matrix(n_features) + mincv * np.eye(n_features)
 
  def make_cov_full(mincv, n_components, n_features):
      return np.array([(make_spd_matrix(n_features) + mincv * np.eye(n_features)) for x in range(n_components)])
 
  def make_cov(cov_type, n_comp, n_fea):
      mincv = 0.1
      dispatch_table = {
          'spherical': make_cov_spherical,
          'tied': make_cov_tied,
          'diag': make_cov_diag,
          'full': make_cov_full,
      }
      func = dispatch_table[cov_type]
      return func(mincv, n_comp, n_fea)

Some thoughts (and reaction to the prior code):

  * Your originally posted code referred to n_comp and n_fea in the 
    signature, but then used n_components and n_features in the 
    processing lines.  Did this function ever work?

  * Individual functions are easier to read and understand.  I would
    find it easier to write testing code (and docstrings) for these 
    functions, also.

  * The assignment of a name (rand = np.random.random) can make 
    sense, but I think it simply shows that the original function 
    was trying to do too many things and was hoping to save space
    with this shorter name for the np.random.random.  Not bad, but I 
    dropped it anyway for the sake of clarity.

  * Each of the above functions (which I copied nearly verbatim) 
    could probably now be broken into one or two lines.  That would 
    make the computation even clearer.

  * There may be a better way to make a function dispatch table than 
    the one I demonstrate above, but I think it makes the point 
    nicely.

  * If you break the individual computations into functions, then 
    you only run the specific computation when it's needed.  In the 
    original example, all of the computations were run AND then, one 
    of the results was selected.  It may not matter, since computers 
    are so fast, but, practicing basic parsimony can avoid little 
    obvious performance hazards like this.

  * In short, longer, but much much clearer.

Good luck,

-Martin

-- 
Martin A. Brown
http://linux-ip.net/



More information about the Python-list mailing list