-4

I am looking at the following function:

# Initialize a network
def initialize_network(n_inputs, n_hidden, n_outputs):
    network = list()
    hidden_layer = [{'weights':[random() for i in range(n_inputs + 1)]} for i in range(n_hidden)]
    network.append(hidden_layer)
    output_layer = [{'weights':[random() for i in range(n_hidden + 1)]} for i in range(n_outputs)]
    network.append(output_layer)
    return network

However, I am particularly stuck on the [{'weights':[random() for i in range(n_inputs + 1)]} for i in range(n_hidden)] line. I am trying to recreate that single line into a function:

def make_weights(n_inputs, n_hidden):
    # for i in range(n_inputs + 1):
        # make a random number?
    # for i in range(n_hidden):
        # make a random number?
    # return array of random numbers?

However, I don't quite understand what that single line is doing. It is looping through the number of inputs + 1 times, and creating a random number? And then is doing the same for the number of hidden inputs?

I am seeking an explanation of that single line, and helping to map that one line into a much cleaner function.

Resources used so far:

halfer
  • 19,471
  • 17
  • 87
  • 173
artemis
  • 5,690
  • 10
  • 36
  • 75
  • 1
    `[random() for i in range(n_inputs + 1)]` creates a list of `n_inputs + 1` random elements (each generated independently of the other), and `[{'weights':[...]} for i in range(n_hidden)]` creates a list of `n_hidden` dictionaries, where each dictionary consists of a single key `'weights'`, associated to a list of `n_inputs + 1` randomly generated elements. – Right leg Apr 23 '19 at 13:25

2 Answers2

3

In general, the following two are equivalent:

result = [obj for sub in iterable for obj in sub]

# and

result = []
for sub in interable:
    for obj in sub:
        result.append(obj)

Accordingly, your make_weights function could be defined as follows:

def make_weights(n_inputs, n_hidden):
    result = []
    for i in range(n_hidden):
        weights = {'weights': []}
        for j in range(n_inputs + 1):
            weights['weights'].append(random())

        result.append(weights)
gmds
  • 17,927
  • 4
  • 26
  • 51
  • 1
    This produces the same results as running the single line function. And, I appreciate the explanation. Thank you! – artemis Apr 23 '19 at 13:45
  • @JerryM. You're welcome! Also, I actually find comprehensions in general more readable; it's just that this one is poorly structured. – gmds Apr 23 '19 at 13:47
2

An equivalent for loop might be as follows,

results = []
for i in range(n_hidden):
        weights = {'weights': []}
        for j in range(n_inputs + 1):
            weights['weights'].append(random())
        result.append(weights)
Devesh Kumar Singh
  • 19,767
  • 5
  • 18
  • 37
  • You don't need `dct` any more. – gmds Apr 23 '19 at 13:29
  • Updated, my bad! – Devesh Kumar Singh Apr 23 '19 at 13:29
  • You're not using any `_` – Right leg Apr 23 '19 at 13:32
  • Updated, my bad! – Devesh Kumar Singh Apr 23 '19 at 13:39
  • @DeveshKumarSingh thank you very much, this worked! I ultimately selected the other answer due to it being posted first + explanation, but this indeed solves the problem. Thank you. – artemis Apr 23 '19 at 14:13
  • You're using twice the same variable name `_`. The underscore character has nothing special in Python, it's just so often used as a wildcard or a discard name that by convention, we understand that it means `ignore this variable`. However, it is a regular variable, and should be treated as such. In this case, I'd call the two loop variables `_i` and `_j`, so as to keep the `ignore this` meaning, but also make it readable. – Right leg Apr 23 '19 at 14:46