Python 优雅地从主列表的子列表中获取信息

Python 优雅地从主列表的子列表中获取信息,python,list,numpy,Python,List,Numpy,好的,这是我的问题。我有一个由N子列表组成的列表,每个子列表由M元素(浮动)组成。所以在一般情况下,它看起来是这样的: a_list = [b_list_1, b_list_2, ..., b_list_N] a = [[1.1, 0.5, 0.7], [0.3, 1.4, 0.2], [0.6, 0.2, 1.], [1.1, 0.5, 0.3], [0.2, 1.1, 0.8], [1.1, 0.5, 1.], [1.2, 0.3, 0.6], [0.6, 0.4, 0.9], [0.6,

好的,这是我的问题。我有一个由
N
子列表组成的列表,每个子列表由
M
元素(浮动)组成。所以在一般情况下,它看起来是这样的:

a_list = [b_list_1, b_list_2, ..., b_list_N]
a = [[1.1, 0.5, 0.7], [0.3, 1.4, 0.2], [0.6, 0.2, 1.], [1.1, 0.5, 0.3], [0.2, 1.1, 0.8], [1.1, 0.5, 1.], [1.2, 0.3, 0.6], [0.6, 0.4, 0.9], [0.6, 0.2, 0.5]]
与:

对于本例,假设
N=9;M=3,因此列表如下所示:

a_list = [b_list_1, b_list_2, ..., b_list_N]
a = [[1.1, 0.5, 0.7], [0.3, 1.4, 0.2], [0.6, 0.2, 1.], [1.1, 0.5, 0.3], [0.2, 1.1, 0.8], [1.1, 0.5, 1.], [1.2, 0.3, 0.6], [0.6, 0.4, 0.9], [0.6, 0.2, 0.5]]
我需要循环浏览这个列表,识别那些共享相同前两个浮点值的项目,作为相同的项目,其中第三个浮点值应该在存储之前平均。这意味着我应该检查一个项目是否已经被标识为以前重复过,因此我不再将其标识为新项目

为了更清楚地理解我的意思,以下是处理列表
a
的输出:

a_processed = [[1.1, 0.5, 0.67], [0.3, 1.4, 0.2], [0.6, 0.2, 0.75], [0.2, 1.1, 0.8], [1.2, 0.3, 0.6], [0.6, 0.4, 0.9]]
请注意,此新列表中的第一项在a(
a[0]
a[3]
a[5]
)中被标识了三次,因此它以其第三个浮点平均值(
(0.7+0.3+1.)/3.=0.67
)存储。第二项未在
a
中重复,因此按原样存储。第三项在
a
a[2]
a[8]
)中发现两次,并以其第三个浮点平均值(
(1.+0.5)/2.=0.75
)存储。新列表中的其余项目没有在
a
中重复找到,因此它们也被存储,没有任何修改

因为我知道不建议在循环时更新/修改列表,所以我选择使用几个临时列表。这是我想出的代码:

import numpy as np

a = [[1.1, 0.5, 0.7], [0.3, 1.4, 0.2], [0.6, 0.2, 1.], [1.1, 0.5, 0.3],
     [0.2, 1.1, 0.8], [1.1, 0.5, 1.], [1.2, 0.3, 0.6], [0.6, 0.4, 0.9],
[0.6, 0.2, 0.5]]

# Final list.
a_processed = []

# Holds indexes of elements to skip.
skip_elem = []

# Loop through all items in a.
for indx, elem in enumerate(a):
    temp_average = []
    temp_average.append(elem)        
    # Only process if not found previously.
    if indx not in skip_elem:
        for indx2, elem2 in enumerate(a[(indx+1):]):
            if elem[0] == elem2[0] and elem[1] == elem2[1]:
                temp_average.append(elem2)
                skip_elem.append(indx2+indx+1)

        # Store 1st and 2nd floats and averaged 3rd float.
        a_processed.append([temp_average[0][0], temp_average[0][1],
                            round(np.mean([i[2] for i in temp_average]),2)])

这段代码可以工作,但我想知道是否有一种更优雅的/pythonic的方法来实现这一点。它看起来太复杂了(我认为是Fortran风格的)。

我认为,通过使用
defaultdict
创建一个字典,从每个子列表的前两个元素到所有第三个项目,您当然可以使代码更加简洁易读:

from collections import defaultdict
nums = defaultdict(list)
for arr in a:
    key = tuple(arr[:2]) # make the first two floats the key
    nums[key].append( arr[2] ) # append the third float for the given key

a_processed = [[k[0], k[1], sum(vals)/len(vals)] for k, vals in nums.items()]
使用此选项,我可以获得与您相同的输出(尽管顺序不同):


如果
a_处理的顺序是一个问题,您可以使用@DSM指出的方法进行比较。如果这确实是一个幕后的数据处理问题,那么您可以通过这种方式节省大量时间

>>> a
[[1.1, 0.5, 0.7], [0.3, 1.4, 0.2], [0.6, 0.2, 1.0], [1.1, 0.5, 0.3], [0.2, 1.1, 0.8], [1.1, 0.5, 1.0], [1.2, 0.3, 0.6], [0.6, 0.4, 0.9], [0.6, 0.2, 0.5]]
>>> df = pd.DataFrame(a)
>>> df.groupby([0,1]).mean()
                2
0   1            
0.2 1.1  0.800000
0.3 1.4  0.200000
0.6 0.2  0.750000
    0.4  0.900000
1.1 0.5  0.666667
1.2 0.3  0.600000

这个问题很常见,是一个简单的问题。您可以使用命名列、计算大量其他有用的统计数据、处理缺少的数据等。

这可能在codereview.stackexchange.com上更好。是否需要在
已处理的
中指定顺序?或者元素的任何顺序都可以?任何顺序都可以,我可以稍后重新排列它们。另一种保持顺序的方法是使用
OrderedDict
而不是
defaultdict
,并使用
nums.setdefault(key,[]).append(arr[2])
。然后迭代
nums.items()
将按照第一次出现的顺序给出键、值对。这看起来非常简单,但不幸的是,我无法使用当前(未安装在我使用的集群中)的
pandas
,不过我肯定会检查这个包。非常感谢。