3

I have a set of 9 different arrays, all n by n in size. I need to combine them element wise in order to yield a specific array.

Ex.: Given a set of 9 equally sized arrays:

a1 = np.array([[11, 12, 13], [14, 15, 16], [17, 18, 19]])
a2 = np.array([[21, 22, 23], [24, 25, 26], [27, 28, 29]])
a3 = np.array([[31, 32, 33], [34, 35, 36], [37, 38, 39]])

a4 = np.array([[41, 42, 43], [44, 45, 46], [47, 48, 49]])
a5 = np.array([[51, 52, 53], [54, 55, 56], [57, 58, 59]])
a6 = np.array([[61, 62, 63], [64, 65, 66], [67, 68, 69]])

a7 = np.array([[71, 72, 73], [74, 75, 76], [77, 78, 79]])
a8 = np.array([[81, 82, 83], [84, 85, 86], [87, 88, 89]])
a9 = np.array([[91, 92, 93], [94, 95, 96], [97, 98, 99]])

The desired result would be

b = np.array([[11, 21, 31, 12, 22, 32, 13, 23, 33],
              [41, 51, 61, 42, 52, 62, 43, 53, 63],
              [71, 81, 91, 72, 82, 92, 73, 83, 94],
              [14, 24, 34, 15, 25, 35, 16, 26, 36],
              [44, 54, 64, 45, 55, 65, 46, 56, 66],
              [74, 84, 94, 75, 85, 95, 76, 86, 96],
              [17, 27, 37, 18, 28, 38, 19, 29, 39],
              [47, 57, 67, 48, 58, 68, 49, 59, 69],
              [77, 87, 97, 78, 88, 98, 79, 89, 99]]) 

So the first row of array b is made up of the first rows of a1, a2, and a3, combined element wise.

The second row of array b is made up of the first rows of a4, a5, and a6, combined element wise.

The third row is made up of the first rows of a7, a8, and a9, combined element wise.

And then the same pattern continues for the rest of the rows in a1-a9.

This needs to work for any size of the a1-a9 arrays, as in the arrays being n by n in size. I've tried tinkering with np.concatenate, zip, and np.einsum, all with no luck.

dumbouser
  • 33
  • 4
  • Welcome to SO. This isn't a discussion forum or tutorial. Please take the [tour] and take the time to read [ask] and the other links found on that page. Questions asking for code are discouraged. – wwii Sep 11 '19 at 18:03

3 Answers3

5

EDIT: Generalized to different array sized and number of arrays:

import numpy as np

def combine_arrays(arrays):
    arrays = np.asarray(arrays)
    n, p, q = arrays.shape
    s = int(round(np.sqrt(n)))
    arrays = arrays.reshape(s, -1, p, q)
    return arrays.transpose(2, 0, 3, 1).reshape(s * p, -1)

a1 = np.array([[11, 12, 13], [14, 15, 16], [17, 18, 19]])
a2 = np.array([[21, 22, 23], [24, 25, 26], [27, 28, 29]])
a3 = np.array([[31, 32, 33], [34, 35, 36], [37, 38, 39]])

a4 = np.array([[41, 42, 43], [44, 45, 46], [47, 48, 49]])
a5 = np.array([[51, 52, 53], [54, 55, 56], [57, 58, 59]])
a6 = np.array([[61, 62, 63], [64, 65, 66], [67, 68, 69]])

a7 = np.array([[71, 72, 73], [74, 75, 76], [77, 78, 79]])
a8 = np.array([[81, 82, 83], [84, 85, 86], [87, 88, 89]])
a9 = np.array([[91, 92, 93], [94, 95, 96], [97, 98, 99]])

print(combine_arrays([a1, a2, a3, a4, a5, a6, a7, a8, a9]))
# [[11 21 31 12 22 32 13 23 33]
#  [41 51 61 42 52 62 43 53 63]
#  [71 81 91 72 82 92 73 83 93]
#  [14 24 34 15 25 35 16 26 36]
#  [44 54 64 45 55 65 46 56 66]
#  [74 84 94 75 85 95 76 86 96]
#  [17 27 37 18 28 38 19 29 39]
#  [47 57 67 48 58 68 49 59 69]
#  [77 87 97 78 88 98 79 89 99]]

a1 = np.array([[11, 12], [14, 15]])
a2 = np.array([[21, 22], [24, 25]])
a3 = np.array([[31, 32], [34, 35]])
a4 = np.array([[41, 42], [44, 45]])

print(combine_arrays([a1, a2, a3, a4]))
# [[11 21 12 22]
#  [31 41 32 42]
#  [14 24 15 25]
#  [34 44 35 45]]

You can do that by reshaping and transposing:

import numpy as np

a1 = np.array([[11, 12, 13], [14, 15, 16], [17, 18, 19]])
a2 = np.array([[21, 22, 23], [24, 25, 26], [27, 28, 29]])
a3 = np.array([[31, 32, 33], [34, 35, 36], [37, 38, 39]])

a4 = np.array([[41, 42, 43], [44, 45, 46], [47, 48, 49]])
a5 = np.array([[51, 52, 53], [54, 55, 56], [57, 58, 59]])
a6 = np.array([[61, 62, 63], [64, 65, 66], [67, 68, 69]])

a7 = np.array([[71, 72, 73], [74, 75, 76], [77, 78, 79]])
a8 = np.array([[81, 82, 83], [84, 85, 86], [87, 88, 89]])
a9 = np.array([[91, 92, 93], [94, 95, 96], [97, 98, 99]])

a = np.stack([a1, a2, a3, a4, a5, a6, a7, a8, a9])
a = a.reshape(3, 3, 3, 3).transpose(2, 0, 3, 1).reshape(9, 9)
print(a)
# [[11 21 31 12 22 32 13 23 33]
#  [41 51 61 42 52 62 43 53 63]
#  [71 81 91 72 82 92 73 83 93]
#  [14 24 34 15 25 35 16 26 36]
#  [44 54 64 45 55 65 46 56 66]
#  [74 84 94 75 85 95 76 86 96]
#  [17 27 37 18 28 38 19 29 39]
#  [47 57 67 48 58 68 49 59 69]
#  [77 87 97 78 88 98 79 89 99]]
jdehesa
  • 58,456
  • 7
  • 77
  • 121
  • 1
    Starting off with `np.array([..])` than `np.stack` seems slightly better on perf. – Divakar Sep 11 '19 at 17:36
  • 1
    sorry but this answer is not generalized "for any size of the a1-a9 arrays" as asked in the question... Your dimensions should be calculated prior to the reshaping, not imposed. – jeannej Sep 11 '19 at 17:44
  • 1
    @jeannej Thanks, didn't read that part, added general solution now. – jdehesa Sep 11 '19 at 18:01
1

Try this one:

>>> import numpy as np
>>> np.hstack([
       np.vstack([a1.ravel(), a2.ravel(), a3.ravel()]).T.reshape(3, -1),
       np.vstack([a4.ravel(), a5.ravel(), a6.ravel()]).T.reshape(3, -1),
       np.vstack([a7.ravel(), a8.ravel(), a9.ravel()]).T.reshape(3, -1)
    ]).reshape(9,9)
array([[11, 21, 31, 12, 22, 32, 13, 23, 33],
       [41, 51, 61, 42, 52, 62, 43, 53, 63],
       [71, 81, 91, 72, 82, 92, 73, 83, 93],
       [14, 24, 34, 15, 25, 35, 16, 26, 36],
       [44, 54, 64, 45, 55, 65, 46, 56, 66],
       [74, 84, 94, 75, 85, 95, 76, 86, 96],
       [17, 27, 37, 18, 28, 38, 19, 29, 39],
       [47, 57, 67, 48, 58, 68, 49, 59, 69],
       [77, 87, 97, 78, 88, 98, 79, 89, 99]])
Grzegorz Skibinski
  • 12,624
  • 2
  • 11
  • 34
  • sorry but this answer is not generalized "for any size of the a1-a9 arrays" as asked in the question... Your dimensions should be calculated prior to the reshaping, not imposed. – jeannej Sep 11 '19 at 17:44
  • why the use of `ravel` method above `flatten` method? – jeannej Sep 11 '19 at 19:10
  • Because it's faster, and better suits this problem ;) https://stackoverflow.com/a/28930580/11610186 – Grzegorz Skibinski Sep 11 '19 at 19:36
  • 1
    Thanks for the link, though I fail to see why this "better suits this problem" : you don't know if the `ai` are used afterwards, which in this case could be a problem if they are over-written... Though it's true `ravel` is faster (I got 1.2e-3 sec for `ravel` and 3.9e-3 sec for `flatten` with `timeit.repeat`), this doesn't appear safe without knowing the rest of the code. Maybe just add a note in your answer, stating that the `ai` could be modified by the process, and if wished otherwise you should use `flatten` method instead? – jeannej Sep 11 '19 at 20:01
  • No, it won't - if you would be modifying ```ravel```-ed array then maybe. But in this case you won't e.g. https://pastebin.com/0h5Wvgv9 That's why "better suits this problem". Especially IF you assign the result to another variable. – Grzegorz Skibinski Sep 11 '19 at 20:14
1

As for time speed (used timeit.repeat on 10000 iterations to get that), from the best to the worst:

  1. @jdehesa np.stack + a.reshape(3, 3, 3, 3).transpose(2, 0, 3, 1).reshape(9, 9) : 9.9e-2 s
  2. @Grzegorz Skibinski vstack + hstack + reshape : 1.6e-1 s
jeannej
  • 1,135
  • 1
  • 9
  • 23
  • This doesn't seem to give the right answer to me (array starts with `[[11 12 13 21 22 ...`). – jdehesa Sep 11 '19 at 18:05
  • @jdehesa oooops you're right, my bad I went a like too fast here, I will edit my post (though now that you edited your answer I like it the most ;) ) – jeannej Sep 11 '19 at 19:11