【问题标题】:A loop that makes multi-conditional summations进行多条件求和的循环
【发布时间】:2022-01-20 22:22:16
【问题描述】:

我有一个表单的数据框:

df = [["john","2019","30.2"] , ["john","2019","40"] , ["john","2020","50.3"] , 
      ["amy","2019","60"] , ["amy","2019","20"] , ["amy","2020","40.1"]]

我想要的结果是最后一个索引的多条件总和列表,而前两个索引相等:

> [["john", "2019", "70.2"] ,  ["john","2020","50.3"] , ["amy","2019","80"] , ["amy","2020","40.1"]]

我尝试做的是一个 for 循环,它检查每个条件的相等性,然后总结最后一个索引,如果条件为真 - 这是某种伪代码:

for i in df[i]:
   if df[i][0] == df[i+1][0] and df[i][1] == df[i+1][1]: #if both conditions are true
      sum1 = sum(float(df[i][2]))
      lst = []
      lst.append(df[i][0])
      lst.append(df[i][1])
      lst.append(str(sum1))

编辑:希望有一个不使用包的解决方案。

【问题讨论】:

  • 还有数据吗?如果是,它们的格式是否相同——“姓名、年份、第三个索引”?

标签: python pandas dataframe loops


【解决方案1】:

以下代码不使用任何包。从Python 3.7开始,所有的dicts都是insertion-ordered,这个事实用在下面的代码中,这样最终结果就具有元素原始外观的顺序。如果由于某种原因您的 python 低于3.7,请告诉我,我将修改代码以显式进行排序,而不是依赖此语言功能。

Try it online!

df = [["john","2019","30.2"], ["john","2019","40"], ["john","2020","50.3"],
      ["amy","2019","60"], ["amy","2019","20"], ["amy","2020","40.1"]]

r = {}
for *a, b in df:
    a = tuple(a)
    if a not in r:
       r[a] = 0
    r[a] += float(b)
r = [list(k) + [str(v)] for k, v in r.items()]

print(r)

输出:

[['john', '2019', '70.2'], ['john', '2020', '50.3'], ['amy', '2019', '80.0'], ['amy', '2020', '40.1']]

【讨论】:

    【解决方案2】:

    由于您使用的是 df 变量名,因此我假设您熟悉 pandas。

    您可以在 pandas 中轻松做到这一点。只需将您的列表转换为 df。

    以及您想要唯一值的 groupby 列并选择最后一行

    df.groupby(['col_a', 'col_b'], as_index=False).last()
    

    如果您有任何自定义逻辑,您可以在调用 groupby 之前对 df 进行排序

    【讨论】:

    • 非常感谢,但是有没有什么办法可以不用包呢?
    【解决方案3】:

    这是一种使用defaultdict的方法:

    from collections import defaultdict
    sums = defaultdict(lambda: defaultdict(float))
    for item in df:
        sums[item[0]][item[1]] += float(item[2])
    lst = [[key, inner_key, value] for key in sums for inner_key, value in sums[key].items()]
    

    【讨论】:

      【解决方案4】:

      一个选项,使用标准库中的工具:

      from itertools import groupby
      from decimal import Decimal
      from operator import itemgetter
      
      # itertools' groupby requires the data to be sorted
      key_func = itemgetter(0,1)
      df = sorted(df, key = key_func)
      
      # compute values within the groupby
      [[*key, str(sum(Decimal(e) for *_, e in ent))] 
        for key, ent 
        in groupby(df, key = key_func)]
      
      [['amy', '2019', '80'],
       ['amy', '2020', '40.1'],
       ['john', '2019', '70.2'],
       ['john', '2020', '50.3']]
      

      【讨论】:

        【解决方案5】:

        字典有方便的setdefault 方法,它检查它的第一个参数是否是字典的键,并返回相应的值或默认值。

        在我们的例子中,因为我们要对数值求和,当然默认必须是0。

        我们使用由元组 (name, year) 索引的临时字典,当我们完成求和后,我们按照您在问题伪代码中显示的方向将字典数据展开到列表列表中。

        In [15]: data = [["john","2019","30.2"] , ["john","2019","40"] , ["john","2020","50.3"] ,
            ...:         ["amy","2019","60"] , ["amy","2019","20"] , ["amy","2020","40.1"]]
            ...: d_temp = {}
            ...: for n, y, v in data:
            ...:     d_temp[(n,y)] = d_temp.setdefault((n,y),0)+float(v)
            ...: lol = [[n, y, v] for (n, y), v in d_temp.items()]
            ...: lol
        Out[15]: 
        [['john', '2019', 70.2],
         ['john', '2020', 50.3],
         ['amy', '2019', 80.0],
         ['amy', '2020', 40.1]]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-09-02
          • 2017-12-27
          • 2018-06-18
          • 2015-05-23
          • 2017-12-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多