简体   繁体   English

Python中的嵌套列表理解

[英]Nested list comprehension in Python

I've got a list comprehension I'm trying to get my head around and I just can't seem to get what I'm after and thought I'd see if anybody else knew how! 我有一个列表理解我正试图让我的头脑,我似乎无法得到我想要的东西,并认为我会看到其他人是否知道如何!

My basic data structure is this: 我的基本数据结构如下:

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]])]]

So I've got an overall list containing sublists of numpy arrays and my desired output is some sort of grouping (don't care if it's a list or an array) with the following elements paired: 所以我有一个包含numpy数组子列表的整体列表,我想要的输出是某种分组(不管它是列表还是数组),并且配对了以下元素:

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

I thought I'd got it with the following style construct: 我以为我会用以下样式构造得到它:

output = [structure[i][0][j] for j in range(9) for i in range(len(structure))] but alas, no joy. output = [structure[i][0][j] for j in range(9) for i in range(len(structure))]但是,没有快乐。

I don't really mind if it needs more than one stage - just want to get those elements grouped together! 我不介意它是否需要不止一个阶段 - 只是想将这些元素组合在一起!

(as a bit of background - I've got lists of probabilities outputted from various models and within those models I've got a training list and a validation list: (作为一些背景 - 我有各种模型输出的概率列表,在这些模型中我有一个训练列表和一个验证列表:

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

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

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

I'd like to group together the prediction for item 1 for each of the models and create a training vector out of it of length equal to the number of models I've got. 我想将每个模型的项目1的预测组合在一起,并创建一个长度等于我得到的模型数量的训练向量。 I'd then like to do the same but for the second row of [training_set]. 然后我想做同样的事情,但是对于[training_set]的第二行。

If that doesn't make sense let me know! 如果这没有意义,请告诉我!

Since all the arrays (and sublists) in structure are the same size you can turn it into one higher dimensional array: 由于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)

Reshaping and swapaxes can give you all kinds of combinations. 重塑和交换方式可以为您提供各种组合。

For example, the values in your sample sublist can be selected with: 例如,可以使用以下选项选择样本子列表中的值:

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

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

and reshape to get 并重塑得到

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

and transpose to get the 6 rows of pairs: 并转置以获得6对对:

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

To get them in the 1,4,2,5.. order I can transpose first 为了让他们进入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]])

Not sure exactly what full output you want but this may help: 不确定你想要的完整输出,但这可能会有所帮助:

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)]

Ok a breakdown of the witchcraft: 好了巫术的崩溃:

# 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)]]

Finally chain all into a single flat list and get the order correct: 最后将all链接到一个单独的平面列表中并获得正确的顺序:

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)]

A simple example of transposing with zip may help: 使用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)

For python2 you can use itertools.izip : 对于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)]

I had to write the non-list-comprehension version first to get my head around this: 我必须首先编写非列表理解版本来解决这个问题:

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])

The way it works is by creating two parallel iterators (using zip ), one for each model, then creating two parallel iterators for each of the training sets and so on until we get to the actual data and can just stick it together. 它的工作方式是创建两个并行迭代器(使用zip ),每个模型一个,然后为每个训练集创建两个并行迭代器,依此类推,直到我们得到实际数据并且可以将它们粘在一起。

Once we have that, it's not hard to go fold it into a list comprehension: 一旦我们拥有了它,就不难将其折叠成列表理解:

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)]

You can also do this with a dictionary, if that works better for some reason. 您也可以使用字典执行此操作,如果由于某种原因更好。 You would lose the order though: 你会丢失订单:

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)

The trick to this one is that we just keep track of where we saw each point (except for at the model level), so they automatically go into the same dict item. 这个的诀窍是我们只是跟踪我们看到每个点的位置(模型级别除外),因此它们会自动进入同一个dict项目。

I think this is what you want like the format you have, it uses generators: 我认为这就是你想要的格式,它使用生成器:

 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 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM