如何有效地获取 Python 中两个列表列表中元素的平均值
How to efficiently get the mean of the elements in two list of lists in Python
我有两个列表如下。
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
我想得到两个列表中共同元素的平均值,如下所示。
myoutput = [["chocolate", 0.5], ["egg", 0.45]]
我现在的代码如下
for item1 in mylist1:
for item2 in mylist2:
if item1[0] == item2[0]:
print(np.mean([item1[1], item2[1]]))
但是,由于有两个 for
循环(O(n^2)
复杂度),这对于非常长的列表来说效率非常低。我想知道在 Python.
中是否有更多 standard/efficient 方法可以做到这一点
您可以在 O(n) 中完成此操作(单次遍历每个列表),方法是将 1 转换为字典,然后第二个列表中的每个项目访问该字典(在 O(1) 中),如下所示:
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
l1_as_dict = dict(mylist1)
myoutput = []
for item,price2 in mylist2:
if item in l1_as_dict:
price1 = l1_as_dict[item]
myoutput.append([item, (price1+price2)/2])
print(myoutput)
输出:
[['chocolate', 0.5], ['egg', 0.45]]
为了轻松操纵您的值,我建议使用 dict
,找到常用键并计算平均值:
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
recipe_1 = dict(mylist1) # {'lemon': 0.1, 'egg': 0.1, 'muffin': 0.3, 'chocolate': 0.5}
recipe_2 = dict(mylist2) # {'chocolate': 0.5, 'milk': 0.2, 'carrot': 0.8, 'egg': 0.8}
common_keys = recipe_1.keys() & recipe_2.keys() # {'chocolate', 'egg'}
myoutput = [[item, np.mean((recipe_1[item], recipe_2[item]))] for item in common_keys]
myoutput = [[item, (recipe_1[item] + recipe_2[item]) / 2] for item in common_keys]
一个 O(n)
解决方案,将对所有项目进行平均。
构建一个包含值列表的字典,然后对该字典进行平均:
In []:
d = {}
for lst in (mylist1, mylist2):
for i, v in lst:
d.setdefault(i, []).append(v) # alternative use collections.defaultdict
[(k, sum(v)/len(v)) for k, v in d.items()]
Out[]:
[('lemon', 0.1), ('egg', 0.45), ('muffin', 0.3), ('chocolate', 0.5), ('milk', 0.2), ('carrot', 0.8)]
那么如果你只想要普通的可以加一个守卫:
In []:
[(k, sum(v)/len(v)) for k, v in d.items() if len(v) > 1]
Out[]:
[('egg', 0.45), ('chocolate', 0.5)]
这扩展到任意数量的列表,并且不对公共元素的数量做出任何假设。
将列表转换为字典
d_list1 = dict(mylist1)
d_list2 = dict(mylist2)
[[k, (v+d_list2[k])/2] for k, v in d_list1.items() if k in d_list2]
#[['egg', 0.45], ['chocolate', 0.5]]
您使用 set
intersection
方法从两个列表中获取公共键,然后使用列表理解计算平均值:
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
dict1 = dict(mylist1)
dict2 = dict(mylist2)
res = [[key, (dict1.get(key)+dict2.get(key))/2] for key in set(dict1.keys()).intersection(set(dict2.keys()))]
print(res)
输出:
>> [['chocolate', 0.5], ['egg', 0.45]]
你可以在通勤集路口所需的时间内做到这一点,显然是 O(min(N1,N2)) 其中 N1, N2 是列表长度。
intersect = set([a[0] for a in mylist1]).intersection([a[0] for a in mylist2])
d1=dict(mylist1)
d2=dict(mylist2)
{i:(d1[i]+d2[i])/2 for i in intersect}
您可以使用 Pandas 库来避免自己编写任何类型的循环。
你的代码会非常简洁明了。
安装 Pandas 如:pip install pandas
.
然后试试这个:
In [132]: import pandas as pd
In [109]: df1 = pd.DataFrame(mylist1)
In [110]: df2 = pd.DataFrame(mylist2)
In [117]: res = pd.merge(df1, df2, on=0)
In [121]: res['mean'] = res.mean(axis=1)
In [125]: res.drop(['1_x', '1_y'], 1, inplace=True)
In [131]: res.values.tolist()
Out[131]: [['egg', 0.45], ['chocolate', 0.5]]
编辑
Pandas 非常快,因为它在后台使用 numpy
。 Numpy 实现了高效的数组操作。
请查看 post : 以获取有关通过 pure Python vs Pandas
.
计算 mean
的更多详细信息
这是一种使用 collections.defaultdict
to group the items and calculates the averages with statistics.mean
的解决方案:
from collections import defaultdict
from statistics import mean
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
d = defaultdict(list)
for lst in (mylist1, mylist2):
for k, v in lst:
d[k].append(v)
result = [[k, mean(v)] for k, v in d.items()]
print(result)
# [['lemon', 0.1], ['egg', 0.45], ['muffin', 0.3], ['chocolate', 0.5], ['milk', 0.2], ['carrot', 0.8]]
如果我们只想要公共键,只要检查值是否大于 1:
result = [[k, mean(v)] for k, v in d.items() if len(v) > 1]
print(result)
# [['egg', 0.45], ['chocolate', 0.5]]
我们也可以只从集合交集构建结果:
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
d1, d2 = dict(mylist1), dict(mylist2)
result = [[k, (d1[k] + d2[k]) / 2] for k in d1.keys() & d2.keys()]
print(result)
# [['egg', 0.45], ['chocolate', 0.5]]
这是一个简单、非常 Pythonic 的解决方案:
result = [[x[0], (x[1] + y[1])/2] for x in mylist1 for y in mylist2 if x[0] == y[0]]
它可能不是 最快的解决方案,但由于使用 Python 列表理解来迭代列表,它更快,因为无论是这个解决方案还是OP 将使用列表键值的多个实例,它将 np.mean 替换为两个值的简单平均值。
我有两个列表如下。
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
我想得到两个列表中共同元素的平均值,如下所示。
myoutput = [["chocolate", 0.5], ["egg", 0.45]]
我现在的代码如下
for item1 in mylist1:
for item2 in mylist2:
if item1[0] == item2[0]:
print(np.mean([item1[1], item2[1]]))
但是,由于有两个 for
循环(O(n^2)
复杂度),这对于非常长的列表来说效率非常低。我想知道在 Python.
您可以在 O(n) 中完成此操作(单次遍历每个列表),方法是将 1 转换为字典,然后第二个列表中的每个项目访问该字典(在 O(1) 中),如下所示:
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
l1_as_dict = dict(mylist1)
myoutput = []
for item,price2 in mylist2:
if item in l1_as_dict:
price1 = l1_as_dict[item]
myoutput.append([item, (price1+price2)/2])
print(myoutput)
输出:
[['chocolate', 0.5], ['egg', 0.45]]
为了轻松操纵您的值,我建议使用 dict
,找到常用键并计算平均值:
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
recipe_1 = dict(mylist1) # {'lemon': 0.1, 'egg': 0.1, 'muffin': 0.3, 'chocolate': 0.5}
recipe_2 = dict(mylist2) # {'chocolate': 0.5, 'milk': 0.2, 'carrot': 0.8, 'egg': 0.8}
common_keys = recipe_1.keys() & recipe_2.keys() # {'chocolate', 'egg'}
myoutput = [[item, np.mean((recipe_1[item], recipe_2[item]))] for item in common_keys]
myoutput = [[item, (recipe_1[item] + recipe_2[item]) / 2] for item in common_keys]
一个 O(n)
解决方案,将对所有项目进行平均。
构建一个包含值列表的字典,然后对该字典进行平均:
In []:
d = {}
for lst in (mylist1, mylist2):
for i, v in lst:
d.setdefault(i, []).append(v) # alternative use collections.defaultdict
[(k, sum(v)/len(v)) for k, v in d.items()]
Out[]:
[('lemon', 0.1), ('egg', 0.45), ('muffin', 0.3), ('chocolate', 0.5), ('milk', 0.2), ('carrot', 0.8)]
那么如果你只想要普通的可以加一个守卫:
In []:
[(k, sum(v)/len(v)) for k, v in d.items() if len(v) > 1]
Out[]:
[('egg', 0.45), ('chocolate', 0.5)]
这扩展到任意数量的列表,并且不对公共元素的数量做出任何假设。
将列表转换为字典
d_list1 = dict(mylist1)
d_list2 = dict(mylist2)
[[k, (v+d_list2[k])/2] for k, v in d_list1.items() if k in d_list2]
#[['egg', 0.45], ['chocolate', 0.5]]
您使用 set
intersection
方法从两个列表中获取公共键,然后使用列表理解计算平均值:
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
dict1 = dict(mylist1)
dict2 = dict(mylist2)
res = [[key, (dict1.get(key)+dict2.get(key))/2] for key in set(dict1.keys()).intersection(set(dict2.keys()))]
print(res)
输出:
>> [['chocolate', 0.5], ['egg', 0.45]]
你可以在通勤集路口所需的时间内做到这一点,显然是 O(min(N1,N2)) 其中 N1, N2 是列表长度。
intersect = set([a[0] for a in mylist1]).intersection([a[0] for a in mylist2])
d1=dict(mylist1)
d2=dict(mylist2)
{i:(d1[i]+d2[i])/2 for i in intersect}
您可以使用 Pandas 库来避免自己编写任何类型的循环。
你的代码会非常简洁明了。
安装 Pandas 如:pip install pandas
.
然后试试这个:
In [132]: import pandas as pd
In [109]: df1 = pd.DataFrame(mylist1)
In [110]: df2 = pd.DataFrame(mylist2)
In [117]: res = pd.merge(df1, df2, on=0)
In [121]: res['mean'] = res.mean(axis=1)
In [125]: res.drop(['1_x', '1_y'], 1, inplace=True)
In [131]: res.values.tolist()
Out[131]: [['egg', 0.45], ['chocolate', 0.5]]
编辑
Pandas 非常快,因为它在后台使用 numpy
。 Numpy 实现了高效的数组操作。
请查看 post : pure Python vs Pandas
.
mean
的更多详细信息
这是一种使用 collections.defaultdict
to group the items and calculates the averages with statistics.mean
的解决方案:
from collections import defaultdict
from statistics import mean
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
d = defaultdict(list)
for lst in (mylist1, mylist2):
for k, v in lst:
d[k].append(v)
result = [[k, mean(v)] for k, v in d.items()]
print(result)
# [['lemon', 0.1], ['egg', 0.45], ['muffin', 0.3], ['chocolate', 0.5], ['milk', 0.2], ['carrot', 0.8]]
如果我们只想要公共键,只要检查值是否大于 1:
result = [[k, mean(v)] for k, v in d.items() if len(v) > 1]
print(result)
# [['egg', 0.45], ['chocolate', 0.5]]
我们也可以只从集合交集构建结果:
mylist1 = [["lemon", 0.1], ["egg", 0.1], ["muffin", 0.3], ["chocolate", 0.5]]
mylist2 = [["chocolate", 0.5], ["milk", 0.2], ["carrot", 0.8], ["egg", 0.8]]
d1, d2 = dict(mylist1), dict(mylist2)
result = [[k, (d1[k] + d2[k]) / 2] for k in d1.keys() & d2.keys()]
print(result)
# [['egg', 0.45], ['chocolate', 0.5]]
这是一个简单、非常 Pythonic 的解决方案:
result = [[x[0], (x[1] + y[1])/2] for x in mylist1 for y in mylist2 if x[0] == y[0]]
它可能不是 最快的解决方案,但由于使用 Python 列表理解来迭代列表,它更快,因为无论是这个解决方案还是OP 将使用列表键值的多个实例,它将 np.mean 替换为两个值的简单平均值。