在numpy数组中交换列?

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

那么

swap_columns(data, 0, 1)

无法运行。然而,直接调用代码可以。

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

为什么会出现这个问题,我该怎么解决?错误提示为“IndexError: 0维数组只能使用一个()或者一个newaxes列表(和一个单独的...)作为索引”,这似乎意味着参数不是整数?我已经尝试将列转换为整数,但是没有解决问题。

5个回答

130
这里有两个问题。第一个问题是你传递给函数的data显然不是一个二维NumPy数组,至少错误信息是这样说的。
第二个问题是代码不能如你所愿地工作:
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]])

问题在于Numpy的基本切片basic slicing并不会创建实际数据的副本,而是对同一数据的视图。为了使其有效,您需要显式复制。
temp = numpy.copy(my_array[:, 0])
my_array[:, 0] = my_array[:, 1]
my_array[:, 1] = temp

或使用高级切片

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

高级切片似乎也不会复制数据。 - Mateen Ulhaq
2
请放心,它确实可以。请查看相关文档或自行尝试。 - Sven Marnach
它确实复制了数据,但这意味着赋值操作会分配给一个立即被丢弃的临时对象。 - AI0867
2
@AI0867 只有右侧的高级切片会创建一个副本。在赋值目标位置的高级切片不会创建副本。你可以尝试这段代码 - 它完全正常运行。(不同行为的原因是值上下文中的 [] 运算符由 __getitem__() 处理,而带有 [] 的赋值则由 __setitem__() 处理。将临时副本分配给没有意义,因此 NumPy 数组的 __setitem__() 实现不会这样做。) - Sven Marnach
我改正我的错误。 - AI0867

45

我发现以下的方式最快:

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

时间分析:

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

高级切片时间为:

%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

4
支持使用copy()函数的部分,我在代码中缺少了这个。 - magu_

17
在NumPy中交换列的一种优雅方式类似于在Python中交换两个变量的方法,就像这样:x, y = y, x
i, j = 0, 1
A.T[[i, j]] = A.T[[j, i]]  # swap the columns i and j

假设您有一个如下的numpy数组A
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]]会交换前两列:

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

1
确实非常优雅和聪明。谢谢。 - Kjeld Schmidt

15

在@Sven的回答的基础上进行补充:

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]]

1

如果您想同时交换列并分配给新变量,我能想到的最清晰简洁的方法如下:

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

请注意,如果进一步的列不存在,它将连接一个空数组,并且只会交换前两个列。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接