74
from numpy import *
def swap_columns(my_array, col1, col2):
    temp = my_array[:,col1]
    my_array[:,col1] = my_array[:,col2]
    my_array[:,col2] = temp

Then

swap_columns(data, 0, 1)

Doesn't work. However, calling the code directly

temp = my_array[:,0]
my_array[:,0] = my_array[:,1]
my_array[:,1] = temp

Does. Why is this happening and how can I fix it? The Error says "IndexError: 0-d arrays can only use a single () or a list of newaxes (and a single ...) as an index", which implies the arguments aren't ints? I already tried converting the cols to int but that didn't solve it.

0

5 Answers 5

133

There are two issues here. The first is that the data you pass to your function apparently isn't a two-dimensional NumPy array -- at least this is what the error message says.

The second issue is that the code does not do what you expect:

my_array = numpy.arange(9).reshape(3, 3)
# array([[0, 1, 2],
#        [3, 4, 5],
#        [6, 7, 8]])
temp = my_array[:, 0]
my_array[:, 0] = my_array[:, 1]
my_array[:, 1] = temp
# array([[1, 1, 2],
#        [4, 4, 5],
#        [7, 7, 8]])

The problem is that Numpy basic slicing does not create copies of the actual data, but rather a view to the same data. To make this work, you either have to copy explicitly

temp = numpy.copy(my_array[:, 0])
my_array[:, 0] = my_array[:, 1]
my_array[:, 1] = temp

or use advanced slicing

my_array[:, [0, 1]] = my_array[:, [1, 0]]
Sign up to request clarification or add additional context in comments.

5 Comments

Advanced slicing does not appear to copy the data either.
@MateenUlhaq Be assured, it does. See the linked documentation, or try it yourself.
It certainly copies the data, but that means that the assignment assigns to a temporary object that is immediately discarded.
@AI0867 Only the advanced slicing on the right-hand side creates a copy. The advanced slicing in assignment-target position does not. You can try the code – it works just fine. (The reason for the different behaviour is that the [] operator in value context is handled by __getitem__(), while assignments with [] are handled by __setitem__(). It never makes sense to assign to a temporary copy, so the __setitem__() implementation for a NumPy array doesn't.)
I stand corrected.
47

I find the following the fastest:

my_array[:, 0], my_array[:, 1] = my_array[:, 1], my_array[:, 0].copy()

Time analysis of:

import numpy as np
my_array = np.arange(900).reshape(30, 30)

is as follows:

%timeit my_array[:, 0], my_array[:, 1] = my_array[:, 1], my_array[:, 0].copy()
The slowest run took 15.05 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 1.72 µs per loop

The advanced slicing times are:

%timeit my_array[:,[0, 1]] = my_array[:,[1, 0]]
The slowest run took 7.38 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 6.9 µs per loop

1 Comment

Upvote for the copy() part, I was missing this in my code.
17

An elegant way to swap the columns in NumPy is analogous to swapping two variables in Python like so: x, y = y, x.

i, j = 0, 1
A.T[[i, j]] = A.T[[j, i]]  # swap the columns i and j

Suppose you have a numpy array A like this:

array([[ 0., -1.,  0.,  0.],
       [ 0.,  1.,  1.,  1.],
       [ 0.,  0., -1.,  0.],
       [ 0.,  0.,  0., -1.]])

A.T[[0, 1]] = A.T[[1, 0]] will swap the first two columns:

array([[-1.,  0.,  0.,  0.],
       [ 1.,  0.,  1.,  1.],
       [ 0.,  0., -1.,  0.],
       [ 0.,  0.,  0., -1.]])

Comments

15

Building up on @Sven's answer:

import numpy as np
my_array = np.arange(9).reshape(3, 3)
print my_array

[[0 1 2]
 [3 4 5]
 [6 7 8]]

def swap_cols(arr, frm, to):
    arr[:,[frm, to]] = arr[:,[to, frm]]

swap_cols(my_array, 0, 1)
print my_array

[[1 0 2]
 [4 3 5]
 [7 6 8]]

def swap_rows(arr, frm, to):
    arr[[frm, to],:] = arr[[to, frm],:]

my_array = np.arange(9).reshape(3, 3)
swap_rows(my_array, 0, 2)
print my_array

[[6 7 8]
 [3 4 5]
 [0 1 2]]

Comments

1

If you want to simultaneously swap columns and assign to a new variable, the most clear and concise way I could figure out how to do it was this:

import numpy as np
test_arr = np.arange(12).reshape(4,3)
swapped = np.concatenate((test_arr[:, [1,0]], test_arr[:, 2:]), axis=1)

Note, if the further columns don't exist it will concatenate an on an empty array, meaning it will just swap the first two columns.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.