【问题标题】:Fastest way to rank items with multiple values and weightings对具有多个值和权重的项目进行排名的最快方法
【发布时间】:2014-03-02 00:09:47
【问题描述】:

我有一个这样的键值对集合:

{ 
   'key1': [value1_1, value2_1, value3_1, ...], 
   'key2': [value1_2, value2_2, value3_2, ...],
   ...
 }

还有一个与值列表顺序相同的列表,其中包含每个变量应该应用的权重。所以它看起来像[weight_1, weight_2, weight_3, ...]

我的目标是最终得到一个有序的键列表,根据其具有最高的总分值。请注意,这些值并非全部标准化/标准化,因此 value1_x 的范围可以从 1 到 10,但值 2_x 的范围可以从 1 到 100000。这对我来说是一个棘手的部分,因为我必须以某种方式标准化数据。

我正在尝试使该算法运行以针对许多不同的值进行缩放,因此 1 或 100 需要相同的时间(或至少对数更多时间)。那可能吗?有什么真正有效的方法可以解决这个问题吗?

【问题讨论】:

  • 你无法避免线性时间复杂度,因为标准化和求和需要你处理所有值。
  • @Keyser:理论上可能存在一些棘手的数据结构,给定权重列表,根据给定的权重分布在亚线性时间内为您提供前 k 个项目。我不抱太大希望。
  • 当然你需要线性预处理时间,但如果有足够多的查询要遵循,这可以摊销

标签: python algorithm


【解决方案1】:

你不能得到线性时间,但你可以做得更快;这对我来说就像一个矩阵乘法,所以我建议你使用numpy

import numpy as np

keys = ['key1', 'key2', 'key3']

values = np.matrix([
    [1.1, 1.2, 1.3, 1.4],
    [2.1, 2.2, 2.3, 2.4],
    [3.1, 3.2, 3.3, 3.4]
])

weights = np.matrix([[10., 20., 30., 40.]]).transpose()

res = (values * weights).transpose().tolist()[0]

items = zip(res, keys)
items.sort(reverse=True)

给了

[(330.0, 'key3'), (230.0, 'key2'), (130.0, 'key1')]

编辑: thanks to @Ondro 用于 np.dot 和 to @unutbu for np.argsort,这是一个完全在 numpy 中的改进版本:

import numpy as np

# set up values
keys = np.array(['key1', 'key2', 'key3'])
values = np.array([
    [1.1, 1.2, 1.3, 1.4],    # values1_x
    [2.1, 2.2, 2.3, 2.4],    # values2_x
    [3.1, 3.2, 3.3, 3.4]     # values3_x
])
weights = np.array([10., 20., 30., 40.])

# crunch the numbers
res = np.dot(values, -weights)   # negative of weights!

order = res.argsort(axis=0)  # sorting on negative value gives
                             # same order as reverse-sort; there does
                             # not seem to be any way to reverse-sort
                             # directly
sortedkeys = keys[order].tolist()

导致['key3', 'key2', 'key1']

【讨论】:

    【解决方案2】:

    这是一个归一化函数,它将您的值线性转换为 [0,1]

    def normalize(val, ilow, ihigh, olow, ohigh):
        return ((val-ilow) * (ohigh-olow) / (ihigh - ilow)) + olow
    

    现在,使用normalize 计算具有标准化值的新字典。然后,按加权和排序:

    def sort(d, weights, ranges):
        # ranges is a list of tuples containing the lower and upper bounds of the corresponding value
    
        newD = {k:[normalize(v,ilow, ihigh, 0, 1) for v,(ilow, ihigh) in zip(vals, ranges)] for k,val in d.iteritems()}  # d.items() in python3
        return sorted(newD, key=lambda k: sum(v*w for v,w in zip(newD[k], weights)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多