2

I have seen this, but it doesn't quite answer my question.

I have an array:

x = np.array([0, 1, 2])

I want this:

y = np.array([[0,1], [0,2], [1,0], [1,2], [2,0], [2,1]])

That is, I want to take each value (let's call it i) of the array x and create x.shape[0]-1 new arrays with all of the other values of x, excluding i.

Essentially y contains the indices of a 3x3 matrix without any diagonal elements.

I have a feeling there's an easy, pythonic way of doing this that's just not coming to me.

StatsSorceress
  • 3,019
  • 7
  • 41
  • 82

2 Answers2

1

Approach #1 : One approach would be -

x[np.argwhere(~np.eye(len(x),dtype=bool))]

Approach #2 : In two steps -

r = np.arange(len(x))
out = x[np.argwhere(r[:,None]!=r)]

Approach #3 : For performance, it might be better to create those pairwise coordinates and then mask. To get the paiwise coordinates, let's use cartesian_product_transpose, like so -

r = np.arange(len(x))
mask = r[:,None]!=r
out = cartesian_product_transpose(x,x)[mask.ravel()]

Approach #4 : Another with np.broadcast_to that avoids making copies until masking, again meant as a performance measure -

n = len(x)
r = np.arange(n)
mask = r[:,None]!=r
c0 = np.broadcast_to(x[:,None], (n, n))[mask]
c1 = np.broadcast_to(x, (n,n))[mask]
out = np.column_stack((c0,c1))

Runtime test -

In [382]: x = np.random.randint(0,9,(1000))

# @tom10's soln
In [392]: %timeit list(itertools.permutations(x, 2))
10 loops, best of 3: 62 ms per loop

In [383]: %%timeit
     ...: x[np.argwhere(~np.eye(len(x),dtype=bool))]
100 loops, best of 3: 11.4 ms per loop

In [384]: %%timeit
     ...: r = np.arange(len(x))
     ...: out = x[np.argwhere(r[:,None]!=r)]
100 loops, best of 3: 12.9 ms per loop

In [388]: %%timeit
     ...: r = np.arange(len(x))
     ...: mask = r[:,None]!=r
     ...: out = cartesian_product_transpose(x,x)[mask.ravel()]
100 loops, best of 3: 16.5 ms per loop

In [389]: %%timeit
     ...: n = len(x)
     ...: r = np.arange(n)
     ...: mask = r[:,None]!=r
     ...: c0 = np.broadcast_to(x[:,None], (n, n))[mask]
     ...: c1 = np.broadcast_to(x, (n,n))[mask]
     ...: out = np.column_stack((c0,c1))
100 loops, best of 3: 6.72 ms per loop
Divakar
  • 218,885
  • 19
  • 262
  • 358
0

This is a case where, unless you really need to speed, etc, of numpy, pure Python gives a cleaner solution:

import itertools

y = itertools.permutations([0, 1, 2], 2)

# [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
tom10
  • 67,082
  • 10
  • 127
  • 137