【问题标题】:Extracting values from list of dicts to be used in calculation从要用于计算的字典列表中提取值
【发布时间】:2018-04-11 19:23:30
【问题描述】:

我的输入数据是一个 dicts 列表 (matches),其中每个 dict 有 2 个可能的位置来显示记录,以及两者及其各自数据源之间的相关因素:

[
  { 'r1': record_1, 'r2': record_2, corr: 85, 'r1_source': source_1, 'r2_source': source_2 },
  { 'r1': record_1, 'r2': record_3, corr: 90, 'r1_source': source_1, 'r2_source': source_3 },
  { 'r1': record_2, 'r2': record_3, corr: 77, 'r1_source': source_2, 'r2_source': source_3 },
  ...
]

每个record 都由一个列表表示,该列表来自唯一records 的有限列表。

我想要的输出数据的结构是一个字典列表,其中每个唯一的record 都有自己、它的来源和它的平均相关因子:

[
  { 'record': record_1, 'source': source_1, 'avg': (85 + 90) / 2 },
  { 'record': record_2, 'source': source_2, 'avg': (85 + 77) / 2 },
  { 'record': record_3, 'source': source_3, 'avg': (90 + 77) / 2 },
]

我目前的解决方案:

def average_record_from_match_value(matches):
    averaged_recs = []

    for match in matches:
        # Q1 
        if [rec for rec in averaged_recs if rec['record'] == match['r1']] == []:
            a_recs = []
            # Q2
            a_recs.extend([m['corr'] for m in matches if m['r1'] == match['r1']])
            a_recs.extend([m['corr'] for m in matches if m['r2'] == match['r1']])
            # Q3
            r1_value = sum(a_recs) / len(a_recs)
            averaged_recs.append({ 'record': match['r1'],
                                   'source': match['r1_source'],
                                   'match_value': r1_value,
                                   'record_value': r1_value})
        if [rec for rec in averaged_recs if rec['record'] == match['r2']] == []:
            b_recs = []
            b_recs.extend([m['corr'] for m in matches if m['r1'] == match['r2']])
            b_recs.extend([m['corr'] for m in matches if m['r2'] == match['r2']])
            r2_value = sum(b_recs) / len(b_recs)
            averaged_recs.append({ 'record': match['r2'],
                                   'source': match['r2_source'],
                                   'match_value': r2_value,
                                   'record_value': r2_value})

    return averaged_recs

这可行,但我确信它可以改进。上面 cmets 标记的我的问题是:

  1. 这里有没有更好的方法来强制唯一性?我有胆量 感觉我不需要遍历我的averaged_recs 列表 每场比赛。
  2. 我可以在不循环的情况下将所有这些records 围起来吗 像这样超过他们两次?
  3. 可以/应该将此平均计算与之前的列表扩展结合起来吗?

感谢您的帮助!

【问题讨论】:

    标签: python dictionary list-comprehension


    【解决方案1】:

    用列表理解来做到这一点有点困难,但我设法用更少的行来编写它,并希望使用 tmp dict 对键进行排序

    lst = [
      { 'r1': 'record_1', 'r2': 'record_2', 'corr': 85, 'r1_source': 'source_1', 'r2_source': 'source_2' },
      { 'r1': 'record_1', 'r2': 'record_3', 'corr': 90, 'r1_source': 'source_1', 'r2_source': 'source_3' },
      { 'r1': 'record_2', 'r2': 'record_3', 'corr': 77, 'r1_source': 'source_2', 'r2_source': 'source_3' },
    ]
    
    tmp_dict = {}
    for d in lst:
        if d['r1'] not in tmp_dict.keys():
            tmp_dict[d['r1']] = {}
            tmp_dict[d['r1']]['corr'] = list()
            tmp_dict[d['r1']]['source'] = d['r1_source']
    
        if d['r2'] not in tmp_dict.keys():
            tmp_dict[d['r2']] = {}
            tmp_dict[d['r2']]['corr'] = list()
            tmp_dict[d['r2']]['source'] = d['r2_source']
    
        tmp_dict[d['r1']]['corr'].append(d['corr'])
        tmp_dict[d['r2']]['corr'].append(d['corr'])
    
    
    print [{ 'record': k, 'source': tmp_dict[k]['source'], 'avg': sum(tmp_dict[k]['corr'])/float(len(tmp_dict[k]['corr'])) } for k in tmp_dict.keys()]
    

    【讨论】:

      【解决方案2】:

      我的想法, 我们可以循环列表,为所有的r1,r2生成一个dict,如果是r1,则将其附加到列表的头部,如果是r2,则将其添加到尾部。

      然后循环这个 dict 得到你期望的输出。

      from collections import defaultdict
      test = [
        { 'r1': 'record_1', 'r2': 'record_2', 'corr': 85, 'r1_source': 'source_1', 'r2_source': 'source_2' },
        { 'r1': 'record_1', 'r2': 'record_3', 'corr': 90, 'r1_source': 'source_1', 'r2_source': 'source_3' },
        { 'r1': 'record_2', 'r2': 'record_3', 'corr': 77, 'r1_source': 'source_2', 'r2_source': 'source_3' },
      ]
      temp = defaultdict(list)
      for item in test:
          temp[item['r1']].insert(0, item)
          temp[item['r2']].append(item)
      
      result = []
      for key, value in temp.items():
          new_item = {}
          new_item['avg'] = sum(list(map(lambda item: item['corr'], value)))*1.0/len(value)
          new_item['record'] = key
          new_item['source'] = value[0]['r1_source'] if key == value[0]['r1'] else value[0]['r2_source']
          result.append(new_item)
      print(result)
      

      输出:

      [{'avg': 87.5, 'record': 'record_1', 'source': 'source_1'}, {'avg': 81.0, 'record': 'record_2', 'source': 'source_2'}, {'avg': 83.5, 'record': 'record_3', 'source': 'source_3'}]
      [Finished in 0.175s]
      

      更新 1:

      如果 r1 和 r2 是列表,我们可以将其转换为元组,然后在计算输出时将其转换回来。

      所以代码会是这样的:

      from collections import defaultdict
      record1 = [1, 2, 3]
      record2 = [4, 5, 6]
      record3 = [7, 8, 9]
      test = [
        { 'r1': record1, 'r2': record2, 'corr': 85, 'r1_source': 'source_1', 'r2_source': 'source_2' },
        { 'r1': record1, 'r2': record3, 'corr': 90, 'r1_source': 'source_1', 'r2_source': 'source_3' },
        { 'r1': record2, 'r2': record3, 'corr': 77, 'r1_source': 'source_2', 'r2_source': 'source_3' },
      ]
      temp = defaultdict(list)
      for item in test:
          temp[tuple(item['r1'])].insert(0, item)
          temp[tuple(item['r2'])].append(item)
      
      result = []
      for key, value in temp.items():
          new_item = {}
          new_item['avg'] = sum(list(map(lambda item: item['corr'], value)))*1.0/len(value)
          new_item['record'] = list(key)
          new_item['source'] = value[0]['r1_source'] if list(key) == value[0]['r1'] else value[0]['r2_source']
          result.append(new_item)
      print(result)
      

      输出:

      [{'avg': 87.5, 'record': [1, 2, 3], 'source': 'source_3'}, {'avg': 81.0, 'record': [4, 5, 6], 'source': 'source_3'}, {'avg': 83.5, 'record': [7, 8, 9], 'source': 'source_3'}]
      [Finished in 0.178s]
      

      【讨论】:

      • 一个很酷的想法,但是在这个例子中你的记录是字符串,但是记住每条记录都是一个列表。由于列表是不可散列的类型,因此它不能成为临时字典的键。将'record_1' 替换为['record_1'] 会导致TypeError
      • @Eqomatic,更新了我的答案以支持如果 r1、r2 是列表。
      【解决方案3】:

      Q1 - 字典本质上是由独特的元素组成的,所以我认为您不需要以这种方式重新检查它。您还在遍历平均记录,这是空的。

      Q2 - 您可以在 if 语句中使用 or [m['corr'] for m in matches if m['r1'] == match['r1'] or m['r2'] == match['r1']]

      Q3 - 我真的不认为你需要其他方法来做到这一点

      【讨论】:

        猜你喜欢
        • 2020-08-14
        • 2021-04-06
        • 2021-09-21
        • 1970-01-01
        • 2016-09-24
        • 2021-09-26
        • 1970-01-01
        • 1970-01-01
        • 2018-08-30
        相关资源
        最近更新 更多