【问题标题】:Efficient way of appending / extracting list elements追加/提取列表元素的有效方法
【发布时间】:2016-05-09 01:06:12
【问题描述】:

假设我有以下列表:

rays_all = [np.array(r11, r21, r31, r41),
            np.array(r12, r22, r32, r42),
            np.array(r13, r23, r33, r43),
            np.array(r14, r24, r34, r44)]

所有 r11、r21、r31 等都是形状为 (3L,) 的数组(将其视为 3D 空间中的向量)。

如果我想提取np.array(r14, r24, r34, r44) 的(4L,3L) 数组,我只需使用rays_all[-1]。如果我想追加一个新的np.array(r15, r25, r35, r45) 数组,我只需使用rays_all.append

现在我以另一种方式排列上述向量(r11、r12 等):

ray1 = [r11, r12, r13, r14]
ray2 = [r21, r22]
ray3 = [r31, r32, r33]
ray4 = [r41, r42, r43, r44]

现在每个“射线”都有自己的长度不同的列表。如果我想提取数组结构中每个列表的最后一个元素,即np.array([r14,r22,r33,r44]),那么最有效的方法是什么?另一方面,如果我想将数组np.array([r15,r23,r34,r45]) 中的元素添加到列表中,这样我就会拥有

ray1 = [r11, r12, r13, r14, r15]
ray2 = [r21, r22, r23]
ray3 = [r31, r32, r33, r34]
ray4 = [r41, r42, r43, r44, r45]

什么是最有效的方法?我知道我可以只循环执行此操作,但我想它比rays_all[-1]rays_append() 慢得多?有没有“矢量化”的方式来做到这一点?

【问题讨论】:

  • 通常很难在未对齐的数据上获得矢量化优势。数组实现可能不会改进自然列表算法。
  • 那么在这种情况下使用循环已经是最快的方式了吗?是否有其他存储 ray1,ray2,ray3,ray4 的方法(以便它们对齐?)以便我仍然可以使用rays_all 矢量化方式?
  • 为这些列表定义align

标签: python arrays list numpy vectorization


【解决方案1】:

小心混合数组和列表操作。

制作一些 3 元素数组并像第一种情况一样组合它们:

In [748]: r1,r2,r3,r4=np.arange(3),np.ones(3),np.zeros(3),np.arange(3)[::-1]
In [749]: x1=np.array((r1,r2))
In [750]: x2=np.array((r3,r4))
In [751]: rays=[x1,x2]
In [752]: rays
Out[752]: 
[array([[ 0.,  1.,  2.],
        [ 1.,  1.,  1.]]), array([[ 0.,  0.,  0.],
        [ 2.,  1.,  0.]])]

rays 现在是一个包含两个二维数组((2,3) 形状)的列表。正如您所说,您可以从该列表中选择一个项目或向其附加另一个数组(您可以向其附加任何内容,而不仅仅是一个类似的数组)。 rays 的操作是列表操作。

你也可以创建一个 3d 数组:

In [758]: ray_arr=np.array((x1,x2))
In [759]: ray_arr
Out[759]: 
array([[[ 0.,  1.,  2.],
        [ 1.,  1.,  1.]],

       [[ 0.,  0.,  0.],
        [ 2.,  1.,  0.]]])
In [760]: ray_arr.shape
Out[760]: (2, 2, 3)
In [761]: ray_arr[-1]
Out[761]: 
array([[ 0.,  0.,  0.],
       [ 2.,  1.,  0.]])

您可以像列表一样从ray_arr 中进行选择。但是追加需要通过np.concatenate 创建一个新数组(可能隐藏在np.append 函数中)。没有“就地”附加在列表中。

通过在最后一维上进行索引,有效选择所有组件数组的最后一个元素。

In [762]: ray_arr[:,:,-1]
Out[762]: 
array([[ 2.,  1.],
       [ 0.,  0.]])

要从列表 rays 中获取相应的值,您必须使用列表推导(或其他循环):

In [765]: [r[:,-1] for r in rays]
Out[765]: [array([ 2.,  1.]), array([ 0.,  0.])]

没有像数组那样的索引快捷方式。

有像zip(以及itertools 中的其他工具)这样的工具可以帮助您遍历列表,甚至重新排列值,例如

In [773]: list(zip(['a','b'],['c','d']))
Out[773]: [('a', 'c'), ('b', 'd')]
In [774]: list(zip(['a','b'],['c','d']))[-1]
Out[774]: ('b', 'd')

还有参差不齐的子列表:

In [782]: list(zip(['a','b','c'],['d']))
Out[782]: [('a', 'd')]
In [783]: list(itertools.zip_longest(['a','b','c'],['d']))
Out[783]: [('a', 'd'), ('b', None), ('c', None)]

但我不明白这些将如何帮助从您的光线向量中提取值。


值得探索的是将基向量收集到一个二维数组中,并为各种目的使用对额外组的索引,

In [867]: allrays=np.array([r1,r2,r3,r4])
In [868]: allrays
Out[868]: 
array([[ 0.,  1.,  2.],
       [ 1.,  1.,  1.],
       [ 0.,  0.,  0.],
       [ 2.,  1.,  0.]])

所有光线的“z”坐标

In [869]: allrays[:,-1]
Out[869]: array([ 2.,  1.,  0.,  0.])

光线的一个子集(因为它是一个切片,所以它是一个视图)

In [871]: allrays[0:2,:]
Out[871]: 
array([[ 0.,  1.,  2.],
       [ 1.,  1.,  1.]])

另一个子集:

In [872]: allrays[2:,:]
Out[872]: 
array([[ 0.,  0.,  0.],
       [ 2.,  1.,  0.]])

3 个项目子集,通过列表选择 - 这是一个副本

In [873]: allrays[[0,1,2],:]
Out[873]: 
array([[ 0.,  1.,  2.],
       [ 1.,  1.,  1.],
       [ 0.,  0.,  0.]])
In [874]: allrays[[3],:]
Out[874]: array([[ 2.,  1.,  0.]])

索引得到的几个子集:

In [875]: ind=[[0,1,2],[3]]
In [876]: [allrays[i] for i in ind]
Out[876]: 
[array([[ 0.,  1.,  2.],
        [ 1.,  1.,  1.],
        [ 0.,  0.,  0.]]), 
 array([[ 2.,  1.,  0.]])]

如果组是连续的,你可以使用split:

In [884]: np.split(allrays,[3])
Out[884]: 
[array([[ 0.,  1.,  2.],
        [ 1.,  1.,  1.],
        [ 0.,  0.,  0.]]), array([[ 2.,  1.,  0.]])]

子数组是视图(检查 .__array_interface__ 属性。

实际上,它只是将参差不齐的列表问题提升了一个级别。尽管如此,还有更多的灵活性。您可以构建其他索引子列表,例如

In [877]: ind1=[i[-1] for i in ind]   # last of all groups
In [878]: ind1
Out[878]: [2, 3]
In [879]: ind2=[i[0] for i in ind]   # first of all groups
In [880]: ind2
Out[880]: [0, 3]

您可以将一些新值连接到allrays。然后,您可能必须重建索引列表。但我怀疑这种建筑是一次性完成的,而访问是重复的。


我想到了一个关于从plt.pcolormesh(和plt.pcolor)生成的img 中访问值的早期SO 问题。一个将图像作为 2d 网格上的表面来维护,另一个更一般地说,只是四边形的集合,每个四边形都有定义其边界的颜色和路径。

【讨论】:

    【解决方案2】:

    在回答您的具体问题时,包含四个“射线”列表的最后一个元素的列表通常是 [ray1[-1],ray2[-1],ray3[-1],ray4[-1]]

    由于您在这里主要关心的似乎是执行速度,我假设您必须一遍又一遍地执行此操作。您是否考虑过创建一个代表最后一个元素的小数据结构,例如last_element = [r1x,r2x,r3x,r4x],并在您逐步解决问题时保持其值?每次更改 last_element 时,您都会根据需要将新数据附加到其他列表中。换句话说,不是从大列表中重复提取最后一个元素,而是从最后一个元素逐步构建大列表。只要您无论如何都必须构建那些大列表,那将必须更有效。它能解决你的问题吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      相关资源
      最近更新 更多