【问题标题】:Nested list comprehension in PythonPython中的嵌套列表理解
【发布时间】:2015-06-24 22:49:58
【问题描述】:

我有一个列表理解,我正在努力解决问题,但我似乎无法得到我想要的东西,我想看看是否有其他人知道!

我的基本数据结构是这样的:

structure = [[np.array([[1,2,3],[4,5,6]]), np.array([[7,8,9],[10,11,12]])], [np.array([[13,14,15],[16,17,18]]), np.array([[19,20,21],[22,23,24]])]]

所以我有一个包含 numpy 数组的子列表的整体列表,我想要的输出是某种分组(不管它是列表还是数组),并与以下元素配对:

[1, 13]
[4, 16]
[2, 14]
[5, 17]
[3, 15]
[6, 18]

我以为我可以使用以下样式构造:

output = [structure[i][0][j] for j in range(9) for i in range(len(structure))] 但可惜,没有乐趣。

我真的不介意它是否需要多个阶段 - 只是想将这些元素组合在一起!

(作为背景知识 - 我有从各种模型输出的概率列表,在这些模型中我有一个训练列表和一个验证列表:

[[model_1], [model_2], ..., [model_n]]

其中[model_1][[training_set], [validation_set], [test_set]]

[training_set]np.array([p_1, p_2, ..., p_n],[p_1, p_2, ..., p_n],...])

我想将每个模型的项目 1 的预测组合在一起,并从中创建一个长度等于我拥有的模型数量的训练向量。然后我想做同样的事情,但对于 [training_set] 的第二行。

如果这不合理,请告诉我!

【问题讨论】:

  • 别误会——这不是一个理想的数据结构!这是因为它允许我轻松添加任意数量的模型,然后根据这些模型的输出构建线性模型。我认为将外部分组设置为:training_set = [[model_1], [model_2], ..., [model_n]] 我很乐意将我的列表拆分为单独的变量,因为它可能会使事情变得更容易!
  • 嘿抱歉我删除了我的评论,因为我意识到我读错了..

标签: python numpy list-comprehension slice


【解决方案1】:

由于structure 中的所有数组(和子列表)大小相同,您可以将其转换为一个更高维的数组:

In [189]: A=np.array(structure)
Out[189]: 
array([[[[ 1,  2,  3],
         [ 4,  5,  6]],

        [[ 7,  8,  9],
         [10, 11, 12]]],


       [[[13, 14, 15],
         [16, 17, 18]],

        [[19, 20, 21],
         [22, 23, 24]]]])

In [190]: A.shape
Out[190]: (2, 2, 2, 3)

重塑和交换轴可以为您提供各种组合。

例如,可以使用以下方式选择示例子列表中的值:

In [194]: A[:,0,:,:]
Out[194]: 
array([[[ 1,  2,  3],
        [ 4,  5,  6]],

       [[13, 14, 15],
        [16, 17, 18]]])

再整形得到

In [197]: A[:,0,:,:].reshape(2,6)
Out[197]: 
array([[ 1,  2,  3,  4,  5,  6],
       [13, 14, 15, 16, 17, 18]])

并转置得到 6 行对:

In [198]: A[:,0,:,:].reshape(2,6).T
Out[198]: 
array([[ 1, 13],
       [ 2, 14],
       [ 3, 15],
       [ 4, 16],
       [ 5, 17],
       [ 6, 18]])

为了让它们按照1,4,2,5.. 的顺序,我可以先转置

In [208]: A[:,0,:,:].T.reshape(6,2)
Out[208]: 
array([[ 1, 13],
       [ 4, 16],
       [ 2, 14],
       [ 5, 17],
       [ 3, 15],
       [ 6, 18]])

【讨论】:

  • 很好,全部保存在 numpy 中!
【解决方案2】:

我认为这就是你想要的格式,它使用生成器:

import numpy as np
structure = [[np.array([[1,2,3],[4,5,6]]), np.array([[7,8,9],[10,11,12]])], [np.array([[13,14,15],[16,17,18]]), np.array([[19,20,21],[22,23,24]])]]
struc = structure

my_gen = ([struc[i][j][k][l], struc[i+1][j][k][l]] for i in range(len(struc)-1)
                                     for j in range(len(struc[i]))
                                     for k in range(len(struc[i][j]))
                                     for l in range(len(struc[i][j][k])))

try:
    val = my_gen.next()
    while val != None:
        print val
        val = my_gen.next()
except:
    pass

【讨论】:

    【解决方案3】:

    不确定你想要什么完整的输出,但这可能会有所帮助:

    imort numpy as np
    
    structure = [[np.array([[1, 2, 3], [4, 5, 6]]), np.array([[7, 8, 9], [10, 11, 12]])],
                 [np.array([[13, 14, 15], [16, 17, 18]]), np.array([[19, 20, 21], [22, 23, 24]])]]
    
    from itertools import chain
    
    zipped = (zip(*ele) for ele in zip(*next(zip(*structure))))
    
    print (list(chain.from_iterable(zip(*zipped))))
    [(1, 13), (4, 16), (2, 14), (5, 17), (3, 15), (6, 18)]
    

    好吧,巫术的细分:

    # transpose sub arrays so column 0 is the first two sub elements from 
    # each sub array
    In [4]: start = zip(*structure)
    
    In [5]: start
    Out[5]: 
    [(array([[1, 2, 3],
             [4, 5, 6]]), array([[13, 14, 15],
             [16, 17, 18]])), (array([[ 7,  8,  9],
             [10, 11, 12]]), array([[19, 20, 21],
             [22, 23, 24]]))]
    
    # our interesting sub array's i.e colunm[0]
    In [6]: first_col = next(start)
    
    In [7]: first_col
    Out[7]: 
    (array([[1, 2, 3],
            [4, 5, 6]]), array([[13, 14, 15],
            [16, 17, 18]]))
    
    # pair up corresponding sub array's
    In [8]: intersting_pairs = zip(*first_col)
    
    In [9]: intersting_pairs
    Out[9]: 
    [(array([1, 2, 3]), array([13, 14, 15])),
     (array([4, 5, 6]), array([16, 17, 18]))]
    
    # pair them up (1, 13), (2, 14) ...
    In [10]: create_final_pairings = [zip(*ele) for ele in intersting_pairs]
    
    In [11]: create_final_pairings
    Out[11]: [[(1, 13), (2, 14), (3, 15)], [(4, 16), (5, 17), (6, 18)]]
    

    最后将所有内容链接到一个单一的平面列表中并获得正确的顺序:

    In [13]: from itertools import chain
    # create flat list 
    In [14]: flat_list = list(chain.from_iterable(zip(*create_final_pairings))
    
    In [15]: flat_list
    Out[15]: [(1, 13), (4, 16), (2, 14), (5, 17), (3, 15), (6, 18)]
    

    一个使用 zip 转置的简单示例可能会有所帮助:

    In [17]: l = [[1,2,3],[4,5,6]]
    
    In [18]: zip(*l)
    Out[18]: [(1, 4), (2, 5), (3, 6)]
    
    In [19]: zip(*l)[0]
    Out[19]: (1, 4)
    
    In [20]: zip(*l)[1]
    Out[20]: (2, 5)
    
    In [21]: zip(*l)[2]
    Out[21]: (3, 6)
    

    对于 python2 你可以使用itertools.izip:

    from itertools import chain, izip
    
    
    zipped = (izip(*ele) for ele in izip(*next(izip(*structure))))
    print (list(chain.from_iterable(izip(*zipped))))
    
    [(1, 13), (4, 16), (2, 14), (5, 17), (3, 15), (6, 18)]
    

    【讨论】:

    • 太棒了!要求解释一下会不会太厚脸皮了,因为目前这在很大程度上似乎是巫术!
    • @Kali_89。哈哈,这对我来说也像是巫术。六个月以来,我从来没有像这样拉过拉链和换位过这么多!我会尝试分解它
    • @Kali_89,尽我所能分解每个步骤。如果顺序无关紧要,您可以删除最后一个 zip*
    • @PadraicCunningham Bravo!
    【解决方案4】:

    我必须先编写非列表理解版本才能理解这一点:

    new_training_vector = []
    for m1, m2 in zip(structure[0], structure[1]):
        for t1, t2 in zip(m1, m2):
            for d1, d2 in zip(t1, t2):
                new_training_vector.append([d1, d2])
    

    它的工作方式是创建两个并行迭代器(使用zip),每个模型一个,然后为每个训练集创建两个并行迭代器,依此类推,直到我们得到实际数据并且可以坚持一起来。

    一旦我们有了它,就不难将它折叠成列表理解:

    new_training_vector = [[d1, d2]
                           for m1, m2 in zip(structure[0], structure[1])
                           for t1, t2 in zip(m1, m2)
                           for d1, d2 in zip(t1, t2)]
    

    如果由于某种原因效果更好,您也可以使用字典来执行此操作。你会失去订单:

    import collections
    d = collections.defaultdict(list)
    for model in structure:
        for i, training_set in enumerate(model):
            for j, row in enumerate(training_set):
                for k, point in enumerate(row):
                    d[(i, j, k)].append(point)
    

    这一点的诀窍是我们只跟踪我们看到每个点的位置(模型级别除外),因此它们会自动进入相同的dict 项目。

    【讨论】:

      猜你喜欢
      • 2021-02-13
      • 1970-01-01
      • 2014-11-18
      • 1970-01-01
      • 2011-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多