我有一个列表列表,比如[[1,2],[2,3],[1,3]]到元组列表[(1,2),(2,3),(1, 3)]。这可以通过列表推导轻松完成
[tuple(l) for l in list]
然而,这对于大型列表来说会很慢。所以我想使用纯粹的numpy操作来执行相同的操作。
编辑1 我会尽量让它更清晰。
我有一个函数说foo()
,它将返回一个列表的python列表
def foo(*args):
# Do something
return arr
arr将有一个列表结构arr = [[a,b], [c,d],...]
。
每个内部列表(例如[a, b]
)将是2个元素长,并且arr将包含大量此类列表(通常大于90,000)。
arr = [(a,b), (c, d),...]
这可以使用列表推导来执行
def result(arr):
return [tuple(l) for l in arr]
但是,考虑到列表很大,我会避免这种情况,并使用纯numpy函数来完成此任务。 (正如@hpaulj建议使用arr.view(),在下面的答案中使用dict()和zip()查看他的另一种方法。
我想知道这是否可行。如果可行,请告诉我如何。
答案 0 :(得分:2)
您的样本列表以及由其制作的数组:
In [26]: alist = [[1,2], [2,3], [1,3]]
In [27]: arr = np.array(alist)
In [28]: arr
Out[28]:
array([[1, 2],
[2, 3],
[1, 3]])
tolist
是一种相对快速的“解包”数组的方法,但它会生成一个列表列表 - 就像我们开始时一样:
In [29]: arr.tolist()
Out[29]: [[1, 2], [2, 3], [1, 3]]
因此将其转换为元组列表需要相同的列表理解:
In [30]: [tuple(x) for x in arr.tolist()]
Out[30]: [(1, 2), (2, 3), (1, 3)]
In [31]: [tuple(x) for x in alist]
Out[31]: [(1, 2), (2, 3), (1, 3)]
现在,如果数组具有复合dtype,则tolist
会生成元组列表。相反,要从列表创建结构化数组,我们需要一个元组列表:
In [33]: arr1 = np.array([tuple(x) for x in alist], dtype='i,i')
In [34]: arr1
Out[34]: array([(1, 2), (2, 3), (1, 3)], dtype=[('f0', '<i4'), ('f1', '<i4')])
In [35]: arr1.tolist()
Out[35]: [(1, 2), (2, 3), (1, 3)]
从二维数组构造一个结构化数组,有点棘手:
In [37]: arr.view('i,i')
Out[37]:
array([[(1, 0), (2, 0)],
[(2, 0), (3, 0)],
[(1, 0), (3, 0)]], dtype=[('f0', '<i4'), ('f1', '<i4')])
astype
并没有好多少。事实上,我不止一次推荐使用tolist
路线:
np.array([tuple(x) for x in arr.tolist()],'i,i')
In[33]
是一个案例列表,其中元组列表很重要。那是因为numpy
开发人员选择将元组解释为结构数组'标记'。
我想不到常规的Python案例是必需的元组列表,列表列表也不行。通常元组和列表之间的显着差异是元组是不可变的。好的,在构造字典键(或设置元素)时,不变性很重要。
In [42]: dict(zip(alist,['a','b','c']))
....
TypeError: unhashable type: 'list'
In [43]: dict(zip([tuple(x) for x in alist],['a','b','c']))
Out[43]: {(1, 2): 'a', (1, 3): 'c', (2, 3): 'b'}
view
转换为结构化数组我之前使用view
的尝试是错误的,因为我使用了错误的dtype
:
In [45]: arr.dtype
Out[45]: dtype('int64')
In [46]: arr.view('i8,i8')
Out[46]:
array([[(1, 2)],
[(2, 3)],
[(1, 3)]], dtype=[('f0', '<i8'), ('f1', '<i8')])
In [47]: arr.view('i8,i8').tolist()
Out[47]: [[(1, 2)], [(2, 3)], [(1, 3)]]
更好 - 尽管现在我在列表中有元组。
In [48]: arr.view('i8,i8').reshape(3).tolist()
Out[48]: [(1, 2), (2, 3), (1, 3)]
这可以避免列表理解,但速度并不快:
In [49]: timeit arr.view('i8,i8').reshape(3).tolist()
21.4 µs ± 51.1 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [50]: timeit [tuple(x) for x in arr]
6.26 µs ± 5.51 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
从列表列表与元组列表创建字典的时间测试:
In [51]: timeit dict(zip([tuple(x) for x in alist],['a','b','c']))
2.67 µs ± 21.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [52]: timeit dict(zip(Out[48],['a','b','c']))
1.31 µs ± 5.96 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
显然你需要对现实问题进行时间测试,但是这个小例子表明了这些问题的实现方式。尽管所有关于numpy
操作的讨论都很快(呃),但列表推导并不是那么糟糕,特别是如果结果将成为Python对象列表的话。