将一维NumPy数组从(隐式)行优先顺序转为列优先顺序

3 投票
2 回答
1290 浏览
提问于 2025-04-30 07:19

我在NumPy中有一个一维数组,它隐含地表示了一些二维数据,按照行优先的顺序排列。这里有一个简单的例子:

import numpy as np
# My data looks like [[1,2,3,4], [5,6,7,8]]
a = np.array([1,2,3,4,5,6,7,8])

我想把这个一维数组转换成列优先的顺序(也就是说,像例子中的 b = [1,5,2,6,3,7,4,8] 这样)。通常,我会这样做:

mat = np.reshape(a, (-1,4))
b = mat.flatten('F')

不过,我的输入数组的长度并不是我想要的行长度的整数倍(也就是说,a = [1,2,3,4,5,6,7]),所以我不能使用 reshape。但是,我想保留那些额外的数据,因为这些数据可能会很多,因为我的行比较长。请问在NumPy中有没有简单的方法可以做到这一点呢?

暂无标签

2 个回答

2

我想到的最简单的方法是不要尝试使用reshape和像ravel('F')这样的方式,而是直接把你数组的切片拼接在一起。

比如说:

>>> cols = 4
>>> a = np.array([1,2,3,4,5,6,7])
>>> np.concatenate([a[i::cols] for i in range(cols)])
array([1, 5, 2, 6, 3, 7, 4])

这个方法适用于任何长度的数组和任何列数:

>>> cols = 5
>>> b = np.arange(17)
>>> np.concatenate([b[i::cols] for i in range(cols)])
array([ 0,  5, 10, 15,  1,  6, 11, 16,  2,  7, 12,  3,  8, 13,  4,  9, 14])

另外,你也可以使用as_strided来改变形状。数组a如果太小,无法适应(2, 4)的形状也没关系:你只会在最后的位置得到一些垃圾数据(也就是内存中随便的内容):

>>> np.lib.stride_tricks.as_strided(a, shape=(2, 4))
array([[        1,         2,         3,         4],
       [        5,         6,         7, 168430121]])

>>> _.flatten('F')[:7]
array([1, 5, 2, 6, 3, 7, 4])

一般来说,给定一个数组b和想要的列数cols,你可以这样做:

>>> x = np.lib.stride_tricks.as_strided(b, shape=(len(b)//cols + 1, cols)) # reshape to min 2d array needed to hold array b
>>> np.concatenate((x[:,:len(b)%cols].ravel('F'), x[:-1, len(b)%cols:].ravel('F')))

这会把数组中“好的”部分(那些不包含垃圾值的列)和“坏的”部分(除了底行的垃圾值)分开,并把这两个部分拼接在一起。例如:

>>> cols = 5
>>> b = np.arange(17)
>>> x = np.lib.stride_tricks.as_strided(b, shape=(len(b)//cols + 1, cols))
>>> np.concatenate((x[:,:len(b)%cols].ravel('F'), x[:-1, len(b)%cols:].ravel('F')))
array([ 0,  5, 10, 15,  1,  6, 11, 16,  2,  7, 12,  3,  8, 13,  4,  9, 14])
1

用一些值来表示空值,这样可以让数组的长度变成你想要分割的倍数。如果可以把数据转换成浮点数的话,可以用nan(不是一个数字)来表示那些空值。接着,把这个数组变成二维的,再进行转置,最后再变回一维。最后,去掉那些空值。

import numpy as np
a = np.array([1,2,3,4,5,6,7]) # input
b = np.concatenate( (a, [np.NaN]) ) # add a NaN to make it 8 = 4x2
c = b.reshape(2,4).transpose().reshape(8,)  # reshape to 2x4, transpose, reshape to 8x1
d = c[-np.isnan(c)]  # remove NaN
print d

[ 1.  5.  2.  6.  3.  7.  4.]

撰写回答