将一维NumPy数组从(隐式)行优先顺序转为列优先顺序
我在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.]