2

I have four numpy arrays, and example given below:

a1=np.array([[-24.4925, 295.77  ],
             [-24.4925, 295.77  ],
             [-14.3925, 295.77  ],
             [-16.4125, 295.77  ],
             [-43.6825, 295.77  ],
             [-22.4725, 295.77  ]])

a2=np.array([[-26.0075, 309.39  ],
             [-24.9975, 309.39  ],
             [-14.8975, 309.39  ],
             [-17.9275, 309.39  ],
             [-46.2075, 309.39  ],
             [-23.9875, 309.39  ]])

a3=np.array([[-25.5025, 310.265 ],
             [-25.5025, 310.265 ],
             [-15.4025, 310.265 ],
             [-17.4225, 310.265 ],
             [-45.7025, 310.265 ],
             [-24.4925, 310.265 ]])

a4=np.array([[-27.0175, 326.895 ],
             [-27.0175, 326.895 ],
             [-15.9075, 326.895 ],
             [-18.9375, 326.895 ],
             [-48.2275, 326.895 ],
             [-24.9975, 326.895 ]])

I want to make all possible combinations between arrays and at the same time concatenate, for example:

array[-24.4925, 295.77, -26.0075, 309.39, -25.5025, 310.265, -27.0175, 326.895]

and

array[-24.4925, 295.77, -26.0075, 309.39, -25.5025, 310.265, -27.0175, 326.895]

that is [a1[0],a2[0],a3[0],a4[0]], [a1[0],a2[0],a3[0],a4[1]] and so on

what is the fastest method to it other than to loop over the four arrays?!

2 Answers2

2

Well, there isn't a faster way than looping, but there is a clean way where you don't have to write the loops:

import numpy as np
import itertools

a1=np.array([[-24.4925, 295.77  ],
             [-24.4925, 295.77  ],
             [-14.3925, 295.77  ],
             [-16.4125, 295.77  ],
             [-43.6825, 295.77  ],
             [-22.4725, 295.77  ]])

a2=np.array([[-26.0075, 309.39  ],
             [-24.9975, 309.39  ],
             [-14.8975, 309.39  ],
             [-17.9275, 309.39  ],
             [-46.2075, 309.39  ],
             [-23.9875, 309.39  ]])

a3=np.array([[-25.5025, 310.265 ],
             [-25.5025, 310.265 ],
             [-15.4025, 310.265 ],
             [-17.4225, 310.265 ],
             [-45.7025, 310.265 ],
             [-24.4925, 310.265 ]])

a4=np.array([[-27.0175, 326.895 ],
             [-27.0175, 326.895 ],
             [-15.9075, 326.895 ],
             [-18.9375, 326.895 ],
             [-48.2275, 326.895 ],
             [-24.9975, 326.895 ]])

arrays = [a1, a2, a3, a4]

for pieces in itertools.product(*arrays):
    combined = np.concatenate(pieces, axis = 0)
    print(combined)

The standard library itertools module (https://docs.python.org/3/library/itertools.html) provides a variety of tools for producing products, combinations, permutations, etc. of iterables. Since numpy array happens to be iterable (iterating over the first index), we can use itertools to grab slices from each of the array and then use numpy to combine them.

Josh Karpel
  • 2,110
  • 2
  • 10
  • 21
1

Here is a numpy solution, based on the Cartesian product implementation from here.

arr = np.stack([a1, a2, a3, a4])

print(arr.shape) # (4, 6, 2)
n, m, k = arr.shape

# from https://stackoverflow.com/questions/11144513/cartesian-product-of-x-and-y-array-points-into-single-array-of-2d-points
def cartesian_product(*arrays):
    la = len(arrays)
    dtype = np.result_type(*arrays)
    arr = np.empty([len(a) for a in arrays] + [la], dtype=dtype)
    for i, a in enumerate(np.ix_(*arrays)):
        arr[...,i] = a
    return arr.reshape(-1, la)

inds = cartesian_product(*([np.arange(m)] * n))
res = np.take_along_axis(arr, inds.T[...,None], 1).swapaxes(0,1).reshape(-1, n*k)

print(res[0])
# [-24.4925 295.77   -26.0075 309.39   -25.5025 310.265  -27.0175 326.895 ]

In this example, the inds array looks as follows:

print(inds[:10])
# [[0 0 0 0]
#  [0 0 0 1]
#  [0 0 0 2]
#  [0 0 0 3]
#  [0 0 0 4]
#  [0 0 0 5]
#  [0 0 1 0]
#  [0 0 1 1]
#  [0 0 1 2]
#  [0 0 1 3]]

We can then use np.take_along_axis to select appropriate elements for each combination.

hilberts_drinking_problem
  • 11,322
  • 3
  • 22
  • 51