【发布时间】:2019-11-12 03:54:34
【问题描述】:
我会尽量以最清晰的方式解释我的问题。假设我们有 df 数据框:
import pandas as pd
users = ['a','b','c','d','e','f','g','h', 'a','b','c','g','h', 'b','c','d','e']
groups = ['g1']*8 + ['g2']*5 + ['g3']*4
scores = [0.54, 0.02, 0.78, 0.9 , 0.98, 0.27, 0.25, 0.98, 0.47, 0.02, 0.8, 0.51, 0.28, 0.53, 0.01, 0.51, 0.6 ]
df = pd.DataFrame({'user': users,
'group': groups,
'score': scores}).sort_values('score', ascending=False)
这将返回如下内容:
user group score
7 h g1 0.98
4 e g1 0.98
3 d g1 0.90
10 c g2 0.80
2 c g1 0.78
16 e g3 0.60
0 a g1 0.54
13 b g3 0.53
11 g g2 0.51
15 d g3 0.51
8 a g2 0.47
12 h g2 0.28
5 f g1 0.27
6 g g1 0.25
1 b g1 0.02
9 b g2 0.02
14 c g3 0.01
每个用户在属于每个组时都有一定的分数。问题是每个组可以有有限数量的成员。这些数字存储在字典中:
members = {'g1': 3,
'g2': 2,
'g3': 1}
问题来了:我必须选择将用户分组的最佳方式,同时考虑到他们的分数和每个组可以托管的用户数量。
如果我们看一下上面的数据框,将用户分配到组的最佳方法是:
- 最高分是分配给
h、e和d属于g1的分数。鉴于g1最多可容纳 3 个成员,则将这三个用户分配给它。现在g1不能再招收会员了。 - 以下最好成绩是分配给属于
g2的c的成绩。因此g2现在还剩一个空位。 - 观察到下面的分数也是指
c,但是这个用户已经被分配了,所以不能分配两次。因此,它必须被忽略。下面的情况也是如此,它把e(已经分配给g1)的用户与g3相关联。 - 以下一个将
a与g1相关联,但该组已满。因此,它也必须被忽略。 - 该过程必须继续进行,直到所有组都已满,或者直到没有更多的行可以填充组(在这种情况下,一些组将有空闲插槽)。
我找到的解决方案是这样的:
final = pd.DataFrame([])
# As long as there are non-assigned users and groups with free slots...
while len(df):
# Take the first row (i.e. the best score of the rows left)
i = df.first_valid_index()
# If there are free slots...
if members[df.loc[i,'group']] > 0:
# Subtract 1 from the slots left of this group
members[df.loc[i,'group']] -= 1
# Append this row to the 'final' DataFrame
final = final.append(df.loc[i])
# Delete all rows belonging to this user, as it was already assigned
df = df.loc[df.user != df.loc[i,'user']]
# If the group has no free slots left...
else:
# Delete all rows belonging to this group, as it is already full
df = df.loc[df.group != df.loc[i,'group']]
final = final.groupby('group').agg({'user': ['unique','count']})
这将返回以下 DataFrame:
user
unique count
group
g1 [h, d, f] 3
g2 [c, g] 2
g3 [b] 1
问题出在这里:这段代码在现实生活中需要很长时间才能运行。我有超过 2000 万不同的用户,大约有 10 个不同的组需要填充。所以这种方法真的不可行。
有没有更有效的方法来做到这一点? 如有必要,我愿意采用次优解决方案。也就是说,将几乎最佳的用户分配给每个组......如果这有意义的话。
【问题讨论】:
-
用户出现在组中的概率在您的情况下真正意味着什么?它是一种偏好,按降序排列吗?因为无论“概率”如何,您都将返回单个选择...
-
@MadPhysicist 嗯,它们是某种分数。也许“概率”这个词不是最好的术语。我会在问题中改变它。不过,无论
score列的实际含义如何,都应按照问题中的说明进行选择。 -
有道理。澄清一下,您的问题是如何优化现有算法?
-
@MadPhysicist 是的。当与小组一起工作时,我在 OP 末尾编写的循环可以正常工作。这 是 我的问题的最佳解决方案。问题是当有数百万行时这不起作用。因此,我正在寻找另一种解决方案,即使输出不是实际的最佳值,而是接近它的值。
-
@גלעדברקן 所有信息都已在问题中。请仔细阅读,因为“最佳分发方式”在 OP 中有很好的描述。
标签: python pandas algorithm optimization