-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,824
  • 17
  • 99
  • 186
artemis
  • 6,857
  • 11
  • 46
  • 99
  • 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
  • 19,325
  • 4
  • 32
  • 58
  • 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
  • 20,259
  • 5
  • 21
  • 40
  • 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