0

This is a simple operation I am having trouble accomplishing with numpy:

I have two numpy arrays:

import numpy as np
arr1 = np.array([12, 13, 14, 15])
arr2 = np.array([100, 200, 300, 400])

I would like four distinct numpy arrays:

a1 = np.array([12, 13, 14, 15, 100])
a2 = np.array([12, 13, 14, 15, 200])
a3 = np.array([12, 13, 14, 15, 300])
a4 = np.array([12, 13, 14, 15, 400])

What's the most "numpythonic" way to accomplish this?

I could repeat the first array using numpy.tile, e.g.

repeats = np.tile(arr1, len(arr2))

But that's not optimal.

ShanZhengYang
  • 16,511
  • 49
  • 132
  • 234

3 Answers3

2

I would like four distinct numpy arrays:

Are you sure you don't want one array, np.array([a1, a2, a3, a4])?

But that's not optimal.

If optimality is your concern, preallocating results in the fewest copies:

N = len(arr1)
M = len(arr2)
result = np.zeros((M, N + 1)
result[:,:N] = arr1
result[:,N] = arr2

If you really want to be able to write this kind of thing as an expression, you could define:

def build_arr(into, parts):
    for sl, val in parts.items():
        into[sl] = val
    return into

result = build_arr(np.zeros(M, N + 1), {
    np.s_[:,:N]: arr1,
    np.s_[:,N]:  arr2
})
Eric
  • 95,302
  • 53
  • 242
  • 374
1

I would use np.hstack and a generator expression:

a1, a2, a3, a4 = (np.hstack((arr1, v)) for v in arr2)

If you have a variable number of elements in arr2 then you could store the resulting arrays in a list rather than unpacking them to variable names:

arrs = [np.hstack((arr1, v)) for v in arr2]

Dynamically creating variables is almost always a bad idea. If you want a variable number of named arrays then I suggest you store them in a dict or some other named Python structure. You could use a dict comprehension:

named_arrs = {'a%i' % (i + 1): np.hstack((arr1, v)) for i, v in enumerate(arr2)}
Community
  • 1
  • 1
ali_m
  • 71,714
  • 23
  • 223
  • 298
  • `a1, a2, a3, a4 ` What if I don't know a priori the number of arrays which should be generated? One would have to use the length of `arr2` – ShanZhengYang Oct 26 '16 at 01:16
  • @ShanZhengYang: Do you really want to create a dynamic number of variable names? That's a _really_ bad idea – Eric Oct 26 '16 at 01:17
  • 1
    *"I would like four distinct numpy arrays"*. You could easily collect the subarrays in a list if you don't want to unpack them to separate variable names, e.g. `arrs = [np.hstack((arr1, v)) for v in arr2]`. – ali_m Oct 26 '16 at 01:19
  • @ali_m "I would like four distinct numpy arrays"---yeah, I'm sorry---it's annoying when OPs do this. I should have given the above as an example first. – ShanZhengYang Oct 26 '16 at 01:20
  • So which one do you want? Four separate arrays or one array with four rows? – ali_m Oct 26 '16 at 01:22
  • @ali_m four separate array, whereby "four" is whatever the length of `arr2` (e.g. if it was `np.array([100, 200, 300, 400, 500, 600])`, there would be 6 arrays) – ShanZhengYang Oct 26 '16 at 01:31
1

I rather like the use of tile:

In [1684]: np.tile(arr1,[arr2.shape[0],1])
Out[1684]: 
array([[12, 13, 14, 15],
       [12, 13, 14, 15],
       [12, 13, 14, 15],
       [12, 13, 14, 15]])
In [1685]: np.concatenate((np.tile(arr1,[arr2.shape[0],1]),arr2[:,None]),axis=1)
Out[1685]: 
array([[ 12,  13,  14,  15, 100],
       [ 12,  13,  14,  15, 200],
       [ 12,  13,  14,  15, 300],
       [ 12,  13,  14,  15, 400]])

Such a 2d array is handy in itself. But it can be split into arrays:

In [1686]: np.split(_,arr2.shape[0])
Out[1686]: 
[array([[ 12,  13,  14,  15, 100]]),
 array([[ 12,  13,  14,  15, 200]]),
 array([[ 12,  13,  14,  15, 300]]),
 array([[ 12,  13,  14,  15, 400]])]

And if you really need separate names for those arrays, unpack the list:

In [1687]: a1,a2,a3,a4=_
In [1688]: a1
Out[1688]: array([[ 12,  13,  14,  15, 100]])
hpaulj
  • 221,503
  • 14
  • 230
  • 353