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
,不过我肯定会检查这个包。非常感谢。