展平 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
演示了分段线性复杂性,可以通过复制初始数组与返回视图的ravel
和reshape
的恒定复杂性进行比较来合理地解释这一点。
还值得注意的是,可以预见的是,将输出 .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()
上使用%%timeit
和290 ms ± 2.49 ms
对抗np.array(list_of_arrays).flatten()
的446 ms ± 26.5 ms
,在我的笔记本电脑上没有%%timeit
的情况下,两者似乎都是瞬间执行的。
嗨@ayorgo,我与OP问题略有不同。我假设np.array
s 的np.array
(这与我自己的问题有关)而不是np.array
s 的list
。只使用np.ravel
需要249 ns ± 8.43 ns
而只使用np.flatten
需要25.4 ms ± 244 µs
!!添加np.concatenate
和np.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 数组列表?的主要内容,如果未能解决你的问题,请参考以下文章