Kaggle competition: Santa's Workshop Tour 2019
<SOS> metric: SantaWorkshopSchedule2019 Kaggle data source: santas-workshop-tour-2019<train_model>
!pip install pulp
selector = SelectKBest(f_classif, len(select_features))
selector.fit(train, target)
 scores = -np.log10(selector.pvalues_)
 indices = np.argsort(scores)[::-1]
print('Features importance:')
 for i in range(len(scores)) :
print('%.2f %s' %(scores[indices[i]], select_features[indices[i]]))<choose_model_class>
data = pd.read_csv('/kaggle/input/santa-workshop-tour-2019/family_data.csv', index_col='family_id' )
numpy.random.seed(7)
 model = models.Sequential()
model.add(Dense(30,input_dim=15,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(15,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(5,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1,activation='sigmoid'))
model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])
 model.fit(train,target,epochs=150, batch_size=20, verbose=1 )<predict_on_test>
N_FAM = len(data)
 N_DAY = 100
MAX_OCC = 300
MIN_OCC = 125
cost_dict = {0: [ 0, 0],
1: [ 50, 0],
2: [ 50, 9],
3: [100, 9],
4: [200, 9],
5: [200, 18],
6: [300, 18],
7: [300, 36],
8: [400, 36],
9: [500, 36 + 199],
10: [500, 36 + 398],
}
def cost(choice, members, cost_dict):
x = cost_dict[choice]
return x[0] + members * x[1]
all_costs = {k: pd.Series([cost(k, x, cost_dict)for x in range(2,9)], index=range(2,9)) for k in cost_dict.keys() }
family_sizes = data.n_people.values.astype(np.int8)
 family_cost_matrix = np.zeros(( N_DAY,N_FAM))
for i, el in enumerate(family_sizes):
family_cost_matrix[:, i] += all_costs[10][el]
for j, choice in enumerate(data.drop("n_people",axis=1 ).values[i,:]):
family_cost_matrix[choice-1, i] = all_costs[j][el]
def accounting_penalty_day(occupancy_day, occupancy_next_day):
return max(0,(( occupancy_day-MIN_OCC)/400)*occupancy_day**(0.5 +(abs(occupancy_day-occupancy_next_day)) /50))
accounting_matrix = np.zeros([MAX_OCC-MIN_OCC+1,MAX_OCC-MIN_OCC+1])
 for i, x in enumerate(range(MIN_OCC,MAX_OCC+1)) :
for j, y in enumerate(range(MIN_OCC,MAX_OCC+1)) :
accounting_matrix[i,j] = accounting_penalty_day(x,y )
prc = model.predict(train)
 prc = [round(x[0])for x in prc]
accuracy_score(target,prc )<predict_on_test>
def calculate_penalty(assignments, fam_sizes=family_sizes,
fam_cost_matrix=family_cost_matrix, account_matrix=accounting_matrix):
penalty = 0
daily_occupancy = np.zeros(N_DAY+1, dtype=np.int16)
 for index,(day, fam_size)in enumerate(zip(assignments, fam_sizes)) :
day_index = day-1
daily_occupancy[day_index] += fam_size
penalty += fam_cost_matrix[day_index,index]
daily_occupancy[-1] = daily_occupancy[-2]
for day in range(N_DAY):
n = daily_occupancy[day]
n_next = daily_occupancy[day+1]
violation = n < MIN_OCC or n > MAX_OCC
if violation:
penalty += 1e11
elif MIN_OCC <= n_next <= MAX_OCC:
penalty += account_matrix[n-MIN_OCC, n_next-MIN_OCC]
return penalty
snum = 0
enum = len(test)
 prdt2 = model.predict(test)
 prdt2 = [round(x[0])for x in prdt2]
prdt2 = list(map(int,prdt2))
print('Predicted result: ', prdt2 )<save_to_csv>
def retrieve_indices(day_or_fam_value, value_is_fam_bool):
indices = []
for index, v in enumerate(x):
var_name = v.name
var_name_split = var_name.split('_')
 if value_is_fam_bool:
value = int(var_name_split[1])
 else:
value = int(var_name_split[2])- 1
if value == day_or_fam_value:
indices.append(index)
 return indices
santa_prob = LpProblem("SantaWorkshopTour",LpMinimize)
 x = []
match_fam_sizes = []
cost_dict = {}
for fam in range(N_FAM):
day_index_array = np.argsort(family_cost_matrix[:,fam])
 for day in day_index_array[0:4]:
x.append(LpVariable(f'x_{fam}_{day+1}',0,1,LpInteger))
match_fam_sizes.append(family_sizes[fam])
 cost_dict[x[-1]] = family_cost_matrix[day,fam]
z = []
for day in range(N_DAY):
z.append(LpVariable(f'z_{day+1}',0,1,LpInteger))
santa_prob += lpSum([cost_dict[value]*x[index] for index, value in enumerate(x)])
 M = MAX_OCC-MIN_OCC
for day in range(N_DAY):
fam_indices = retrieve_indices(day, False)
 santa_prob += lpSum([match_fam_sizes[fam_index]*x[fam_index] for fam_index in fam_indices])>= MIN_OCC
santa_prob += lpSum([match_fam_sizes[fam_index]*x[fam_index] for fam_index in fam_indices])- M*z[day] <= MIN_OCC
for fam in range(N_FAM):
day_indices = retrieve_indices(fam, True)
 santa_prob += lpSum([x[day_index] for day_index in day_indices])== 1
max_diff = 175
correction = 120
alpha = 0.2
rhs = max_diff + alpha*MIN_OCC
for day in range(N_DAY-1):
fam_indices = retrieve_indices(day, False)
 fam_indices_plus = retrieve_indices(day+1, False)
 santa_prob +=(lpSum([match_fam_sizes[fam_index]*(1+alpha)*x[fam_index] for fam_index in fam_indices])
 -lpSum([match_fam_sizes[fam_index]*x[fam_index] for fam_index in fam_indices_plus])
 + correction*z[day] <= rhs)
 santa_prob +=(lpSum([match_fam_sizes[fam_index]*x[fam_index] for fam_index in fam_indices_plus])
 -lpSum([match_fam_sizes[fam_index]*(1-alpha)*x[fam_index] for fam_index in fam_indices])
 + correction*z[day] <= rhs )
sampl['Survived'] = pd.DataFrame(prdt2)
 sampl.to_csv('submission.csv', index=False )<set_options>
time_lim = 10000
messaging = 1
gap = 0
santa_prob.solve(pulp.PULP_CBC_CMD(maxSeconds=time_lim, msg=messaging, fracGap=gap))
print('Status: ' + str(LpStatus[santa_prob.status])+ ', Value: ' + str(value(santa_prob.objective)))
 solution_df = pd.DataFrame(np.zeros(N_FAM), columns = ['assigned_day'], dtype=np.int8)
 for index, v in enumerate(santa_prob.variables()):
var_name = v.name
if v.varValue == 1 and 'x' in var_name:
var_name_split = var_name.split('_')
 fam = int(var_name_split[1])
 day = int(var_name_split[2])
 solution_df.iat[fam,0] = day
solution = solution_df['assigned_day']
solution_penalty = calculate_penalty(solution)
 solution_df.to_csv(f'SantaPuLP_{int(solution_penalty)}.csv', index_label='family_id' )
%matplotlib inline<load_from_csv>
def local_search(best_solution, best_penalty, time_limit):
start = timer()
time_since_start = 0
current_solution = best_solution.copy()
current_penalty = best_penalty
new_solution = best_solution.copy()
new_penalty = best_penalty
choice_index = 0
while time_since_start < time_limit:
improvement = False
random_permutation = np.random.permutation(N_FAM)
 for fam in random_permutation:
time_since_start = round(( timer() -start))
if time_since_start > time_limit:
break
if current_solution[fam] == data.iat[fam,choice_index]:
continue
new_solution = current_solution.copy()
new_solution[fam] = data.iat[fam,choice_index]
new_penalty = calculate_penalty(new_solution)
 if new_penalty < current_penalty:
current_solution = new_solution.copy()
current_penalty = new_penalty
if new_penalty < best_penalty:
best_solution = new_solution.copy()
best_penalty = new_penalty
improvement = True
if improvement:
choice_index = 0
else:
choice_index += 1
if choice_index == 10:
return best_solution
return best_solution
<count_missing_values><EOS> 
ls_time_limit = 900
final_solution = local_search(solution, solution_penalty, ls_time_limit)
 final_solution_penalty = calculate_penalty(final_solution)
 final_solution_df = pd.DataFrame(final_solution, columns=['assigned_day'])
 final_solution_df.to_csv(f'SantaPuLP_{int(final_solution_penalty)}.csv', index_label='family_id' )