Individual.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import sys
  2. from copy import deepcopy
  3. from functools import reduce
  4. from random import choice
  5. import numpy as np
  6. import pandas as pd
  7. class GeneticAlgorithmConnect(object):
  8. def __init__(self, min_ini=pd.Timedelta('0 days 00:15:00')):
  9. self.flight_info = pd.DataFrame()
  10. self.min_ini = min_ini
  11. def initialize_flight_info(self):
  12. signal_day_ = pd.read_csv('Bin\\Data\\Signal_day.csv')
  13. signal_day_['DES_REAL_LANDING'] = pd.to_datetime(signal_day_['DES_REAL_LANDING'])
  14. signal_day_['DEP_REAL_TAKEOFF'] = pd.to_datetime(signal_day_['DEP_REAL_TAKEOFF']) + self.min_ini
  15. self.flight_info = signal_day_.sort_values('DES_REAL_LANDING')
  16. def marshaling_result(self, seat):
  17. self.flight_info['Seat'] = seat
  18. self.flight_info['DEP_REAL_TAKEOFF'] -= self.min_ini
  19. self.flight_info.to_csv('Bin\\Data\\Result.csv', index=False)
  20. class GeneticAlgorithm:
  21. def __init__(self,
  22. dna_length=50,
  23. population_number=100,
  24. cross_probability=0.3,
  25. mutation_probability=0,
  26. generate_number=20,
  27. target='max'
  28. ):
  29. self.dna_length = dna_length
  30. self.population_number = population_number
  31. self.cross_probability = cross_probability
  32. self.mutation_probability = mutation_probability
  33. self.generate_number = generate_number
  34. self.target = 1 if target == 'max' else -1
  35. self.connect_data = GeneticAlgorithmConnect()
  36. self.boys = pd.DataFrame([], columns=['name', 'fitness', 'actual_fitness'])
  37. def initialize_connect_class(self):
  38. self.connect_data.initialize_flight_info()
  39. def decimal_individual(self):
  40. fi = self.connect_data.flight_info
  41. pork = list(range(self.dna_length))
  42. boy = []
  43. for index, row in fi.iterrows():
  44. valid = self.valid_pork(boy, row) + list(set(pork) ^ set(list(set(boy)))) if boy else pork
  45. if valid:
  46. boy.append(choice(valid))
  47. else:
  48. print('初代无解,程序退出')
  49. sys.exit()
  50. return boy
  51. def valid_pork(self, boy, row):
  52. assigned_position = self.connect_data.flight_info.iloc[:len(boy)].copy()
  53. assigned_position['Seat'] = boy
  54. takeoff_time = assigned_position.groupby('Seat').apply(lambda x: x['DEP_REAL_TAKEOFF'].max())
  55. return takeoff_time[takeoff_time < row['DES_REAL_LANDING']].index.tolist()
  56. @staticmethod
  57. def duplicate_removal(some_list):
  58. return reduce(lambda x, y: x if y in x else x + [y], [[], ] + some_list)
  59. def get_boys(self):
  60. boys = []
  61. while len(boys) < self.population_number:
  62. boys.append(self.decimal_individual())
  63. boys = self.duplicate_removal(boys)
  64. self.boys = pd.DataFrame([], columns=['name', 'fitness']) # Collecting fitness in a moment
  65. self.boys['name'] = boys
  66. def get_fitness(self):
  67. fi = self.connect_data.flight_info.copy()
  68. fitness = []
  69. for boy in self.boys['name'].values:
  70. fi['Seat'] = boy
  71. fitness.append(fi.groupby('Seat').apply(self.get_diff).sum())
  72. self.make_up(fitness) # never go out without make-up
  73. self.sort_values()
  74. def make_up(self, fitness):
  75. self.boys['actual_fitness'] = fitness
  76. self.boys['fitness'] = fitness
  77. self.boys = self.boys.fillna(max(fitness) if self.target > 0 else min(fitness))
  78. self.boys['fitness'] *= self.target
  79. self.boys['fitness'] = self.boys['fitness'] - self.boys['fitness'].min() + 1e-5
  80. self.boys['fitness'] = self.boys['fitness'].ffill()
  81. def sort_values(self): # It's always a ascending order
  82. self.boys = self.boys.sort_values('fitness').reset_index(drop=True)
  83. @staticmethod
  84. def get_diff(x):
  85. x = x.sort_values('DES_REAL_LANDING')
  86. if (x['DES_REAL_LANDING'] < x['DEP_REAL_TAKEOFF'].shift()).any():
  87. return np.nan
  88. return (x['DES_REAL_LANDING'] - x['DEP_REAL_TAKEOFF'].shift()).sum().total_seconds()
  89. def selection(self):
  90. idx = np.random.choice(self.population_number, size=self.population_number, replace=True,
  91. p=self.boys['fitness'] / self.boys['fitness'].sum())
  92. self.boys = self.boys.iloc[idx].copy()
  93. self.sort_values()
  94. def crossover(self):
  95. boys = self.boys['name'].values
  96. girls = deepcopy(boys)
  97. def should_recovery(index_):
  98. if not self.is_the_boy_healthy(boy):
  99. boy[:] = girls[index_]
  100. for index, boy in enumerate(boys): # some children is unattractive
  101. if index == 0:
  102. boy[:] = girls[-1]
  103. elif np.random.rand() < self.cross_probability: # the boy should change
  104. girl = choice(girls)
  105. exchange_of_chromosomes = np.random.randint(self.dna_length, size=self.population_number)
  106. for chromosome in list(set(exchange_of_chromosomes.tolist())):
  107. boy[chromosome] = girl[chromosome]
  108. should_recovery(index)
  109. if self.mutation_probability > 0:
  110. for chromosome in range(self.dna_length):
  111. if np.random.rand() < self.mutation_probability:
  112. boy[chromosome] = np.random.randint(self.dna_length)
  113. should_recovery(index)
  114. def is_the_boy_healthy(self, boy):
  115. fi = self.connect_data.flight_info.copy()
  116. fi['Seat'] = boy
  117. return fi.groupby('Seat').apply(self.physical_examination).all()
  118. @staticmethod
  119. def physical_examination(x):
  120. if x.shape[0] > 1:
  121. x = x.sort_values('DES_REAL_LANDING')
  122. return not (x['DEP_REAL_TAKEOFF'].shift() > x['DES_REAL_LANDING']).any()
  123. return True
  124. def marshaling_result(self):
  125. self.connect_data.marshaling_result(self.boys.iloc[0]['name'])