Numpy:当所有数组具有相同的长度时,创建一个由numpy数组组成的1D数组。

3
我想要能够将一个现有的二维数组转换为一个一维数组的数组。我所找到的唯一方法是使用类似以下的方式:
my_2d_array = np.random.random((5, 3))
my_converted_array = np.zeros(len(my_2d_array), dtype='O')
for i, row in enumerate(my_converted_array):
    my_converted_array[i] = row

你是否有更快、更简洁的方法来完成这个任务?

如果内部数组的形状不同,也是可能的,例如:

my_1d_array = np.array([
    np.array([0, 1], dtype=np.float),
    np.array([2], dtype=np.float)
], dtype='O')
assert my_array.shape == (2,)

但如果数组长度相同,numpy会自动将其转换为二维数组:
my_2d_array = np.array([
    np.array([0, 1], dtype=np.float),
    np.array([2, 3], dtype=np.float)
], dtype='O')
assert my_array.shape == (2, 2)

编辑:为了澄清一些答案,我不能使用flattenreshaperavel,因为它们会保持相同数量的元素。相反,我想从形状为(N, M)的二维数组转换为形状为(N,)的一维数组,其中每个对象(1D数组)都具有形状(M,)


new_array[:] = list(2d_array) 可以作为枚举循环的替代方案。无论如何,您都必须从正确大小的对象数组开始。 - hpaulj
当然,非常聪明。不幸的是我刚刚对其进行了基准测试,当数组很大时,它所需的时间比我的for循环长约两倍。 - user2685230
只是补充一下,当内部维度很小时,一旦大于约1000,差异更像是10%。 - user2685230
你的对象数组实际上就是一个列表。在它上面进行迭代几乎和在列表上进行迭代一样快,而且比在二维数组上进行迭代更快。 - hpaulj
4个回答

2

这里有一种使用np.frompyfunc的方法,比您的方法少打一些字,并且速度相当 - 对于小数组来说大致相同,但对于大数组来说更快:

>>> import numpy as np
>>> 
>>> def f_empty(a):
...     n = len(a)
...     b = np.empty((n,), dtype=object)
...     for i in range(n):
...         b[i] = a[i]
...     return b
... 
>>> def f_fpf(a):
...     n = len(a)
...     return np.frompyfunc(a.__getitem__, 1, 1)(np.arange(n))
... 
>>> def f_fpfl(a):
...     n = len(a)
...     return np.frompyfunc(list(a).__getitem__, 1, 1)(np.arange(n))
... 

>>> from timeit import repeat
>>> kwds = dict(globals=globals(), number=10000)

>>> a = np.random.random((10, 20))
>>> repeat('f_fpf(a)', **kwds)
[0.04216550011187792, 0.039600114803761244, 0.03954345406964421]
>>> repeat('f_fpfl(a)', **kwds)
[0.05635825078934431, 0.04677496198564768, 0.04691878380253911]
>>> repeat('f_empty(a)', **kwds)
[0.04288528114557266, 0.04144620103761554, 0.041292963083833456]

>>> a = np.random.random((100, 200))
>>> repeat('f_fpf(a)', **kwds)
[0.20513887284323573, 0.2026138547807932, 0.20201953873038292]
>>> repeat('f_fpfl(a)', **kwds)
[0.21277308696880937, 0.18629810912534595, 0.18749701930209994]
>>> repeat('f_empty(a)', **kwds)
[0.2321561980061233, 0.24220682680606842, 0.22897077212110162]

>>> a = np.random.random((1000, 2000))
>>> repeat('f_fpf(a)', **kwds)
[2.1829855730757117, 2.1375885657034814, 2.1347726942040026]
>>> repeat('f_fpfl(a)', **kwds)
[1.8276268909685314, 1.8227900266647339, 1.8233762909658253]
>>> repeat('f_empty(a)', **kwds)
[2.5640305397100747, 2.565472401212901, 2.4353492129594088]

frompyfunc返回一个对象数据类型数组的巧妙用法。通常这是个麻烦,但在这里它是一个有用的特性。 - hpaulj

1

你可以简单地调用ravel()将任何维度的数组转换为1d

my_converted_array = np.ravel(my_2d_array)

了解更多关于 ravel() 的信息在这里

或者您可以简单地使用:

my_converted_array = my_2d_array.reshape(-1)

1
In [136]: arr = np.arange(15).reshape(5,3)
In [137]: arr1 = np.empty(5, object)

直接赋值不起作用:

In [138]: arr1[:] = arr
...
ValueError: could not broadcast input array from shape (5,3) into shape (5)

arr分解为一系列行的操作。
In [139]: arr1[:] = list(arr)
In [140]: arr1
Out[140]: 
array([array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8]),
       array([ 9, 10, 11]), array([12, 13, 14])], dtype=object)

我并不太惊讶你的原始版本在速度上是有竞争力的:

In [141]: for i,row in enumerate(arr):
     ...:     arr1[i] = row

"

arr1 包含指针,就像列表一样

"
In [143]: list(arr)
Out[143]: 
[array([0, 1, 2]),
 array([3, 4, 5]),
 array([6, 7, 8]),
 array([ 9, 10, 11]),
 array([12, 13, 14])]

对对象数组的操作几乎总是需要迭代和/或对象引用。与数值数组一样快的只有那些不涉及内容的东西,例如reshape和slice。

我在其他时间测试中发现,对对象数组进行迭代比对数组行进行迭代要快,但仍然比对列表进行迭代慢一些。

我经常创建这样的数组,但不是在“生产”规模下。海报通常希望反过来转换对象数组为2d,因此我使用这个来复制他们的示例。海报通常从其他地方获得这样的对象数组,例如Pandas dataframe或一些使用对象数组进行普遍性的机器学习代码。


0

有一些方法可以完成这项工作,例如ravelflattenreshape。在link中了解它们之间的区别。

使用ravelflatten

my_1d_array = my_2d_array.flatten() # Return (15,) dimension 
my_1d_array = my_2d_array.ravel() # Return (15,) dimension

这种类型(15,)在执行一些矩阵操作时可能会导致一些不一致,从而导致数据结果不一致或程序错误。

因此,我建议您使用以下的reshape

my_1d_array = my_2d_array.reshape((-1,1)) # Returns (15,1) dimension
or,
my_1d_array = my_2d_array.reshape((1,-1)) # Returns (1,15) dimension

通过这种方式将矩阵重塑为(x, y),可以确保矩阵操作始终产生一致的数据,而不会出现任何错误。


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