按第二个元素对元组列表进行分组,获取第一个元素的平均值。

4

我有一个类似于 (x,y) 的元组列表:

l = [(2,1), (4,6), (3,1), (2,7), (7,10)]

现在我想创建一个新列表:
l = [(2.5,1), (4,6), (2,7), (7,10)]

如果元组中有多个二元组的第二个值(y)相同,则新列表的平均值为元组的第一个值(x)的平均值。

这里,由于对于元组(x,y)=(2,1)和(3,1),元组中的第二个元素y = 1是相同的,因此x = 2和3的平均值在新列表中。 y = 1在其他地方没有出现,因此其他元组保持不变。


为什么你打了pandas的标签,但是却输入了元组列表(而不是数据框)?pandas数据框处理起来更好。原生的Python列表对于处理元组的能力非常有限。 - smci
4个回答

2

Since you tagged pandas:

l = [(2,1), (4,6), (3,1), (2,7), (7,10)]
df = pd.DataFrame(l)

那么df就是一个有两列的数据框:
    0   1
0   2   1
1   4   6
2   3   1
3   2   7
4   7   10

现在您想计算列0中具有相同值的列1中数字的平均值: "最初的回答"
(df.groupby(1).mean()     # compute mean on each group
   .reset_index()[[0,1]]  # restore the column order
   .values                # return the underlying numpy array
 )

输出:

array([[ 2.5,  1. ],
       [ 4. ,  6. ],
       [ 2. ,  7. ],
       [ 7. , 10. ]])

你能解释一下这段代码正在做什么吗?我对 pandas 不太熟悉。 - ubuntu_noob
“[[0,1]]”是做什么的?我知道它可以颠倒列的顺序,但是它是如何实现的呢? - ubuntu_noob
没有它,数据将显示为“列1,列0”。 - Quang Hoang
是的,我知道那个。我在问它是如何发生的?它是如何反转的? - ubuntu_noob
@QuangHoang:抱歉,我是个白痴,.reset_index() 是正确的(我把 pandas 和 R 混淆了)。但我想知道 [0,1] 是否可以避免。 - smci
显示剩余5条评论

0
首先,将所有第二个元素作为键(key),它们对应的值(value)作为值(value)列表形式构建一个哈希表/字典。然后使用列表推导式(listcomp)通过迭代字典的项来获取所需的输出结果。
from collections import defaultdict
out = defaultdict(list)
for i in l:
    out[i[1]] += [i[0]]
out = [(sum(v)/len(v), k) for k, v in out.items()]
print(out)
#prints [(2.5, 1), (4.0, 6), (2.0, 7), (7.0, 10)]

0

使用 groupby 的另一种方法:

from itertools import groupby

# Sort list by the second element
sorted_list = sorted(l,key=lambda x:x[1])

# Group by second element
grouped_list = groupby(sorted_list, key=lambda x:x[1])

result = []
for _,group in grouped_list:
    x,y = list(zip(*group))
    # Take the mean of the first elements
    result.append((sum(x) / len(x),y[0]))

你将获得:

[(2.5, 1), (4.0, 6), (2.0, 7), (7.0, 10)]

for _,group in groupby(...) 几乎总是可以避免且是一种不好的惯用语。在大型数据框上性能更差。 - smci
从来没有听说过这个。你有任何的帖子/参考资料吗? - Nakor

0
这里有一种使用 numpy.bincount 的方法。它依赖于标签是非负整数。(如果不是这种情况,可以先执行 np.unique(i, return_inverse=True))。
w,i = zip(*l)
n,d = np.bincount(i,w), np.bincount(i)
v, = np.where(d)
[*zip(n[v]/d[v],v)]
# [(2.5, 1), (4.0, 6), (2.0, 7), (7.0, 10)]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接