【问题标题】:Convert Average of Python List Values to Another List将 Python 列表值的平均值转换为另一个列表
【发布时间】:2014-03-06 02:51:58
【问题描述】:

我有这样的清单。

list = [["Joe", 5, 7], ["Joe", 6, 9], ["Mike", 1,4], ["Joe", 7,4], ["Mike", 5,7]]

如何将此列表转换为这样的列表:

list2 = [["Joe", 6.00, 6.66], ["Mike", 3.00, 5.50]]

list2[0][1] 和 list2[1][1] 是第一个列表中特定人群的平均值(6.00 来自(list[0][1]+list[1][1]+list[3][1])/3

我应该像这样使用迭代:

for i in range(len(list)):
...

或者..类似的东西?因为我是从 SQLite 导入列表,而列表总是在变化。

【问题讨论】:

    标签: python list python-2.7 python-3.x iteration


    【解决方案1】:

    类似这样的:

    >>> from collections import OrderedDict
    >>> lis = [["Joe", 5, 7], ["Joe", 6, 9], ["Mike", 1,4], ["Joe", 7,4], ["Mike", 5,7]]
    >>> d = OrderedDict()
    >>> for item in lis:
    ...     d.setdefault(item[0], []).append(item[1:])
    

    现在d 包含:

    >>> d
    OrderedDict([('Joe', [[5, 7], [6, 9], [7, 4]]), ('Mike', [[1, 4], [5, 7]])])
    

    我们在这里使用了OrderedDict,所以这里保留了曾经见过的唯一键的有序排列。

    现在我们可以遍历这个字典并获得每个键的列的平均值。 zip* 让我们可以很容易地得到一个列表的转置:

    >>> zip(*[[5, 7], [6, 9], [7, 4]])
    [(5, 6, 7), (7, 9, 4)]
    >>> 
    

    最终列表理解:

    >>> [[k] + [sum(x)/float(len(x)) for x in zip(*v)] for k, v in d.items()]
    [['Joe', 6.0, 6.666666666666667], ['Mike', 3.0, 5.5]]
    

    您可以在 Python3 中删除 float 调用。如果名称 'Joe'、'Mike' 在输出列表中的顺序无关紧要,那么您可以简单地使用带有dict.setdefault 的普通字典或使用collections.defaultdict

    【讨论】:

      【解决方案2】:

      使用itertools.groupby

      >>> from itertools import groupby
      >>> data = [["Joe", 5, 7], ["Joe", 6, 9], ["Mike", 1, 4], ["Joe", 7, 4], ["Mike", 5, 7]]
      >>> data.sort()
      >>> result = []
      >>> for _, groups in groupby(d, lambda x: x[0]):
              it = iter(zip(*groups))
              row = [next(it)[0]]
              for values in it:
                  row.append(sum(values) / len(values))
              result.append(row)
      
      >>> result
      [['Joe', 6.0, 6.666666666666667], ['Mike', 3.0, 5.5]]
      

      【讨论】:

        【解决方案3】:

        既然你说你是从 sqlite 导入列表,你可能有兴趣使用现有的数据处理包,而不是逐个函数滚动你自己的函数。例如,在pandas 中,您可以将数据加载到DataFrame

        >>> df = pd.DataFrame(yourlist)
        >>> df
              0  1  2
        0   Joe  5  7
        1   Joe  6  9
        2  Mike  1  4
        3   Joe  7  4
        4  Mike  5  7
        
        [5 rows x 3 columns]
        >>> df.groupby(0).mean()
              1         2
        0                
        Joe   6  6.666667
        Mike  3  5.500000
        
        [2 rows x 2 columns]
        

        现在使用pandas 单独解决问题会显得过于矫枉过正,但如果您从数据库中提取数据,您可能需要对数据执行多项操作。

        【讨论】:

        • 这绝对看起来不错。 +1
        【解决方案4】:

        这适用于您要求和的任意数量的值(在您的情况下为两个):

        Python 3

        from collections import defaultdict
        
        rows = [["Joe", 5, 7], ["Joe", 6, 9], ["Mike", 1,4], ["Joe", 7,4], ["Mike", 5,7]]
        
        d = defaultdict(list)
        for k, *v in rows:
            d[k].append(v)
        
        averages = [[k] + [sum(x) / len(v) for x in zip(*v)] for k, v in d.items()]
        print(averages)
        

        Python 2

        items() 替换为iteritems(),在sum(x) 周围添加float,使用空格而不是括号使用print,并将for 循环更改为

        for row in rows:
           d[row[0]].append(row[1:])
        

        (Python 3 肯定不错。)


        说明

        defaultdictfor 循环创建从名称到值列表的映射。

        {'Mike': [[1, 4], [5, 7]], 'Joe': [[5, 7], [6, 9], [7, 4]]}
        

        k, v in d.items() 遍历每个名​​称和列表列表。

        zip(*v) 接受[[5, 7], [6, 9], [7, 4]] 之类的内容并将其转换为[[5, 6, 7], [7, 9, 4]]。然后我们将这些相加并除以原始列表的数量。

        我们附加[k] 和这个平均值列表以获得类似['Joe', 6.0, 6.67] 的列表。

        顺便说一句,如果这是来自数据库,您是否考虑过在那里进行聚合?

        【讨论】:

          【解决方案5】:

          另一种解决方案。它有点复杂,但没有进口的单衬里。

          map(lambda x : [x[0],float(x[1])/x[3],float(x[2])/x[3]],reduce(lambda x,y : x[0:(len(x)-1)] + [[x[-1][0],x[-1][1]+y[1],x[-1][2]+y[2],x[-1][3]+1]] if ((y[0] == x[-1][0]) if (len(x)>0)  else False) else x + [[y[0],y[1],y[2],1]] ,arr,[]))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-02-25
            • 2016-06-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-12-04
            • 2019-05-19
            相关资源
            最近更新 更多