1+ import csv
2+ import numpy as np
3+
4+
5+ PATH = './'
6+
7+ MAX_PER_PROJECT = 2
8+ MIN_PROPOSAL_VALUE = 6
9+ MIN_SATISFACTION_VALUE = 5
10+
11+
12+ def read_data_and_clean ():
13+ students = []
14+ projects = []
15+ preferences = {}
16+ rankings = {}
17+ count_map = {}
18+
19+ with open (PATH + 'data1/raw.csv' , 'r' ) as file :
20+ reader = csv .reader (file )
21+ for i , row in enumerate (reader ):
22+ if i == 0 :
23+ projects = row [2 :]
24+ rankings = {project : [] for project in projects }
25+ count_map = {project : {str (i ): 0 for i in range (1 , 100 )} for project in projects }
26+ else :
27+ student = f'{ row [0 ]} ({ row [1 ]} )'
28+ if student :
29+ if student in students :
30+ print ('Found duplicate student:' , student )
31+ else :
32+ students .append (student )
33+ preferences [student ] = {}
34+ for j , col in enumerate (row [2 :]):
35+ if not col :
36+ col = str (len (row [2 :]))
37+ project = projects [j ]
38+ preferences [student ][project ] = col
39+ rankings [project ].append ((student , col ))
40+ count_map [project ][str (col )] += 1
41+
42+ c = 0
43+ temp = {project : '' for project in projects }
44+ for project , dict in count_map .items ():
45+ s = dict ['1' ] + dict ['2' ]
46+ temp [project ] = s
47+ c += 1
48+
49+ for ranking , items in rankings .items ():
50+ items .sort (key = lambda x : int (x [1 ]))
51+
52+ ranking_map = {project : {} for project in projects }
53+ for project , items in rankings .items ():
54+ maxx = - 1
55+ rank = 1
56+ for item in items :
57+ student = item [0 ]
58+ pref = item [1 ]
59+
60+ if maxx == - 1 :
61+ maxx = int (pref )
62+ elif int (pref ) > maxx :
63+ maxx = int (pref )
64+ rank += 1
65+
66+ ranking_map [project ][student ] = str (rank )
67+
68+ max_per_projects = {}
69+ exceptions = {'E' : 3 , 'F' : 1 , 'H' : 4 , 'I' : 6 , 'L' : 1 , 'M' : 1 }
70+ for p in projects :
71+ if p in list (exceptions .keys ()):
72+ max_per_projects [p ] = exceptions [p ]
73+ else :
74+ max_per_projects [p ] = MAX_PER_PROJECT
75+
76+ return students , projects , max_per_projects , preferences , rankings , ranking_map
77+
78+ def get_averages_of_preferences (projects , preferences ):
79+ totals = [0 ] * len (projects )
80+ counts = [0 ] * len (projects )
81+ averages = [0 ] * len (projects )
82+
83+ for st , prefs in preferences .items ():
84+ i = 0
85+ for project_name , pref in prefs .items ():
86+ counts [i ] += 1
87+ totals [i ] += int (pref )
88+ i += 1
89+
90+ for i in range (len (totals )):
91+ averages [i ] = totals [i ] / counts [i ]
92+
93+ indexes = sorted (range (len (averages )), key = lambda i : averages [i ], reverse = True )
94+
95+ return indexes
96+
97+
98+ def calculate_averages_of_proposals (projects , allocations , proposals ):
99+ averages_dict = {project : 0.0 for project in projects }
100+
101+ for project , students in allocations .items ():
102+ total = 0
103+ for student in students :
104+ total += int (proposals [student ])
105+
106+ averages_dict [project ] = total / len (students )
107+
108+ averages = [avg for p , avg in averages_dict .items ()]
109+ indexes = sorted (range (len (averages )), key = lambda i : averages [i ])
110+
111+ averages_out = {}
112+ for i in range (len (averages )):
113+ averages_out [ projects [i ] ] = averages [i ]
114+
115+ return averages_out , indexes
116+
117+
118+ def matching_first_round (students , projects , max_per_projects , preferences , rankings , ranking_map ):
119+ indexes = get_averages_of_preferences (projects , preferences )
120+
121+ allocations = {project : [] for project in projects }
122+ proposals = {student : '' for student in students }
123+ ranking_allocations = {student : '' for student in students }
124+ for i in indexes :
125+ project = projects [i ]
126+ proejct_rankings = rankings [project ]
127+
128+ for j , item in enumerate (proejct_rankings ):
129+ student = item [0 ]
130+ pref = item [1 ]
131+ if not proposals [student ] and (pref in ['1' ,'2' ,'3' ,'4' ,'5' ]):
132+ allocations [project ].append (student )
133+ proposals [student ] = pref
134+ ranking_allocations [student ] = ranking_map [project ][student ]
135+
136+ allocations [project ].sort (key = lambda s : int (preferences [s ][project ]))
137+
138+ if len (allocations [project ]) > max_per_projects [project ]:
139+ rejected_student = allocations [project ].pop ()
140+ proposals [rejected_student ] = ''
141+ ranking_allocations [rejected_student ] = ''
142+
143+ unassigned_students = []
144+ for sid , pref in proposals .items ():
145+ if not pref :
146+ unassigned_students .append (sid )
147+
148+ return allocations , proposals , ranking_allocations , unassigned_students
149+
150+
151+ def checking (projects , max_per_projects , preferences , allocations , proposals , ranking_allocations , unassigned_students ):
152+ students = []
153+
154+ for student in students :
155+ this_group = ''
156+ this_proposal = proposals [student ]
157+ this_prefs = dict (sorted (preferences [student ].items (), key = lambda a : int (a [1 ])))
158+
159+ for project , members in allocations .items ():
160+ if student in members :
161+ this_group = project
162+ break
163+
164+ possible_projects = []
165+ i = 0
166+ for pro , pref in this_prefs .items ():
167+ if i < 3 :
168+ possible_projects .append (pro )
169+ i += 1
170+
171+ for pro in possible_projects :
172+ assigned_memnbers = allocations [pro ]
173+ for member in assigned_memnbers :
174+ their_prefs = dict (sorted (preferences [member ].items (), key = lambda a : int (a [1 ])))
175+ if member not in students :
176+ print (member , their_prefs )
177+
178+
179+ def write_csv (allocations , proposals , ranking_allocations ):
180+ allocations_items = []
181+ for project , students in allocations .items ():
182+ temp = []
183+ temp .append (project )
184+ for student in students :
185+ temp .append (student )
186+ allocations_items .append (temp )
187+
188+ save ('allocations.csv' , allocations_items )
189+
190+
191+ proposals_items = []
192+ for project , students in allocations .items ():
193+ temp = []
194+ temp .append (project )
195+ for student in students :
196+ proposal = proposals [student ]
197+ temp .append (str (proposal ))
198+ proposals_items .append (temp )
199+
200+ save ('proposals.csv' , proposals_items )
201+
202+ ranking_allocations_items = []
203+ for project , students in allocations .items ():
204+ temp = []
205+ temp .append (project )
206+ for student in students :
207+ ranking_allocation = ranking_allocations [student ]
208+ temp .append (str (ranking_allocation ))
209+ ranking_allocations_items .append (temp )
210+
211+ save ('ranking_allocations.csv' , ranking_allocations_items )
212+
213+
214+ def save (filename , items ):
215+ with open (PATH + '/output1/' + filename , 'w' , newline = '' ) as file :
216+ writer = csv .writer (file )
217+ for item in items :
218+ writer .writerow (item )
219+
220+
221+ if __name__ == '__main__' :
222+ students , projects , max_per_projects , preferences , rankings , ranking_map = read_data_and_clean ()
223+
224+ allocations , proposals , ranking_allocations , unassigned_students = matching_first_round (students , projects , max_per_projects , preferences , rankings , ranking_map )
225+ # checking(projects, max_per_projects, preferences, allocations, proposals, ranking_allocations, unassigned_students)
226+
227+ write_csv (allocations , proposals , ranking_allocations )
0 commit comments