【问题标题】:Python - Group combinations based on conditionPython - 基于条件的组组合
【发布时间】:2018-08-15 12:51:31
【问题描述】:

考虑以下数据集,

Name    Age Grade
Person1 18  50
Person2 19  100
Person3 20  0
Person4 21  -25
Person5 22  -125
Person6 23  80
Person7 24  -70

如果我想根据学生的成绩汇总将他们分组,我会怎么做? 我的意思是 - 我想让学生分组,例如该年级所有学生的成绩总和为 0 或尽可能接近零。

因此,理想情况下 - 数据集的答案类似于 -

  1. Group 1 ----> Person1、Person2、Person4、Person5(因为他们的 加分是 0)

  2. Group 2 ----> Person3(因为等级是0)

  3. Group 3 ----> Person6, Person7(因为加起来是10)

我是如何着手解决这个问题的 -

new_dt = pd.read_csv('../tt.csv')

a = list(itertools.chain.from_iterable(
    [[j for i in el for j in i] for el in itertools.combinations(new_dt.values.tolist(),i)]
    for i in range(1, len(new_dt)+1)
    )
    )

out = pd.DataFrame(a)

所以,基本上我正在使用 itertools.combinations 找出所有可能的组合

    0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  19  20
0   Person1 18  50                                                                      
1   Person2 19  100                                                                     
2   Person3 20  0                                                                       
3   Person4 21  -25                                                                     
4   Person5 22  -125                                                                        
5   Person6 23  80                                                                      
6   Person7 24  -70                                                                     
7   Person1 18  50  Person2 19  100                                                         
8   Person1 18  50  Person3 20  0                                                           
9   Person1 18  50  Person4 21  -25                                                         
10  Person1 18  50  Person5 22  -125                                                            
11  Person1 18  50  Person6 23  80                                                          
12  Person1 18  50  Person7 24  -70                                                         
13  Person2 19  100 Person3 20  0                                                           
14  Person2 19  100 Person4 21  -25                                                         
15  Person2 19  100 Person5 22  -125                                                            
16  Person2 19  100 Person6 23  80                                                          
17  Person2 19  100 Person7 24  -70                                                         
18  Person3 20  0   Person4 21  -25                                                         
19  Person3 20  0   Person5 22  -125                                                            
20  Person3 20  0   Person6 23  80                                                          
21  Person3 20  0   Person7 24  -70                                                         
22  Person4 21  -25 Person5 22  -125                                                            
23  Person4 21  -25 Person6 23  80                                                          
24  Person4 21  -25 Person7 24  -70                                                         
25  Person5 22  -125    Person6 23  80                                                          
26  Person5 22  -125    Person7 24  -70                                                         
27  Person6 23  80  Person7 24  -70                                                         
28  Person1 18  50  Person2 19  100 Person3 20  0                                               
29  Person1 18  50  Person2 19  100 Person4 21  -25                                             
30  Person1 18  50  Person2 19  100 Person5 22  -125                                                
31  Person1 18  50  Person2 19  100 Person6 23  80                                              
32  Person1 18  50  Person2 19  100 Person7 24  -70                                             
33  Person1 18  50  Person3 20  0   Person4 21  -25                                             
34  Person1 18  50  Person3 20  0   Person5 22  -125                                                
35  Person1 18  50  Person3 20  0   Person6 23  80                                              
36  Person1 18  50  Person3 20  0   Person7 24  -70                                             
37  Person1 18  50  Person4 21  -25 Person5 22  -125                                                
38  Person1 18  50  Person4 21  -25 Person6 23  80                                              
39  Person1 18  50  Person4 21  -25 Person7 24  -70                                             
40  Person1 18  50  Person5 22  -125    Person6 23  80                                              
41  Person1 18  50  Person5 22  -125    Person7 24  -70                                             
42  Person1 18  50  Person6 23  80  Person7 24  -70                                             
43  Person2 19  100 Person3 20  0   Person4 21  -25                                             
44  Person2 19  100 Person3 20  0   Person5 22  -125                                                
45  Person2 19  100 Person3 20  0   Person6 23  80                                              
46  Person2 19  100 Person3 20  0   Person7 24  -70                                             
47  Person2 19  100 Person4 21  -25 Person5 22  -125                                                
48  Person2 19  100 Person4 21  -25 Person6 23  80                                              
49  Person2 19  100 Person4 21  -25 Person7 24  -70                                             
50  Person2 19  100 Person5 22  -125    Person6 23  80                                              
51  Person2 19  100 Person5 22  -125    Person7 24  -70                                             
52  Person2 19  100 Person6 23  80  Person7 24  -70                                             
53  Person3 20  0   Person4 21  -25 Person5 22  -125                                                
54  Person3 20  0   Person4 21  -25 Person6 23  80                                              
55  Person3 20  0   Person4 21  -25 Person7 24  -70                                             
56  Person3 20  0   Person5 22  -125    Person6 23  80                                              
57  Person3 20  0   Person5 22  -125    Person7 24  -70                                             
58  Person3 20  0   Person6 23  80  Person7 24  -70                                             
59  Person4 21  -25 Person5 22  -125    Person6 23  80                                              
60  Person4 21  -25 Person5 22  -125    Person7 24  -70                                             
61  Person4 21  -25 Person6 23  80  Person7 24  -70                                             
62  Person5 22  -125    Person6 23  80  Person7 24  -70                                             
63  Person1 18  50  Person2 19  100 Person3 20  0   Person4 21  -25                                 
64  Person1 18  50  Person2 19  100 Person3 20  0   Person5 22  -125                                    
65  Person1 18  50  Person2 19  100 Person3 20  0   Person6 23  80                                  
66  Person1 18  50  Person2 19  100 Person3 20  0   Person7 24  -70                                 
67  Person1 18  50  Person2 19  100 Person4 21  -25 Person5 22  -125                                    
68  Person1 18  50  Person2 19  100 Person4 21  -25 Person6 23  80                                  
69  Person1 18  50  Person2 19  100 Person4 21  -25 Person7 24  -70                                 
70  Person1 18  50  Person2 19  100 Person5 22  -125    Person6 23  80                                  
71  Person1 18  50  Person2 19  100 Person5 22  -125    Person7 24  -70                                 
72  Person1 18  50  Person2 19  100 Person6 23  80  Person7 24  -70                                 
73  Person1 18  50  Person3 20  0   Person4 21  -25 Person5 22  -125                                    
74  Person1 18  50  Person3 20  0   Person4 21  -25 Person6 23  80                                  
75  Person1 18  50  Person3 20  0   Person4 21  -25 Person7 24  -70                                 
76  Person1 18  50  Person3 20  0   Person5 22  -125    Person6 23  80                                  
77  Person1 18  50  Person3 20  0   Person5 22  -125    Person7 24  -70                                 
78  Person1 18  50  Person3 20  0   Person6 23  80  Person7 24  -70                                 
79  Person1 18  50  Person4 21  -25 Person5 22  -125    Person6 23  80                                  
80  Person1 18  50  Person4 21  -25 Person5 22  -125    Person7 24  -70                                 
81  Person1 18  50  Person4 21  -25 Person6 23  80  Person7 24  -70                                 
82  Person1 18  50  Person5 22  -125    Person6 23  80  Person7 24  -70                                 
83  Person2 19  100 Person3 20  0   Person4 21  -25 Person5 22  -125                                    
84  Person2 19  100 Person3 20  0   Person4 21  -25 Person6 23  80                                  
85  Person2 19  100 Person3 20  0   Person4 21  -25 Person7 24  -70                                 
86  Person2 19  100 Person3 20  0   Person5 22  -125    Person6 23  80                                  
87  Person2 19  100 Person3 20  0   Person5 22  -125    Person7 24  -70                                 
88  Person2 19  100 Person3 20  0   Person6 23  80  Person7 24  -70                                 
89  Person2 19  100 Person4 21  -25 Person5 22  -125    Person6 23  80                                  
90  Person2 19  100 Person4 21  -25 Person5 22  -125    Person7 24  -70                                 
91  Person2 19  100 Person4 21  -25 Person6 23  80  Person7 24  -70                                 
92  Person2 19  100 Person5 22  -125    Person6 23  80  Person7 24  -70                                 
93  Person3 20  0   Person4 21  -25 Person5 22  -125    Person6 23  80                                  
94  Person3 20  0   Person4 21  -25 Person5 22  -125    Person7 24  -70                                 
95  Person3 20  0   Person4 21  -25 Person6 23  80  Person7 24  -70                                 
96  Person3 20  0   Person5 22  -125    Person6 23  80  Person7 24  -70                                 
97  Person4 21  -25 Person5 22  -125    Person6 23  80  Person7 24  -70                                 
98  Person1 18  50  Person2 19  100 Person3 20  0   Person4 21  -25 Person5 22  -125                        
99  Person1 18  50  Person2 19  100 Person3 20  0   Person4 21  -25 Person6 23  80                      
100 Person1 18  50  Person2 19  100 Person3 20  0   Person4 21  -25 Person7 24  -70                     
101 Person1 18  50  Person2 19  100 Person3 20  0   Person5 22  -125    Person6 23  80                      
102 Person1 18  50  Person2 19  100 Person3 20  0   Person5 22  -125    Person7 24  -70                     
103 Person1 18  50  Person2 19  100 Person3 20  0   Person6 23  80  Person7 24  -70                     
104 Person1 18  50  Person2 19  100 Person4 21  -25 Person5 22  -125    Person6 23  80                      
105 Person1 18  50  Person2 19  100 Person4 21  -25 Person5 22  -125    Person7 24  -70                     
106 Person1 18  50  Person2 19  100 Person4 21  -25 Person6 23  80  Person7 24  -70                     
107 Person1 18  50  Person2 19  100 Person5 22  -125    Person6 23  80  Person7 24  -70                     
108 Person1 18  50  Person3 20  0   Person4 21  -25 Person5 22  -125    Person6 23  80                      
109 Person1 18  50  Person3 20  0   Person4 21  -25 Person5 22  -125    Person7 24  -70                     
110 Person1 18  50  Person3 20  0   Person4 21  -25 Person6 23  80  Person7 24  -70                     
111 Person1 18  50  Person3 20  0   Person5 22  -125    Person6 23  80  Person7 24  -70                     
112 Person1 18  50  Person4 21  -25 Person5 22  -125    Person6 23  80  Person7 24  -70                     
113 Person2 19  100 Person3 20  0   Person4 21  -25 Person5 22  -125    Person6 23  80                      
114 Person2 19  100 Person3 20  0   Person4 21  -25 Person5 22  -125    Person7 24  -70                     
115 Person2 19  100 Person3 20  0   Person4 21  -25 Person6 23  80  Person7 24  -70                     
116 Person2 19  100 Person3 20  0   Person5 22  -125    Person6 23  80  Person7 24  -70                     
117 Person2 19  100 Person4 21  -25 Person5 22  -125    Person6 23  80  Person7 24  -70                     
118 Person3 20  0   Person4 21  -25 Person5 22  -125    Person6 23  80  Person7 24  -70                     
119 Person1 18  50  Person2 19  100 Person3 20  0   Person4 21  -25 Person5 22  -125    Person6 23  80          
120 Person1 18  50  Person2 19  100 Person3 20  0   Person4 21  -25 Person5 22  -125    Person7 24  -70         
121 Person1 18  50  Person2 19  100 Person3 20  0   Person4 21  -25 Person6 23  80  Person7 24  -70         
122 Person1 18  50  Person2 19  100 Person3 20  0   Person5 22  -125    Person6 23  80  Person7 24  -70         
123 Person1 18  50  Person2 19  100 Person4 21  -25 Person5 22  -125    Person6 23  80  Person7 24  -70         
124 Person1 18  50  Person3 20  0   Person4 21  -25 Person5 22  -125    Person6 23  80  Person7 24  -70         
125 Person2 19  100 Person3 20  0   Person4 21  -25 Person5 22  -125    Person6 23  80  Person7 24  -70         
126 Person1 18  50  Person2 19  100 Person3 20  0   Person4 21  -25 Person5 22  -125    Person6 23  80  Person7 24  -70

得到之后,所有的成绩都在每 3 列,所以我将每 3 行的总和添加到该行与

only_grades['Total'] = only_grades.sum(axis=1)
out['Total'] = only_grades['Total']
out.to_csv('../tt_2.csv')

添加一列“总计”,每行包含以下输出,

Total
50
100
0
-25
-125
80
-70
150
50
25
-75
130
-20
100
75
-25
180
30
-25
-125
80
-70
-150
55
-95
-45
-195
10
150
125
25
230
80
25
-75
130
-20
-100
105
-45
5
-145
60
75
-25
180
30
-50
155
5
55
-95
110
-150
55
-95
-45
-195
10
-70
-220
-15
-115
125
25
230
80
0
205
55
105
-45
160
-100
105
-45
5
-145
60
-20
-170
35
-65
-50
155
5
55
-95
110
30
-120
85
-15
-70
-220
-15
-115
-140
0
205
55
105
-45
160
80
-70
135
35
-20
-170
35
-65
-90
30
-120
85
-15
-40
-140
80
-70
135
35
10
-90
-40
10

然后我想知道,我会用这些来制作组。您如何看待这种方法?以及如何使用“总计”列创建组,以便在创建组时考虑原始数据集中的每一行,而不是更多。

【问题讨论】:

  • 一个问题;查看您的“理想”输出,您将Person 3 作为一个单独的组。那么,所有评分为 0 的Person(s) 是否应该单独在一个单独的组中?
  • 不,我会将所有 0 成绩归为一组。我只是想区分一下,在那种情况下我更喜欢 3 个组,而不是将 Person3 与 Person6 和 Person7 一起添加。
  • 您要解决的真正问题是什么?为什么要创建成绩总和为 0 的学生组?如果所有学生的成绩都为零,那么应该有多少个集群?了解真正的业务目标可能表明另一种方法更合适。
  • 好的,所以也许成绩不是解释问题的最佳例子。想象一下标准是“投入的时间”。我想将学生分组在一起,他们作为一个组投入的时间尽可能接近 0。这有点意思?所有投入时间为 0 小时的学生将被放在一起。
  • 但是如果你有两个总和为0的组,那么它们不应该合并吗?我不明白这个分组逻辑是为了完成什么......

标签: python python-3.x combinations mathematical-optimization itertools


【解决方案1】:

您的答案似乎有效,但它的复杂性是指数级的,因为您进行了详尽的搜索。

这个问题看起来就像the subset sum problem,你想在一个更大的集合中找到一个总和为零的子集(这是一个NP问题,所以你不会在多项式中找到任何完美的解决方案时间。这里是an explanation of NP problems,如果你不知道的话)。

由于已经存在多项式算法来找到子集和问题的近似解,我认为调整您的问题可能会导致您获得可接受的解决方案。这里是the backtracking algorithm I would use

现在让我们调整您的问题:

1) 回溯问题只适用于正数,所以第一步是找到你的集合中的最低分数。保留它,您将需要它多次。一个简单的 for 循环就可以了。

2) 如果此最低分数 = 0,则除了单独的学生成绩为零(并且您有解决方案)之外,您没有任何子集使 0。

3) 现在您的问题与the video 上的问题完全相同,n 是您的完整集合的大小,m 是您在步骤 中添加到整个集合的数字2)(即加前的零)。执行算法,找到您的子集,然后将其从集合中删除。

4) 请注意,您的算法可能会在未找到所需子集的情况下到达图表的末尾。因此,每次回溯时,保留子集及其总和,将其与迄今为止找到的最佳值进行比较,如果更好则替换它。

5) 将步骤 3) 应用于您的剩余集合,直到您获得剩余集合的总和

这可能不是最好的解决方案,请随时提出任何改进。该算法将优先考虑低距离子集 + 最后一个坏子集,因此如果您需要让所有子集都大致良好,这可能不是一个好的解决方案。

如果您每次都能在图中快速找到子集,那么算法的复杂性在很大程度上取决于,因此按成绩对学生进行排序可以提高时间复杂度。并且它会删除步骤 1) 因为最小值是第一个元素。

【讨论】:

    【解决方案2】:

    你很接近,但我建议你的输出字典:

    from itertools import combinations
    
    d = {p: df.loc[df['Name'].isin(p), 'Grade'].sum() \
         for i in range(1, len(df['Name'])+1) \
         for p in combinations(df['Name'], i)}
    
    res = sorted(d.items(), key=lambda x: (abs(x[1]), -len(x[0])))
    
    print(res[:5])
    
    [(('Person1', 'Person2', 'Person3', 'Person4', 'Person5'), 0),
     (('Person1', 'Person2', 'Person4', 'Person5'), 0),
     (('Person3',), 0),
     (('Person1', 'Person3', 'Person5', 'Person6'), 5),
     (('Person2', 'Person3', 'Person4', 'Person7'), 5),
      ...]
    

    如果您需要数据框,我强烈建议您使用布尔系列。下面的解决方案假设您已经构建了上面的结果字典。

    L = [[v] + [i in k for i in df['Name'].values] for k, v in d.items()]
    
    res_df = pd.DataFrame(L, columns=['Score'] + df['Name'].tolist())
    res_df = res_df.iloc[np.argsort(res_df['Score'].abs())].astype(int)
    
    print(res_df.head())
    
        Score  Person1  Person2  Person3  Person4  Person5  Person6  Person7
    2       0        0        0        1        0        0        0        0
    98      0        1        1        1        1        1        0        0
    67      0        1        1        0        1        1        0        0
    85      5        0        1        1        1        0        0        1
    76      5        1        0        1        0        1        1        0
    

    【讨论】:

    • 在您的解决方案中,您会如何建议我应该创建哪些组?例如,您如何跟踪哪些学生被分入了哪些小组?假设一个学生只能做一组,你是如何分组的?
    • @user10141156,不确定您的意思。这会计算出所有种可能的组合。
    猜你喜欢
    • 2019-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 1970-01-01
    • 2018-10-27
    • 1970-01-01
    相关资源
    最近更新 更多