假设我有一个事物列表,它们的频率,(按频率排序)和项目总数(为了清楚起见,我在这里使用dict,但实际上它们是具有频率属性的对象):
items = {"bananas":12, "oranges":12, "apples":11, "pears":2}
现在,我想从我的37(max_results
)个项目中挑选出10个项目(total_frequency
),但与其频率成比例(最多,比方说,3个项目) - max_proportion
)。在这个例子中,我最终得到3个香蕉,橙子和苹果,以及1个梨。
def get_relative_quantities(total_frequency, items, max_results, max_proportion):
results = {}
num_added = 0
for freq, the_group in it.groupby(items, lambda x: x.frequency):
if num_added == max_results:
break
the_group_list = list(the_group)
group_size = len(the_group_list)
shuffle(the_group_list)
for item in the_group_list:
if num_added == max_results:
break
rel_freq = min(math.ceil((freq/total_frequency)*max_results), max_proportion)
results[item] = rel_freq
num_added += rel_freq
return results
我担心的一件事是,如果只有1项,这种方法,我将得不到足够的结果。我将得到3(假设一个max_proportion
f 3中的10)。我该如何处理这个问题?
答案 0 :(得分:0)
这将取决于哪种策略对您的需求更有意义。我们假设您max_results
为10
而max_proportion
为2
。应该归还什么?第一次迭代将获得每个2
。
max_proportion
增加到3
,则梨的数量将降至1
(即结果将类似于您的示例); max_results = 2
和max_proportion = 1
进行新的迭代,则会增加一个香蕉和一个橙色;
max_proportion
保留在2
,您可能会获得2个香蕉或2个橙子,而另一个则不会。无论您想要的输出是什么,我的建议都是一样的:检查是否有足够的结果,如有必要,再次致电get_relative_quantities
,减少max_results
(以获取剩余的元素)或增加max_proportion
(丢弃初始结果并接受越来越多的每个项目)。根据需要多次执行此操作以达到所需数量或耗尽可能性。 (这与iterative deepening)
答案 1 :(得分:0)
首先,建立一个具有比例数量的元素的项目列表:
items = {"bananas":12, "oranges":12, "apples":11, "pears":2}
choices = []
[choices.extend([k] * v) for k, v in items.items()]
接下来,设置最终结果,每个结果的最小数量(每个可能的项目之一):
selected = list(items.keys())
最后,对于您要选择的其他项目,请从按比例重复的项目列表中选择一个随机项目:
import random as rnd
[selected.append(rnd.choice(choices)) for i in xrange(10 - len(items))]
所有这些片段组合在一起:
import random as rnd
items = {"bananas":12, "oranges":12, "apples":11, "pears":2}
choices = []
[choices.extend([k] * v) for k, v in items.items()]
selected = list(items.keys())
[selected.append(rnd.choice(choices)) for i in xrange(10 - len(items))]
运行的输出:
>>> pp.pprint(selected)
['pears',
'bananas',
'oranges',
'apples',
'bananas',
'bananas',
'oranges',
'apples',
'apples',
'apples']
答案 2 :(得分:0)
您可以使用d'Hondt method(或Jefferson方法)来执行此操作。
import heapq, collections, itertools
def fruit_divided(fruit, weight, max_proportion):
for div in range(1, min(weight, max_proportion) + 1):
yield (- weight / div, fruit)
def pick(items, max_results, max_proportion):
fruits = heapq.merge(*(fruit_divided(fruit, frequency, max_proportion)
for fruit, frequency in items.items()))
fruits = itertools.islice(fruits, max_results)
return collections.Counter(fruit for _, fruit in fruits)
示例运行:
>>> items = {"bananas":12, "oranges":12, "apples":11, "pears":2}
>>> max_results = 10
>>> max_proportion = 3
>>> print(pick(items, max_results, max_proportion))
Counter({'oranges': 3, 'bananas': 3, 'apples': 3, 'pears': 1})
如果只能选择少于max_results
个水果,则会返回最高数量。
>>> print(pick(items, max_results, max_proportion))
Counter({'oranges': 3, 'bananas': 3, 'apples': 3, 'pears': 2})