从 ND 到1D 数组

假设我有一个数组 a:

a = np.array([[1,2,3], [4,5,6]])


array([[1, 2, 3],
[4, 5, 6]])

我想把它转换成一个一维数组(例如一个列向量) :

b = np.reshape(a, (1,np.product(a.shape)))

但现在又回来了

array([[1, 2, 3, 4, 5, 6]])

这不同于:

array([1, 2, 3, 4, 5, 6])

我可以将这个数组的第一个元素手动转换为一维数组:

b = np.reshape(a, (1,np.product(a.shape)))[0]

但这需要我知道原始数组有多少维(并在处理更高维时连接[0])

有没有一种与维数无关的方法可以从任意的 ndarray 中获得列/行向量?

400766 次浏览

使用 Np.ravel(用于一维视图)或 Np.ndarray 压平(用于一维副本)或 Np.ndarray 公寓(用于一维迭代器) :

In [12]: a = np.array([[1,2,3], [4,5,6]])


In [13]: b = a.ravel()


In [14]: b
Out[14]: array([1, 2, 3, 4, 5, 6])

请注意,ravel()在可能的情况下返回 aview。因此,修改 b也修改 a。当1D 元素在内存中是连续的时候,ravel()返回一个 view,但是如果 a是通过使用非单位步长(例如 a = x[::2])切割另一个数组而得到的,则返回一个 copy

如果需要的是副本而不是视图,请使用

In [15]: c = a.flatten()

如果你只想要一个迭代器,使用 np.ndarray.flat:

In [20]: d = a.flat


In [21]: d
Out[21]: <numpy.flatiter object at 0x8ec2068>


In [22]: list(d)
Out[22]: [1, 2, 3, 4, 5, 6]
In [14]: b = np.reshape(a, (np.product(a.shape),))


In [15]: b
Out[15]: array([1, 2, 3, 4, 5, 6])

或者,简单地说:

In [16]: a.flatten()
Out[16]: array([1, 2, 3, 4, 5, 6])

虽然这不是使用 np 数组格式,(懒得修改我的代码)这应该做你想要的... 如果,你真的想要一个列向量,你会想要调换向量的结果。这完全取决于你打算如何使用它。

def getVector(data_array,col):
vector = []
imax = len(data_array)
for i in range(imax):
vector.append(data_array[i][col])
return ( vector )
a = ([1,2,3], [4,5,6])
b = getVector(a,1)
print(b)


Out>[2,5]

因此,如果你需要调换位置,你可以这样做:

def transposeArray(data_array):
# need to test if this is a 1D array
# can't do a len(data_array[0]) if it's 1D
two_d = True
if isinstance(data_array[0], list):
dimx = len(data_array[0])
else:
dimx = 1
two_d = False
dimy = len(data_array)
# init output transposed array
data_array_t = [[0 for row in range(dimx)] for col in range(dimy)]
# fill output transposed array
for i in range(dimx):
for j in range(dimy):
if two_d:
data_array_t[j][i] = data_array[i][j]
else:
data_array_t[j][i] = data_array[j]
return data_array_t

不同大小的数组列表使用如下:

import numpy as np


# ND array list with different size
a = [[1],[2,3,4,5],[6,7,8]]


# stack them
b = np.hstack(a)


print(b)

产出:

[1 2 3 4 5 6 7 8]

最简单的方法之一是使用 flatten(),如下例所示:

 import numpy as np


batch_y =train_output.iloc[sample, :]
batch_y = np.array(batch_y).flatten()

我的数组是这样的:

    0
0   6
1   6
2   5
3   4
4   3
.
.
.

使用 flatten()后:

array([6, 6, 5, ..., 5, 3, 6])

它也是这类错误的解决方案:

Cannot feed value of shape (100, 1) for Tensor 'input/Y:0', which has shape '(?,)'

我希望看到一个基准测试结果的功能提到的答案,包括 Unutbu 餐厅

还要指出的是,笨蛋医生建议使用 arr.reshape(-1)的情况下,视图是可取的。(即使 ravel在下面的结果中稍微快一点)


DR : np.ravel是性能最好的(非常小的剂量)。

基准

职能:

Numpy 版本:’1.18.0’

不同 ndarray大小的执行时间

+-------------+----------+-----------+-----------+-------------+
|  function   |   10x10  |  100x100  | 1000x1000 | 10000x10000 |
+-------------+----------+-----------+-----------+-------------+
| ravel       | 0.002073 |  0.002123 |  0.002153 |    0.002077 |
| reshape(-1) | 0.002612 |  0.002635 |  0.002674 |    0.002701 |
| flatten     | 0.000810 |  0.007467 |  0.587538 |  107.321913 |
| flat        | 0.000337 |  0.000255 |  0.000227 |    0.000216 |
+-------------+----------+-----------+-----------+-------------+

结论

ravelreshape(-1)的执行时间是一致的,与 ndarray 大小无关。 然而,ravel稍快,但 reshape提供灵活的重塑大小。(也许这就是为什么 笨蛋医生推荐使用它。或者在某些情况下,reshape返回 view,而 ravel不返回 view)。
如果您正在处理大尺寸 ndarray,使用 flatten可能会导致性能问题。建议不要使用。除非您需要数据的副本来执行其他操作。

用过的代码

import timeit
setup = '''
import numpy as np
nd = np.random.randint(10, size=(10, 10))
'''


timeit.timeit('nd = np.reshape(nd, -1)', setup=setup, number=1000)
timeit.timeit('nd = np.ravel(nd)', setup=setup, number=1000)
timeit.timeit('nd = nd.flatten()', setup=setup, number=1000)
timeit.timeit('nd.flat', setup=setup, number=1000)

最好和最快的所有建议的解决方案: np.reshape()

%timeit img1ary = np.reshape(img2ary,(np.product(img2ary.shape),1))
9.3 µs ± 69.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)


%timeit img1ary = img2ary.ravel()
157 ns ± 1.32 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)


%timeit img1ary = img2ary.flatten()
961 ns ± 5.77 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)