2

I have a numpy array of shape [12, 8, 5, 5]. I want to modify the values of 3rd and 4th dimension for each element.

For e.g.

import numpy as np
x = np.zeros((12, 80, 5, 5))

print(x[0,0,:,:])

Output:

[[ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]

Modify values:

 y = np.ones((5,5))
 x[0,0,:,:] = y
 print(x[0,0,:,:])

Output:

[[ 1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.]]

I can modify for all x[i,j,:,:] using two for loops. But, I was wondering if there is any pythonic way to do it without running two loops. Just curious to know :)

UPDATE

Actual use case:

dict_weights = copy.deepcopy(combined_weights)
for i in range(0, len(combined_weights[each_layer][:, 0, 0, 0])):
    for j in range(0, len(combined_weights[each_layer][0, :, 0, 0])):
          # Extract 5x5
          trans_weight = combined_weights[each_layer][i,j]
          trans_weight = np.fliplr(np.flipud(trans_weight ))
          # Update
          dict_weights[each_layer][i, j] = trans_weight

NOTE: The dimensions i, j of combined_weights can vary. There are around 200 elements in this list with varied i and j dimensions, but 3rd and 4th dimensions are always same (i.e. 5x5).

I just want to know if I can updated the elements combined_weights[:,:,5, 5] with transposed values without running 2 for loops.

Thanks.

blackbug
  • 1,098
  • 3
  • 13
  • 40
  • What do you want to update them with? Probably not just ones? Please give more detail, because it makes a difference here. – Paul Panzer Feb 20 '17 at 13:07
  • I need to transpose the elements of 3rd and 4th - D [i, j, :, : ] and then update the array. – blackbug Feb 20 '17 at 13:19
  • Why not just use `transpose` or `swapaxes`? They'd do it in one line - and no time at all. (These functions just alter the data layout, without moving the actual data, so they are super-cheap) – Paul Panzer Feb 20 '17 at 13:22
  • @blackbug So, use `y.T` to update? – Divakar Feb 20 '17 at 13:23
  • Hey guys, I have updated question with actual use case. I guess my example with 0s and 1s wasnt so clear. Sorry aout that. – blackbug Feb 20 '17 at 13:30
  • 1
    You do not need to loop for that. just do `dict_weights[each_layer]=combined_weights[each_layer][..., ::-1, ::-1]` that also saves you the deepcopy. just initialise `dict_weights` as an empty dict. Or you could even do a dict comprehension and do the entire thing in one line. – Paul Panzer Feb 20 '17 at 13:43
  • @PaulPanzer Sorry about that, we posted at the exact same time :) – Divakar Feb 20 '17 at 13:44
  • @Divakar no prob ;-) Do you think flattening the last two axes would gain anything here? – Paul Panzer Feb 20 '17 at 13:46
  • Thanks guys for your solutions. Thats what I was looking for. I knew numpy shouldnt need loops to do this just didnt know how) @PaulPanzer I am curious about 'dict comprehension and do the entire thing in one line' how can I do this? – blackbug Feb 20 '17 at 13:47
  • 1
    I was assuming that your `each_layer` is something you are looping over. If that's the case you could write `dict_weights = {k: v[..., ::-1, ::-1] for k, v in combined_weights.items()}`. – Paul Panzer Feb 20 '17 at 13:51
  • combined_weights is actually a list of numpy arrays. Thus, i am looping over it and doing operations for each entry in the list and then atht end pairing it as a dictionary. – blackbug Feb 20 '17 at 13:54
  • 1
    So your dictionary keys are just 0, 1, 2, ...? Still works, just replace `combined_weights.items()` with `enumerate(combined_weights)` or, if the keys are something else but you have them in a list called `keys` use `zip(keys, combined_weights)` – Paul Panzer Feb 20 '17 at 13:59
  • Thanks for the suggestions. My dictionary keys are strings and thus as you suggested I will use zip. i was using enumerate on list to get the position in the list and the element as well. Thanks alot! – blackbug Feb 20 '17 at 14:07
  • I tried `dict_weights = {k: v[..., ::-1, ::-1] for k, v in zip(list_layer_names, combined_weights)` where list_layer_name is a list of 200 elements and combined_weights is also of 200 elem. The code gives an error `dict_weights = {k: v[..., ::-1, ::-1] for k, v in zip(list_layer_names, all_weights)} IndexError: too many indices for array` – blackbug Feb 20 '17 at 14:19
  • My bad! i got it correct now :) Thanks again! – blackbug Feb 20 '17 at 14:29

1 Answers1

2

Simply do -

dict_weights[each_layer] = combined_weights[each_layer][...,::-1,::-1]
Divakar
  • 218,885
  • 19
  • 262
  • 358
  • I have a noice question here: how to interpret [...,::-1,::-1]. '...' is usually the complete range – blackbug Feb 20 '17 at 13:57
  • 1
    @blackbug Well I would refer you to [`this post`](http://stackoverflow.com/a/773472/3293881). Exerpt from it that's relevant here : `"Ellipsis (...) is used here to indicate a placeholder for the rest of the array dimensions not specified. "`. Thus, we are using that ellipsis to indicate the first two axes, as we are specifying the last two axes with `::-1` each in that 4D array. – Divakar Feb 20 '17 at 14:01