ai

GA-1208

hyebing_KIM 2023. 12. 8. 15:58
# import
import random
import pandas as pd
import openpyxl
import numpy as np
import matplotlib.pyplot as plt
import copy
# calling the data
Parameter=pd.read_csv(r"C:\Users\user\Desktop\Parameter.csv")
Test_50_Data=pd.read_csv(r"C:\Users\user\Desktop\Test_50_Data.csv")
Test_50_Data = Test_50_Data.iloc[1:,1:] # 여기서 행이 16개만 뽑힘
Test_50_Data.head()

# number of row and column
people_row=len(Test_50_Data) #16 타임 시간 6:00~ 7:30
people_column=len(Test_50_Data.columns)-30 # 20 라인

#coefficients
zero_payload_desel=Parameter.iloc[0,1]
zero_payload_electric=Parameter.iloc[1,1]
variable_electric=Parameter.iloc[0,2]
variable_desel=Parameter.iloc[1,2]
ratio_desel=Parameter.iloc[0,3]
ratio_electric=Parameter.iloc[1,3]

# lists
fitness_value=[]
num_generation=[]
last_optimal=[]
repaired_population=[]
operating_interval = []
parameter_answer=[]

# Ebs constraint
Ebs_constraint=80
Ebs_constraint_list= pd.DataFrame([Ebs_constraint]*16).T


#interval of dispatching and distance

dispatching_interval = [5, 10, 20, 20, 10, 5, 5, 10, 20, 20, 10, 5, 10, 5, 5, 20, 10, 20, 5, 5, 10, 20, 20,10, 20, 20, 10, 5]
distance = [59, 30, 39, 70, 86, 60, 70, 35, 62, 57, 82, 44, 53, 74, 84, 48, 46, 87, 81, 50, 61, 34, 42, 49 ]
dispatching_interval = dispatching_interval[:20]
distance = distance[:20]


# operatng_interval
for _ in range(len(distance)) :
    if distance[_] <=30 :
       operating_interval .append(1)
    elif distance[_] >31 and distance[_] <=60:
        operating_interval .append(2)
    else :
        operating_interval.append(3)


# repair_rule
def repair_rule(repair):

    repair = pd.DataFrame(repair)

    while repair.values.sum() >= Ebs_constraint and repair.values.sum() >= Ebs_constraint :
                row = random.randint(0,people_row-1)  
                col = random.randint(0,people_column-1)  

                if repair.iloc[row, col] == 1 :
                    repair.iloc[row, col] = 0
               
    repair = repair.values.tolist()
    return repair

# initialize population
def initialize_population(population_size):
   
    pre_population = [[[random.randint(0, 1) for _ in range(people_column)] for _ in range(people_row)] for _ in range(population_size)]

    # for i in range(population_size) :
    #     repaired_population.append(repair_rule(pre_population[i]))

    # return repaired_population

    return pre_population

    #interpreter
def interpreter(subject):
   
    interpreted = subject

    for col in range (len(operating_interval)) : # 20번
        if operating_interval[col] == 2:
            for row in range(1, interpreted .shape[0]) :
                if row  % 2 != 0 : #
                     interpreted .iloc[row , col] =2
        elif operating_interval[col] == 3:
            for row in range(1, interpreted .shape[0]) :
                if row  % 4 != 0 :
                     interpreted .iloc[row , col] =2      
   
    return interpreted


def changing_capacity(interpreted): # 거리 고려 완료
     
    def_list = copy.deepcopy(Ebs_constraint_list)
   
    for col in range (len(operating_interval)) : # 20번

        if operating_interval[col] == 1:
            for row in range(interpreted.shape[0]-1):
                try:
                    if interpreted.iloc[row, col] == 1:
                        def_list.iloc[:,row+1:row+13] -= 1
                        # Ebs_constraint_list.iloc[row+13, col] += 1
                except IndexError:
                        continue
        elif operating_interval[col] == 2:
            for row in range(interpreted.shape[0]-1):
                try:
                    if interpreted.iloc[row, col] == 1:
                        def_list.iloc[:,row+1:row+25] -= 1
                except IndexError:
                        continue
        else :
             for row in range(interpreted.shape[0]-1):
                try:
                    if interpreted.iloc[row, col] == 1:
                        def_list.iloc[:,row+1:row+37] -= 1
                except IndexError:
                        continue

    return def_list


# fitness function
def fitness(individual): #a = best_individual = 16x20
    global people
   
    total_value = 0
    individual = pd.DataFrame(individual)
    interpreted = interpreter(individual)
    num_row_Ebs = interpreted.apply(lambda x: x.value_counts().get(1,0 ), axis=1)
    num_row_Ebs = pd.DataFrame(num_row_Ebs)
    Ebs_capacity= changing_capacity(interpreted)
   
    # print(num_row_Ebs)
    # print(Ebs_capacity)
   
    for i in range(len(num_row_Ebs)):
        if num_row_Ebs.iloc[i] >Ebs_capacity.iloc[i] :
             return 1/99999999
             
   
    for row in range(people_row):  # 16
        for column in range(people_column):  # 20
            if interpreted.iloc[row, column] == 1:
                total_value += (distance[column] * zero_payload_electric + variable_electric * distance[column] * people.iloc[row, column]) * 0.6
            elif interpreted.iloc[row, column] ==0 :
                total_value += (distance[column] * zero_payload_desel + variable_desel * distance[column] * people.iloc[row,column]) * 3.06

    return 1/total_value

# 교차 연산 (두 부모에서 두 자식 생성)
def crossover(parent1, parent2): # 3x50 을 2개 받아왔음
    crossover_point = random.randint(1, len(parent1) - 2)
    child1 = np.concatenate((parent1[:crossover_point], parent2[crossover_point:])) # 16x20의 형태를 갖춰야한다 , 수정 바람
    child2 = np.concatenate((parent2[:crossover_point] , parent1[crossover_point:]))
    child1 = child1.tolist()
    child2 = child2.tolist()
    return child1, child2

# 돌연변이 연산 (돌연변이가 발생할 확률이 있음)
def mutate(individual, mutation_rate):
    mutated_individual =  [[] for _ in range(people_row)]
   
    for i in range(len(individual)):
        for gene in individual[i]:
            if random.random() < mutation_rate:
                mutated_individual[i].append(1 - gene)  
            else:
                mutated_individual[i].append(gene)
           
    return mutated_individual

# 유전 알고리즘 메인 함수
def genetic_algorithm(population_size, generations, crossover_rate, mutation_rate):
    population = initialize_population(population_size)
    global count
    global last_optimal
    global parameter_answer
    global fitness_value
    for generation in range(generations):
       
        population.sort(key=fitness, reverse=True) ###########################################################

        # 적합도가 가장 높은 개체 출력
        best_individual = population[0]  
        a=best_individual

        print(f"Generation {generation + 1}: Best Individual - {best_individual}, Fitness - {1/(fitness(a))}")
        fitness_value.append(1/fitness(a))
        num_generation.append(generation+1)
       
        # 새로운 세대 생성
        new_population = []

        # 엘리트 개체(적합도가 가장 높은 개체)는 그대로 다음 세대로 전이 , 10개
        for i in range(int(population_size/10)):
            new_population.append(population[i])


        # 교차 연산과 돌연변이 연산을 통해 새로운 개체 생성 ,# 여기에 룰렛 룰 적용하면 될듯 random choice 를 바꿔 #여기서 population 을 잘못 만들고 있음
        while len(new_population) < population_size:
            parent1 = random.choice(population) # parent 1 = 16x20 matrix
            parent2 = random.choice(population)
            child1, child2 = crossover(parent1, parent2)
            child1 = mutate(child1, mutation_rate)
            child2 = mutate(child2, mutation_rate)

            # child1 = repair_rule(child1) # repaired
            # child2 = repair_rule(child2)


            new_population.extend([child1,child2])

        # 현재 세대 갱신
        population = new_population
       
    last_optimal=a #population[0]
    parameter_answer.append(last_optimal)
   
    return a #population[0] =best individaul

if __name__ == "__main__":
      people=Test_50_Data
      genetic_algorithm(population_size=20, generations=1, crossover_rate=0.8, mutation_rate=0.05)


print("last optimal " )
print(last_optimal)
print("people")

# print("---------------------")
# print(people_row)
# print(people_column)
# print(Test_50_Data)


last_optiaml = pd.DataFrame(last_optimal)
sum = last_optiaml.values.sum()
row_sums = last_optiaml.sum(axis=1)
print("total ebs = " , sum)
print("dispatching_interval = ", dispatching_interval)
print("operatining_interval : ", operating_interval)
print( "Row Sums:")
print(row_sums)





# figure
plt.plot(num_generation, fitness_value, marker='o')
plt.title('Fitness over Generations')
plt.xlabel('Generation')
plt.ylabel('Fitness')
plt.grid(True)
plt.show()

추가 

 

거리에 따라 돌아오는 데 까지 걸리는 시간을 1, 2, 3 으로 나눴음 

 

거리가 1일 경우 12타임 사용불가,

거리가 2일 경우 24타임 사용 불가,

거리가 3일경우 36타임 사용 불가

 

fitness 를 계산하기전에 interpreted 해야함 

 

이때 interpreted 된다는 것은 배차간격 때문에 여러개의 1 , 0 이 하나의 1 등으로 바뀐다는 것

 

예를들어 배차간격이 20분인 라인은 4개의 숫자가 하나의 숫자로 해석됨 

 

이렇게 하는 과정을 

 

1  0 0 1 >> 1 2 2 2

1 1 1 1 >>> 1 2 2 2

1 0 0 0 >>> 1 2 2 2 

0100 >>> 0222

 

이런식으로 바꿈

 

fitness 계산할 때에는 

 

1과 0만 계산에 포함하고 2는 계산에 포함하지 않음 

 

이를 통해서 interpreted 의 fitness 를 계산할 수 있음. 

 

 

 

 

'ai' 카테고리의 다른 글

GA- 12-24  (0) 2023.12.24