展平 NumPy 数组列表?

Posted

技术标签:

【中文标题】展平 NumPy 数组列表?【英文标题】:Flattening a list of NumPy arrays? 【发布时间】:2016-02-16 04:05:31 【问题描述】:

看来我有 NumPy 数组列表格式的数据 (type() = np.ndarray):

[array([[ 0.00353654]]), array([[ 0.00353654]]), array([[ 0.00353654]]), 
array([[ 0.00353654]]), array([[ 0.00353654]]), array([[ 0.00353654]]), 
array([[ 0.00353654]]), array([[ 0.00353654]]), array([[ 0.00353654]]), 
array([[ 0.00353654]]), array([[ 0.00353654]]), array([[ 0.00353654]]),
array([[ 0.00353654]])]

我正在尝试将它放入一个 polyfit 函数中:

m1 = np.polyfit(x, y, deg=2)

但是,它返回错误:TypeError: expected 1D vector for x

我假设我需要将我的数据扁平化为:

[0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654 ...]

我尝试了一个通常适用于列表列表的列表理解,但正如预期的那样,这没有奏效:

[val for sublist in risks for val in sublist]

最好的方法是什么?

【问题讨论】:

@Divakar 谢谢!为我工作! concatenate 假定所有数组的大小相同,您可能总是这样,否则请查看 ***.com/a/406822/1240268 之类的内容。 数组的长度都一样吗? 不确定是否重复但肯定相关@​​987654322@。 【参考方案1】:

您可以使用numpy.concatenate,顾名思义,它基本上将此类输入列表的所有元素连接到单个 NumPy 数组中,就像这样 -

import numpy as np
out = np.concatenate(input_list).ravel()

如果你希望最终输出是一个列表,你可以像这样扩展解决方案 -

out = np.concatenate(input_list).ravel().tolist()

示例运行 -

In [24]: input_list
Out[24]: 
[array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]])]

In [25]: np.concatenate(input_list).ravel()
Out[25]: 
array([ 0.00353654,  0.00353654,  0.00353654,  0.00353654,  0.00353654,
        0.00353654,  0.00353654,  0.00353654,  0.00353654,  0.00353654,
        0.00353654,  0.00353654,  0.00353654])

转换为列表-

In [26]: np.concatenate(input_list).ravel().tolist()
Out[26]: 
[0.00353654,
 0.00353654,
 0.00353654,
 0.00353654,
 0.00353654,
 0.00353654,
 0.00353654,
 0.00353654,
 0.00353654,
 0.00353654,
 0.00353654,
 0.00353654,
 0.00353654]

【讨论】:

通过这样做,我得到ValueError: all the input array dimensions except for the concatenation axis must match exactly @Athena 请发布一个新问题。不清楚数据格式到底是什么。【参考方案2】:

也可以通过

np.array(list_of_arrays).flatten().tolist()

导致

[0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654]

更新

正如@aydow 在 cmets 中指出的那样,如果不关心获得copy or a view,使用numpy.ndarray.ravel 会更快

np.array(list_of_arrays).ravel()

虽然,根据docs

当需要在尽可能多的情况下查看视图时,arr.reshape(-1) 可能更可取。

换句话说

np.array(list_of_arrays).reshape(-1)

我的初步建议是使用numpy.ndarray.flatten,returns a copy every time会影响性能。

现在让我们看看上面列出的解决方案的时间复杂度如何比较使用perfplot 包进行类似于 OP 的设置

import perfplot

perfplot.show(
    setup=lambda n: np.random.rand(n, 2),
    kernels=[lambda a: a.ravel(),
             lambda a: a.flatten(),
             lambda a: a.reshape(-1)],
    labels=['ravel', 'flatten', 'reshape'],
    n_range=[2**k for k in range(16)],
    xlabel='N')

这里flatten 演示了分段线性复杂性,可以通过复制初始数组与返回视图的ravelreshape 的恒定复杂性进行比较来合理地解释这一点。

还值得注意的是,可以预见的是,将输出 .tolist() 转换为所有三个的性能均等线性。

【讨论】:

np.flatten 有效,但值得注意的是它比np.ravel 慢得多。随着array 长度的增加,这种差异会变得更糟 @aydow 嗯,怎么会这样? np.flatten 确实较慢但并不显着。我只是在list(map(np.array, np.random.rand(1_000_000, 10)))np.concatenate(list_of_arrays).ravel() 上使用%%timeit290 ms ± 2.49 ms 对抗np.array(list_of_arrays).flatten()446 ms ± 26.5 ms,在我的笔记本电脑上没有%%timeit 的情况下,两者似乎都是瞬间执行的。 嗨@ayorgo,我与OP问题略有不同。我假设np.arrays 的np.array(这与我自己的问题有关)而不是np.arrays 的list。只使用np.ravel 需要249 ns ± 8.43 ns 而只使用np.flatten 需要25.4 ms ± 244 µs!!添加np.concatenatenp.array 会将其减慢到您提到的数字。很抱歉在我最初的评论中没有说明这一点 @aydow 哈哈,确实!我认为在性能上如此不同的是np.flatten 总是返回一个与'np.ravel' (***.com/a/28930580/4755520) 不同的副本。有趣的是,接受的答案不需要使用np.concatenate。只需转换为np.array.ravel() 就足够了。【参考方案3】:

另一种简单的方法是使用numpy.hstack(),然后使用squeeze() 删除单一维度,如下所示:

In [61]: np.hstack(list_of_arrs).squeeze()
Out[61]: 
array([0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654,
       0.00353654, 0.00353654, 0.00353654, 0.00353654, 0.00353654,
       0.00353654, 0.00353654, 0.00353654])

【讨论】:

【参考方案4】:

使用itertools 扁平化数组的另一种方式:

import itertools

# Recreating array from question
a = [np.array([[0.00353654]])] * 13

# Make an iterator to yield items of the flattened list and create a list from that iterator
flattened = list(itertools.chain.from_iterable(a))

这个解决方案应该非常快速,更多解释请参见https://***.com/a/408281/5993892。

如果结果数据结构应该是 numpy 数组,请使用 numpy.fromiter() 将迭代器耗尽到数组中:

# Make an iterator to yield items of the flattened list and create a numpy array from that iterator
flattened_array = np.fromiter(itertools.chain.from_iterable(a), float)

itertools.chain.from_iterable() 的文档: https://docs.python.org/3/library/itertools.html#itertools.chain.from_iterable

numpy.fromiter() 的文档: https://docs.scipy.org/doc/numpy/reference/generated/numpy.fromiter.html

【讨论】:

【参考方案5】:

我遇到了同样的问题,并找到了一个结合可变长度的一维 numpy 数组的解决方案:

np.column_stack(input_list).ravel()

请参阅numpy.column_stack 了解更多信息。

带有示例数据的可变长度数组示例:

In [135]: input_list
Out[135]: 
[array([[ 0.00353654,  0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654]]),
 array([[ 0.00353654,  0.00353654,  0.00353654]])]

In [136]: [i.size for i in input_list]    # variable size arrays
Out[136]: [2, 1, 1, 3]

In [137]: np.column_stack(input_list).ravel()
Out[137]: 
array([ 0.00353654,  0.00353654,  0.00353654,  0.00353654,  0.00353654,
        0.00353654,  0.00353654])

注意:仅在 Python 2.7.12 上测试

【讨论】:

我试过这个并得到ValueError: all the input array dimensions except for the concatenation axis must match exactly :( 我能够使用np.hstack 而不是np.column_stack 使其工作。我认为这是因为我的数组是一维的,而且我没有仔细阅读原始问题。无论如何谢谢:)

以上是关于展平 NumPy 数组列表?的主要内容,如果未能解决你的问题,请参考以下文章

Numpy 数组:连接展平和添加维度

Numpy 展平 RGB 图像数组

如何在 Numpy 中将数组展平为矩阵?

如何在不使用 NumPy 复制的情况下展平多维数组的轴?

如何展平 numpy 数组的最后两个维度? [复制]

展平大量列表,沿途解除分配