【问题标题】:Group list-of-tuples by second element, take average of first element按第二个元素对元组列表进行分组,取第一个元素的平均值
【发布时间】:2019-11-25 18:48:29
【问题描述】:

我有一个元组 (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 Dataframe 效果更好。原生 Python 列表处理元组的能力非常有限。

标签: python python-3.x pandas numpy pandas-groupby


【解决方案1】:

既然你标记了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. ]])

【讨论】:

  • 你能解释一下代码中发生了什么吗?...我是熊猫的新手
  • 当然,请参阅更新。如果您仍然觉得难以理解,我建议将链命令和打印输出分开。
  • [[0,1]] 在做什么?我知道它颠倒了列的顺序,但它是如何做到的?
  • 没有它,数据将显示为column 1, column 0
  • 是的,我知道..我在问这是怎么回事?怎么反转?
【解决方案2】:

首先形成一个哈希表/字典,所有第二个元素作为键,它们对应的值作为值列表。然后使用 listcomp,您可以通过迭代 dict 的项目来获得所需的输出。

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)]

【讨论】:

    【解决方案3】:

    使用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(...) 几乎总是可以避免的,而且总是不好的成语。在大型数据帧上的性能也更差。
    • 从未听说过。您对此有任何帖子/参考吗?
    【解决方案4】:

    这是使用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)]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-16
      • 1970-01-01
      • 1970-01-01
      • 2012-03-08
      • 2022-08-18
      • 2012-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多