Python3 - 如果另一个列表中的值足够接近,则对一个列表中的值取平均值
Python3 - Averaging values in one list if values in another list are sufficiently close
以两个示例列表(或数组)为例:
J = [1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0]
B = [0.7, 0.8, 0.9, 6.0, 7.0, 0.5, 0.6, 8.0]
我的最终目标:如果J中的任何元素相同,则应删除重复值,只出现一个。此外,应该对 B 中索引元素的相应元素进行平均,这留下两个可能更小的列表,但没有重复的 J 值。如果没有相同的元素,那么列表当然应该保持不变。对于上面的示例,1.0 被复制了 3 次,因此相应的 B 值(0.7、0.8 和 0.9)应该对所有三个进行平均。同样,4.0 被复制了两次,因此 0.5 和 0.6 应该取平均值。
想要的结果:
J_desired = [1.0, 2.0, 3.0, 4.0, 5.0]
B_desired = [0.8, 6.0, 7.0, 0.55, 8.0]
我尝试了基于 J 中元素之间差异的方法,并研究了 mapping/list 理解。我尝试使用一种方法,将 J 中的不同元素组合在一起,然后将 B 中的相应元素组合在一起,然后对列表中的每个元组进行平均,但我无法理解如何在两者之间进行映射。任何帮助,将不胜感激!这些列表从来都不是很大,但我想不出一种“Pythonic”的方法来解决这个问题。
如果没有重复,或者元素也适用于更大的列表,任何方法都应该没问题,例如:
J = [1.0, 1.0, 1.0, 0.25860967184801387, 0.17227115716753025, 0.17227115716753025, 0.17227115716753025, 0.13078583765112264, 0.10352331606217618, 0.0835587219343696, 0.0835587219343696, 0.0835587219343696, 0.06857858376511226, 0.06857858376511226]
B = [0.0, 0.03622632071144814, 0.07245264142289629, 3.550179423214222, 6.194700815988386, 6.230927136338296, 6.267153456688205, 8.875448558035552, 11.519969979732812, 14.092038724576383, 14.128265044926295, 14.164491365276204, 16.700333825923735, 16.736560146273646]
如果 J 未排序,此方法有效,但丢失初始顺序是它们已排序(将为 python3.6+ 保留顺序)。
from collections import defaultdict
result = defaultdict(list)
for i_j, i_b in zip(j, b):
result[i_j].append(i_b)
new_j = list(result.keys())
new_b = [sum(result[i_j]) / len(result[i_j]) for i_j in new_j]
由于每个 J 值对应于 B,它看起来很像键值关系或换句话说 dict
。 J 可能有重复的事实仅意味着现在每个 J 值有多个 B 值。所以我们需要收集每个 J 的所有 B。为此,我使用了 defaultdict(list)
- 如果一个键不在字典中,它会将它的默认值设置为空列表,这消除了手动检查的开销如果结果中存在键,如果不存在,则将其设置为空列表。
剩下的很简单:迭代键值对并收集数据。一旦完成,我们就有了每个 J 的所有 B 的字典。将它们转换为列表并获得平均值是微不足道的。
您可以将 groupby
与其他一些功能一起使用,最后从 J
中删除重复项
from itertools import groupby
from operator import itemgetter
j = [1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0]
b = [0.7, 0.8, 0.9, 6.0, 7.0, 0.5, 0.6, 8.0]
b_desired = [sum(i)/len(i) for i in [list(list(zip(*g))[1]) for k, g in groupby(zip(j, b), itemgetter(0))]]
j_desired = list(dict.fromkeys(j))
输出
print(j_desired)
print([round(i, 2) for i in b_desired]) #you could just print B but this looks a little cleaner for output
[1.0, 2.0, 3.0, 4.0, 5.0]
[0.8, 6.0, 7.0, 0.55, 8.0]
那么,这是怎么回事?
好吧,我假设你在最初的理解上有问题,所以让我们来看看吧!
首先分析一下groupby
是干什么的。 Groupby 在与 itemgetter 结合使用时非常有用(如果您不知道 itemgetter 是什么,请阅读有关此 here 的文档,它非常有用!)
Groupby 将使用键对嵌套 list/tuple 类结构的元素进行分组(这就是我们使用 itemgetter() 运算符的原因)
for k, g in groupby(zip(j, b), itemgetter(0)):
print(list(zip(*g)))
[(1.0, 1.0, 1.0), (0.7, 0.8, 0.9)]
[(2.0,), (6.0,)]
[(3.0,), (7.0,)]
[(4.0, 4.0), (0.5, 0.6)]
[(5.0,), (8.0,)]
如您所见,所有元素都分组到元组列表中;第一个元组是第一个元素(正在分组),第二个元素是 zip
中分组值的对应对
由此我们在迭代k,g时继续调用
list(list(zip(*g))[1]
该组的 returns 对值!
这不使用进口,是一种 'pythonic' 方式。
J = [1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0]
B = [0.7, 0.8, 0.9, 6.0, 7.0, 0.5, 0.6, 8.0]
average_list = [round(sum([(B[index]) for index in [i for i, x in enumerate(J) if x == a]])/len([i for i, x in enumerate(J) if x == a]),2) for a in set(J)]
print(set(J))
print(average_list)
>>> {1.0, 2.0, 3.0, 4.0, 5.0}
>>> [0.8, 6.0, 7.0, 0.55, 8.0]
我正在做的是:
第 1 步:
首先我得到一个非重复列表Jfor a in set(J)
第 2 步: 然后我遍历此列表并获取重复列表(列表 J)中重复的每个数字的所有索引 i for i, x in enumerate(J) if x == a]]
例如对于 1.0,索引将是 0,1,2
注意我现在已经创建了一个索引列表
第 3 步:
请注意,我仍在第 2 步的第一次迭代中,在这个新的索引列表中,我获得了列表 B 的所有匹配索引元素,因此对于 1.0
,索引是 0,1,2
因此列表 B 中的匹配索引元素将是 0.7,0.8,0.9
步骤 4: 我现在得到匹配索引元素列表的总和 sum([(B[index]) for index in [i for i, x in enumerate(J) if x == a]])
,
然后除以同一个列表的长度,即
len([i for i, x in enumerate(J) if x == a]),2)
,
所以总体来说是 (sum([(B[index]) for index in [i for i, x in enumerate(J) if x == a]])/len([i for i, x in enumerate(J) if x == a]))
第 5 步: 现在我有了这个总和,然后我将它四舍五入,因为我得到了一些数字的小数点后 7 位。[round(sum([(B[index]) for index in [i for i, x in enumerate(J) if x == a]])/len([i for i, x in enumerate(J) if x == a]),2)
,2
只是将它四舍五入到小数点后两位,你可以把它变成任何你想要的数字。
因此 步骤 1 到 5 重复 中的迭代]步骤 1
还要注意,每次看到 []
中包含的代码时,这意味着里面的所有代码都生成了一个列表(除了 B[index]
只是从列表中获取一个元素,所以通常列表 average_list
生成了大约 4 个列表,它们都被迭代了。
希望对您有所帮助,如有任何疑问,请随时提出。
编辑:
如果你想将它用于未排序的列表,请执行:
average_list = [round(sum([B[index] for index in [i for i, x in enumerate(sorted(B)) if x == a]])/len([i for i, x in enumerate(sorted(B)) if x == a]),2) for a in set(J)]
我加了两个sorted
关键词,这样列表就可以排序了
以两个示例列表(或数组)为例:
J = [1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0]
B = [0.7, 0.8, 0.9, 6.0, 7.0, 0.5, 0.6, 8.0]
我的最终目标:如果J中的任何元素相同,则应删除重复值,只出现一个。此外,应该对 B 中索引元素的相应元素进行平均,这留下两个可能更小的列表,但没有重复的 J 值。如果没有相同的元素,那么列表当然应该保持不变。对于上面的示例,1.0 被复制了 3 次,因此相应的 B 值(0.7、0.8 和 0.9)应该对所有三个进行平均。同样,4.0 被复制了两次,因此 0.5 和 0.6 应该取平均值。
想要的结果:
J_desired = [1.0, 2.0, 3.0, 4.0, 5.0]
B_desired = [0.8, 6.0, 7.0, 0.55, 8.0]
我尝试了基于 J 中元素之间差异的方法,并研究了 mapping/list 理解。我尝试使用一种方法,将 J 中的不同元素组合在一起,然后将 B 中的相应元素组合在一起,然后对列表中的每个元组进行平均,但我无法理解如何在两者之间进行映射。任何帮助,将不胜感激!这些列表从来都不是很大,但我想不出一种“Pythonic”的方法来解决这个问题。
如果没有重复,或者元素也适用于更大的列表,任何方法都应该没问题,例如:
J = [1.0, 1.0, 1.0, 0.25860967184801387, 0.17227115716753025, 0.17227115716753025, 0.17227115716753025, 0.13078583765112264, 0.10352331606217618, 0.0835587219343696, 0.0835587219343696, 0.0835587219343696, 0.06857858376511226, 0.06857858376511226]
B = [0.0, 0.03622632071144814, 0.07245264142289629, 3.550179423214222, 6.194700815988386, 6.230927136338296, 6.267153456688205, 8.875448558035552, 11.519969979732812, 14.092038724576383, 14.128265044926295, 14.164491365276204, 16.700333825923735, 16.736560146273646]
如果 J 未排序,此方法有效,但丢失初始顺序是它们已排序(将为 python3.6+ 保留顺序)。
from collections import defaultdict
result = defaultdict(list)
for i_j, i_b in zip(j, b):
result[i_j].append(i_b)
new_j = list(result.keys())
new_b = [sum(result[i_j]) / len(result[i_j]) for i_j in new_j]
由于每个 J 值对应于 B,它看起来很像键值关系或换句话说 dict
。 J 可能有重复的事实仅意味着现在每个 J 值有多个 B 值。所以我们需要收集每个 J 的所有 B。为此,我使用了 defaultdict(list)
- 如果一个键不在字典中,它会将它的默认值设置为空列表,这消除了手动检查的开销如果结果中存在键,如果不存在,则将其设置为空列表。
剩下的很简单:迭代键值对并收集数据。一旦完成,我们就有了每个 J 的所有 B 的字典。将它们转换为列表并获得平均值是微不足道的。
您可以将 groupby
与其他一些功能一起使用,最后从 J
from itertools import groupby
from operator import itemgetter
j = [1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0]
b = [0.7, 0.8, 0.9, 6.0, 7.0, 0.5, 0.6, 8.0]
b_desired = [sum(i)/len(i) for i in [list(list(zip(*g))[1]) for k, g in groupby(zip(j, b), itemgetter(0))]]
j_desired = list(dict.fromkeys(j))
输出
print(j_desired)
print([round(i, 2) for i in b_desired]) #you could just print B but this looks a little cleaner for output
[1.0, 2.0, 3.0, 4.0, 5.0]
[0.8, 6.0, 7.0, 0.55, 8.0]
那么,这是怎么回事?
好吧,我假设你在最初的理解上有问题,所以让我们来看看吧!
首先分析一下groupby
是干什么的。 Groupby 在与 itemgetter 结合使用时非常有用(如果您不知道 itemgetter 是什么,请阅读有关此 here 的文档,它非常有用!)
Groupby 将使用键对嵌套 list/tuple 类结构的元素进行分组(这就是我们使用 itemgetter() 运算符的原因)
for k, g in groupby(zip(j, b), itemgetter(0)):
print(list(zip(*g)))
[(1.0, 1.0, 1.0), (0.7, 0.8, 0.9)]
[(2.0,), (6.0,)]
[(3.0,), (7.0,)]
[(4.0, 4.0), (0.5, 0.6)]
[(5.0,), (8.0,)]
如您所见,所有元素都分组到元组列表中;第一个元组是第一个元素(正在分组),第二个元素是 zip
由此我们在迭代k,g时继续调用
list(list(zip(*g))[1]
该组的 returns 对值!
这不使用进口,是一种 'pythonic' 方式。
J = [1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0]
B = [0.7, 0.8, 0.9, 6.0, 7.0, 0.5, 0.6, 8.0]
average_list = [round(sum([(B[index]) for index in [i for i, x in enumerate(J) if x == a]])/len([i for i, x in enumerate(J) if x == a]),2) for a in set(J)]
print(set(J))
print(average_list)
>>> {1.0, 2.0, 3.0, 4.0, 5.0}
>>> [0.8, 6.0, 7.0, 0.55, 8.0]
我正在做的是:
第 1 步:
首先我得到一个非重复列表Jfor a in set(J)
第 2 步: 然后我遍历此列表并获取重复列表(列表 J)中重复的每个数字的所有索引 i for i, x in enumerate(J) if x == a]]
例如对于 1.0,索引将是 0,1,2
注意我现在已经创建了一个索引列表
第 3 步:
请注意,我仍在第 2 步的第一次迭代中,在这个新的索引列表中,我获得了列表 B 的所有匹配索引元素,因此对于 1.0
,索引是 0,1,2
因此列表 B 中的匹配索引元素将是 0.7,0.8,0.9
步骤 4: 我现在得到匹配索引元素列表的总和 sum([(B[index]) for index in [i for i, x in enumerate(J) if x == a]])
,
然后除以同一个列表的长度,即
len([i for i, x in enumerate(J) if x == a]),2)
,
所以总体来说是 (sum([(B[index]) for index in [i for i, x in enumerate(J) if x == a]])/len([i for i, x in enumerate(J) if x == a]))
第 5 步: 现在我有了这个总和,然后我将它四舍五入,因为我得到了一些数字的小数点后 7 位。[round(sum([(B[index]) for index in [i for i, x in enumerate(J) if x == a]])/len([i for i, x in enumerate(J) if x == a]),2)
,2
只是将它四舍五入到小数点后两位,你可以把它变成任何你想要的数字。
因此 步骤 1 到 5 重复 中的迭代]步骤 1
还要注意,每次看到 []
中包含的代码时,这意味着里面的所有代码都生成了一个列表(除了 B[index]
只是从列表中获取一个元素,所以通常列表 average_list
生成了大约 4 个列表,它们都被迭代了。
希望对您有所帮助,如有任何疑问,请随时提出。
编辑:
如果你想将它用于未排序的列表,请执行:
average_list = [round(sum([B[index] for index in [i for i, x in enumerate(sorted(B)) if x == a]])/len([i for i, x in enumerate(sorted(B)) if x == a]),2) for a in set(J)]
我加了两个sorted
关键词,这样列表就可以排序了