Commitv7

parent 1cfd4b4d
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Using TensorFlow backend.\n"
]
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import math\n",
"import random\n",
"import time\n",
"import pandas as pd\n",
"import csv\n",
"import sys\n",
"import datetime\n",
"import timeit\n",
"from sklearn.preprocessing import MinMaxScaler\n",
"from keras.models import Sequential\n",
"from keras.layers import Bidirectional, GlobalMaxPool1D\n",
"from keras.layers import LSTM\n",
"from keras.layers import Dropout, Dense"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"#Load dataset sebelum integrasi\n",
"#Datax = pd.read_csv('./Yolanda/tri/Data Toba Samosir_Sheet3.csv')\n",
"#Datax.drop(Datax.filter(regex=\"Unname\"),axis=1, inplace=True)\n",
"Datax = pd.read_csv('./Data Toba Samosir_Sheet1.csv')\n",
"#Datax = pd.read_csv('./Data_Dianalisis.csv')\n",
"Datax.drop(Datax.filter(regex=\"Unname\"),axis=1, inplace=True)\n",
"Dataz = pd.read_csv('./List_city.csv')\n",
"#Dataz = pd.read_csv('./List_city_Data_Dianalisis.csv')\n",
"Dat = Datax.to_numpy()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"start = datetime.datetime.strptime(\"21-07-2020\", \"%d-%m-%Y\")\n",
"end = datetime.datetime.strptime(\"22-07-2020\", \"%d-%m-%Y\")\n",
"date_generated = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]\n",
"#print(len(date_generated))"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"cost = 400000\n",
"Cost = int(cost)\n",
"#min_cost = 399333"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"class Fitness_value:\n",
" def getting_max_distance():\n",
" max_distance = 0 \n",
" max_distance += len(date_generated) * 720\n",
" return max_distance\n",
" def getting_max_cost():\n",
" max_cost = 0\n",
" max_cost +=Cost\n",
" return max_cost"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"#import dataset from data.csv file\n",
"dataset = pd.read_csv('./SuhuKabTobaSamosir.csv')\n",
"dataset = dataset.dropna(subset=[\"Temperature\"])\n",
"dataset = dataset.reset_index(drop=True)\n",
"training_set = dataset.iloc[:,2:3].values"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"#Feature Scaling \n",
"sc = MinMaxScaler(feature_range=(0,1))\n",
"training_set_scaled = sc.fit_transform(training_set)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"x_train = []\n",
"y_train = []\n",
"n_future = len(date_generated) # next 5 days temperature forecast\n",
"n_past = 30 # Past 30 days \n",
"for i in range(0,len(training_set_scaled)-n_past-n_future+1):\n",
" x_train.append(training_set_scaled[i : i + n_past , 0]) \n",
" y_train.append(training_set_scaled[i + n_past : i + n_past + n_future , 0 ])\n",
"x_train , y_train = np.array(x_train), np.array(y_train)\n",
"x_train = np.reshape(x_train, (x_train.shape[0] , x_train.shape[1], 1) )"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/20\n",
"91/91 [==============================] - 3s 36ms/step - loss: 0.1736 - acc: 0.0110\n",
"Epoch 2/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0574 - acc: 0.0110\n",
"Epoch 3/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0410 - acc: 0.0000e+00\n",
"Epoch 4/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0481 - acc: 0.0220\n",
"Epoch 5/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0250 - acc: 0.0000e+00\n",
"Epoch 6/20\n",
"91/91 [==============================] - 0s 4ms/step - loss: 0.0372 - acc: 0.0110\n",
"Epoch 7/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0314 - acc: 0.0110\n",
"Epoch 8/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0264 - acc: 0.0110\n",
"Epoch 9/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0244 - acc: 0.0000e+00\n",
"Epoch 10/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0278 - acc: 0.0000e+00\n",
"Epoch 11/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0228 - acc: 0.0110\n",
"Epoch 12/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0263 - acc: 0.0110\n",
"Epoch 13/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0264 - acc: 0.0110\n",
"Epoch 14/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0250 - acc: 0.0110\n",
"Epoch 15/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0230 - acc: 0.0110\n",
"Epoch 16/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0269 - acc: 0.0110\n",
"Epoch 17/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0247 - acc: 0.0110\n",
"Epoch 18/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0263 - acc: 0.0110\n",
"Epoch 19/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0246 - acc: 0.0110\n",
"Epoch 20/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0250 - acc: 0.0110\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.callbacks.History at 0x1e05e61bef0>"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"regressor = Sequential()\n",
"regressor.add(Bidirectional(LSTM(units=30, return_sequences=True, input_shape = (x_train.shape[1],1) ) ))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(LSTM(units= 30 , return_sequences=True))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(LSTM(units= 30 , return_sequences=True))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(LSTM(units= 30))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(Dense(units = n_future,activation='linear'))\n",
"regressor.compile(optimizer='adam', loss='mean_squared_error',metrics=['acc'])\n",
"regressor.fit(x_train, y_train, epochs=20,batch_size=32 )"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# read test dataset\n",
"testdataset = pd.read_csv('./testing.csv')\n",
"#get only the temperature column\n",
"testdataset = testdataset.iloc[:30,1:2].values\n",
"real_temperature = pd.read_csv('./SuhuKabTobaSamosir.csv')\n",
"real_temperature = real_temperature.iloc[:30,2:3].values\n",
"testing = sc.transform(testdataset)\n",
"testing = np.array(testing)\n",
"testing = np.reshape(testing,(testing.shape[1],testing.shape[0],1))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"predicted_temperature = regressor.predict(testing)\n",
"predicted_temperature = sc.inverse_transform(predicted_temperature)\n",
"predicted_temperature = np.reshape(predicted_temperature,(predicted_temperature.shape[1],predicted_temperature.shape[0]))"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"def get_weather ():\n",
" for i in range(len(predicted_temperature)):\n",
" weat= predicted_temperature[0][0]\n",
" return weat"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"27.432116"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Weather = get_weather ()\n",
"Weather"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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bKoVNXjwYN58801EhHvvvZfbbruNP/zhD9x+++3cfffdDBo0iBUrVtCuXTtuvfVWbr/9dp5++unMj70ZXFE4jlNYPvzQzEDx/gnYMkT2kKT9y3KjqclmBW3bZrddmzY2C8mwtHdoeopn0qRJXHnllYD1lujdu/cmRXHCCSdsKjv+/PPP8/zzzzNggPVjW7FiBXPmzKGhoYHzzz+fLkHxwnD9xsZGLrroIubPn8+6devYfffdARg0aBBXX301l156Keeeey49e/bM7pgzxBWF4ziFJZkjGzYrihY6gbe68//oI0u069s3fVhsMj75xMxW8dFZWZCudl779u23WO+GG27ge9/73hbr3HnnnUnLlF955ZVcffXVnHnmmUycOJGbb74ZgOuvv57TTjuN8ePHc9hhh/HCCy/kJHdzuI/CcZzCUl9vd+v777/l8h13hE6d8hv51NQEX31lvolslQSY83vjRhsjB4466ihGjRoFwPvvv8+nn37KPvvss9V6J510Evfffz8rVqwA4PPPP+fLL7/km9/8JmPGjGFxEKobmp7iy4/HYrFN43z44Yf06dOHn/70pwwcOJDZs2dvVdI8H7iicBynsDQ0wH77WcOiRPIdIvvVV5nlTqSifXuTM8ecih/+8Ids2LCBPn36cNFFFzFixAi2TXLcJ554IpdccgmHH344ffr04fzzz2f58uUccMAB/OxnP+Poo4+mX79+XH311QDcfPPNXHDBBRx55JGbzFJgs6kDDzyQfv36sd1223HKKafQt29f2rRpQ79+/fLmzPYy447jFJYePeC44+CBB7b+7JxzLGN7xoyshkxZZnz2bJtVHHBAzi1OmT/fSqL36ZNcuZUxXmbccZzSY+FCmDdva/9ESDijyMcN65o1Fu1UU5O7koDNsxHP1N5EwRSFiPQSkZdFZJaIzBSRq4Ll/UXkTRGpF5EpIpI03EFE6kRkTvCoK5ScjuMUkLC0eCrncG2tZUTn46IcjpGr2Slkm22gY0cbr4IsLi2hkDOKJuAaVd0POAz4kYjsD9wG/FJV+wP/HbzfAhHpDNwEHAocAtwkIp0KKKvjOIWgOUXRgsinLczmYbvTHXawC31L6dIF1q61GUqF0BI3Q8EUharOV9VpwevlwCygB6BAWPN3R2Beks1PAiao6hJV/QqYAJxcKFmdDFizxuLhnfR88IFdYCqF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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"plt.title(\"Forecast vs Actual using RNN\", fontsize=14)\n",
"plt.plot(pd.Series(np.ravel(real_temperature)), \"r\", label=\"Actual\")\n",
"plt.plot(pd.Series(np.ravel(predicted_temperature)), \"k\", label=\"Forecast\")\n",
"plt.legend(loc=\"upper right\")\n",
"plt.xlabel(\"Time\")\n",
"plt.ylabel(\"Temperature\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# PSO"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"# Initialization of PSO parameters,and velocity\n",
"#Number of Agents\n",
"PARTICLE_COUNT = 40;\n",
"#Acceleration Constant\n",
"Acceleration_constant = 2; # Maximum velocity change allowed. Range: 0 >= V_MAX < CITY_COUNT\n",
"#Iterasi\n",
"MAX_EPOCHS = 2\n",
"map = [];\n",
"particles = []\n",
"Maximum_distance= Fitness_value.getting_max_distance()\n",
"CITY_COUNT = 7"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"# define particle function\n",
"class Particle:\n",
" def __init__(self):\n",
" self.mData = [0] * CITY_COUNT\n",
" self.mpBest_distance = 0.9\n",
" self.mVelocity = 0.0\n",
" def get_data(self, index): \n",
" return self.mData[index]\n",
" def set_data(self, index, value):\n",
" self.mData[index] = value\n",
" def get_pBest_distance(self):\n",
" return self.mpBest_distance\n",
" def set_pBest_distance(self, value):\n",
" self.mpBest_distance = value\n",
" def get_velocity(self):\n",
" return self.mVelocity\n",
" def set_velocity(self, velocityScore):\n",
" self.mVelocity = velocityScore "
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"class City:\n",
" def __init__(self):\n",
" self.mX = 0\n",
" self.mY = 0 \n",
"def get_total_distance(index):\n",
" particles[index].set_pBest_distance(0)\n",
" distance_route = []\n",
" distance = 0\n",
" for i in range(CITY_COUNT):\n",
" if i == CITY_COUNT - 1:\n",
" source = particles[index].get_data(CITY_COUNT -1)\n",
" target = particles[index].get_data(0)\n",
" distance_route.append(Datax.iloc[source][target])\n",
" distance = sum(distance_route)\n",
" particles[index].set_pBest_distance(distance) # Complete trip.\n",
" else:\n",
" source = particles[index].get_data(i)\n",
" target = particles[index].get_data(i + 1)\n",
" distance_route.append(Datax.iloc[source][target])\n",
" distance = sum(distance_route)\n",
" particles[index].set_pBest_distance(distance)\n",
" \n",
" return "
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"# mapping city \n",
"def initialize_map():\n",
" for i in range(CITY_COUNT):\n",
" newCity = City()\n",
" map.append(newCity)\n",
" return "
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
"def randomly_arrange(index = 0):\n",
" cityA = random.randrange(0, CITY_COUNT)\n",
" cityB = 0\n",
" done = False\n",
" while not done:\n",
" cityB = random.randrange(0, CITY_COUNT)\n",
" if cityB != cityA:\n",
" done = \tTrue\n",
" # swap cityA and cityB.\n",
" temp = particles[index].get_data(cityA)\n",
" particles[index].set_data(cityA, particles[index].get_data(cityB))\n",
" particles[index].set_data(cityB, temp)\n",
" return "
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"def initialize_particles():\n",
" for i in range(PARTICLE_COUNT):\n",
" newParticle = Particle() \n",
" for j in range(CITY_COUNT):\n",
" newParticle.set_data(j, j) \n",
" particles.append(newParticle) \n",
" for j in range(10): # just any number of times to randomize them.\n",
" randomly_arrange(len(particles) - 1) \n",
" get_total_distance(len(particles) - 1)\n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
"def quicksort(array, left, right):\n",
" pivot = quicksort_partition(array, left, right) \n",
" if left < pivot:\n",
" quicksort(array, left, pivot - 1) \n",
" if right > pivot:\n",
" quicksort(array, pivot + 1, right) \n",
" return array"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"def quicksort_partition(numbers, left, right):\n",
" # The comparison is on each particle's pBest value.\n",
" I_hold = left\n",
" r_hold = right\n",
" pivot = numbers[left] \n",
" while left < right:\n",
" while (numbers[right].get_pBest_distance() >= pivot.get_pBest_distance()) and (left < right):\n",
" right -= 1\n",
"\n",
" if left != right:\n",
" numbers[left] = numbers[right]\n",
" left += 1\n",
" \n",
" while (numbers[left].get_pBest_distance() <= pivot.get_pBest_distance()) and (left < right):\n",
" left += 1 \n",
" if left != right:\n",
" numbers[right] = numbers[left]\n",
" right -= 1 \n",
" numbers[left] = pivot\n",
" pivot = left\n",
" left = I_hold\n",
" right = r_hold\n",
" \n",
" return pivot\n"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"def get_velocity():\n",
" worstResults_distance = 0.0\n",
" vValue_distance = 0.0 \n",
" # After sorting, worst will be last in list.\n",
" worstResults_distance = particles[PARTICLE_COUNT - 1].get_pBest_distance() \n",
" for i in range(PARTICLE_COUNT):\n",
" vValue_distance = (Acceleration_constant * particles[i].get_pBest_distance()) / worstResults_distance \n",
" if (vValue_distance > Acceleration_constant): \n",
" particles[i].set_velocity(Acceleration_constant)\n",
" elif (vValue_distance < 0.0):\n",
" particles[i].set_velocity(0.0)\n",
" else:\n",
" particles[i].set_velocity(vValue_distance) \n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"def copy_from_particle(source, destination):\n",
" # push destination's data points closer to source's data points.\n",
" targetA = random.randrange(0, CITY_COUNT) # source's city to target.\n",
" targetB = 0\n",
" indexA = 0\n",
" indexB = 0\n",
" tempIndex = 0\n",
" \n",
" # targetB will be source's neighbor immediately succeeding targetA (circular).\n",
" for i in range(CITY_COUNT):\n",
" if particles[source].get_data(i) == targetA:\n",
" if i == CITY_COUNT - 1:\n",
" targetB = particles[source].get_data(0) # if end of array, take from beginning.\n",
" else:\n",
" targetB = particles[source].get_data(i + 1)\n",
" \n",
" break\n",
" \n",
" # Move targetB next to targetA by switching values.\n",
" for j in range(CITY_COUNT):\n",
" if particles[destination].get_data(j) == targetA:\n",
" indexA = j\n",
" \n",
" if particles[destination].get_data(j) == targetB:\n",
" indexB = j \n",
" # get temp index succeeding indexA.\n",
" if indexA == CITY_COUNT - 1:\n",
" tempIndex = 0\n",
" else:\n",
" tempIndex = indexA + 1\n",
" \n",
" # Switch indexB value with tempIndex value.\n",
" temp = particles[destination].get_data(tempIndex)\n",
" particles[destination].set_data(tempIndex, particles[destination].get_data(indexB))\n",
" particles[destination].set_data(indexB, temp) \n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
" # updating particles city\n",
"def update_particles():\n",
" # Best was previously sorted to index 0, so start from the second best.\n",
" for i in range(5):\n",
" if i > 0:\n",
" # The higher the velocity score, the more changes it will need.\n",
" changes = math.floor(math.fabs(particles[i].get_velocity()))\n",
" sys.stdout.write(\"Changes for particle \" + str(i) + \": \" + str(changes) + \"\\n\")\n",
" for j in range(changes):\n",
" # 50/50 chance.\n",
" if random.random() > 0.5:\n",
" randomly_arrange(i)\n",
" \n",
" # Push it closer to it's best neighbor.\n",
" copy_from_particle(i - 1, i) \n",
" # Update pBest value.\n",
" get_total_distance(i) \n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"def PSO_algorithm():\n",
" epoch = 0\n",
" done = False \n",
" initialize_particles() \n",
" while not done:\n",
" # Two conditions can end this loop:\n",
" # if the maximum number of epochs allowed has been reached, or,\n",
" # if the Target value has been found.\n",
" if epoch < MAX_EPOCHS:\n",
" for i in range(5): \n",
" sys.stdout.write(\"Route: \") \n",
" for j in range(CITY_COUNT):\n",
" sys.stdout.write(str(particles[i].get_data(j)) + \", \")\n",
" get_total_distance(i) \n",
" sys.stdout.write(\"Distance: \" + str(particles[i].get_pBest_distance()) + \"\\n\") \n",
" if (particles[i].get_pBest_distance() <= Maximum_distance):\n",
" done = True \n",
" quicksort(particles, 0, len(particles) - 1)\n",
" # list has to sorted in order for get_velocity() to work.\n",
" get_velocity() \n",
" update_particles() \n",
" sys.stdout.write(\"epoch number: \" + str(epoch) + \"\\n\") \n",
" epoch += 1 \n",
" else:\n",
" done = True \n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
"def print_best_solution():\n",
" if (particles[0].get_pBest_distance() <= Maximum_distance):\n",
" sys.stdout.write(\"Target reached.\\n\")\n",
" else:\n",
" sys.stdout.write(\"Target not reached.\\n\") \n",
" sys.stdout.write(\"Best Route: \")\n",
" for j in range(CITY_COUNT):\n",
" sys.stdout.write(str(particles[0].get_data(j)) + \", \") \n",
" sys.stdout.write(\"Distance: \" + str(particles[0].get_pBest_distance()) +\"\\n\")\n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Route: 5, 1, 2, 6, 0, 3, 4, Distance: 336.40000000000003\n",
"Route: 0, 2, 6, 3, 1, 4, 5, Distance: 166.60000000000002\n",
"Route: 2, 5, 6, 3, 0, 1, 4, Distance: 248.10000000000002\n",
"Route: 0, 1, 5, 3, 6, 2, 4, Distance: 256.5\n",
"Route: 2, 0, 5, 6, 1, 3, 4, Distance: 220.49999999999997\n",
"Changes for particle 1: 0\n",
"Changes for particle 2: 0\n",
"Changes for particle 3: 0\n",
"Changes for particle 4: 0\n",
"epoch number: 0\n",
"Target reached.\n",
"Best Route: 4, 2, 5, 0, 3, 1, 6, Distance: 153.10000000000002\n"
]
}
],
"source": [
" if __name__ == '__main__':\n",
" initialize_map()\n",
" PSO_algorithm()\n",
" print_best_solution() "
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[4, 2, 5, 0, 3, 1, 6]"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Decode PSO\n",
"def checking_city():\n",
" if (particles[0].get_pBest_distance() <= Maximum_distance):\n",
" Route = []\n",
" for j in range(CITY_COUNT):\n",
" Route.append(particles[0].get_data(j))\n",
" return Route\n",
"Route= checking_city()\n",
"Route"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
"def decoding(Route):\n",
" id_ = 0\n",
" name = []\n",
" for i in range(len(Route)):\n",
" id_= Route[i]\n",
" print(Dataz.iloc[id_][1])\n",
" i+=1\n",
" return "
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Water Park Tambunan\n",
"Pakkodian\n",
"Bukit Pahoda\n",
"Pantai BUL BUL\n",
"Taman Eden 100 Tobasa\n",
"BUKIT travel Gibeon\n",
"Bukit Senyum\n"
]
}
],
"source": [
"decoding(Route)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ACO"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"def generate_start_nodes (individu,n_kota):\n",
" #return : tabulist yang masih berisi start (dan end) node untuk semua individu semut\n",
" start_nodes= []\n",
" for i in range (individu): \n",
" \n",
" start_nodes.append([0 for i in range(n_kota+1)])\n",
" start_nodes[-1][0] = random.randint(0,(n_kota-1))\n",
" start_nodes[-1][-1] = start_nodes[-1][0]\n",
" return start_nodes"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [],
"source": [
"def evaluate_best_city (kota_sekarang, matriks_jarak ,tau, tabulist, alpha, beta):\n",
" #Mengevaluasi kota terbaik yang memungkinkan berdasarkan probabilitas dan tabulist \n",
" \n",
" probability = [0] * np.size(matriks_jarak[1])\n",
" allowed = []\n",
" allowed[:] = [x for x in range(np.size(matriks_jarak[1])) if x not in tabulist]\n",
" p = 0\n",
" for i in allowed:\n",
" visibility = 1/matriks_jarak[kota_sekarang][i]\n",
" p += (tau[kota_sekarang][i]**alpha)*(visibility**beta)\n",
" for i in allowed:\n",
" visibility = 1/matriks_jarak[kota_sekarang][i]\n",
" probability[i] = (tau[kota_sekarang][i]**alpha)*(visibility**beta)/p\n",
" tmp = max(probability)\n",
" return probability.index(tmp)"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [],
"source": [
"def update_tau(individu, tau, tabulists, L, evaporation_coeff, Q,n_kota):\n",
" \"\"\"\n",
" param evaporation: koefisien evaporation\n",
" param tau : matriks tau seukuran kota x kota\n",
" param L : matriks/array[1x16] yang mengandung informasi jarak tour yang\n",
" dihasilkan oleh satu semut\n",
" param delta_tau : matriks seukuran kota x kota\n",
" return : tau yang baru\n",
" \"\"\"\n",
" for i in range (individu):\n",
" for j in range (n_kota):\n",
" delta_tau = Q/L[i]\n",
" tau[tabulists[i][j],tabulists[i][j+1]] = evaporation_coeff * tau[tabulists[i][j],tabulists[i][j+1]] + delta_tau\n",
" return (tau)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [],
"source": [
"def hitung_jarak_1_rute(single_solution,matriks_jarak):\n",
" \"\"\"\n",
" param single_solution: Sebuah tabulist dari seekor semut (1 solusi) [0..16]\n",
" param matriks_jarak : matriks jarak antar node\n",
" return : Total jarak yang dihasilkan solusi tersebut\n",
" \"\"\"\n",
" jarak = 0\n",
" for i in range (len(single_solution)-1):\n",
" jarak += matriks_jarak[single_solution[i]][single_solution[i+1]] \n",
" return (jarak)"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [],
"source": [
"def compute_shortest_distances(tabulists, matriks_jarak):\n",
" \"\"\"\n",
" param tabulists: Tabulist sejumlah individu x banyak kota\n",
" return : tuple (jarak terkecil yang di temukan (float)\n",
" rute dengan jarak terkecil (list),\n",
" list jarak (L)(list)\n",
" rata2 jarak yang ditemukan (float))\n",
" :>>>(min_dist,route,L,rerata)\n",
" \"\"\"\n",
" distances = []\n",
" distances = [0] * len(tabulists)\n",
" for i in range(0,len(tabulists)):\n",
" distances[i] = hitung_jarak_1_rute(tabulists[i],matriks_jarak)\n",
" L = distances\n",
" L = L- 0.97*min(L)\n",
" return (min(distances) , tabulists[distances.index(min(distances))] , L, np.mean(distances))"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [],
"source": [
"def get_cost(Dataz,route):\n",
" Cost = 0 \n",
" id_city = Dataz['ID_City'].to_numpy()\n",
" cost_route = []\n",
" for i in range(len(id_city)): \n",
" for x in range(7):\n",
" if route[x] == id_city[i]:\n",
" cost_route.append(((Dataz.iloc[i][2])))\n",
" Cost = sum(cost_route) \n",
" return(Cost)"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [],
"source": [
"def get_cost(Dataz,route):\n",
" Cost = 0 \n",
" id_city = Dataz['ID_City'].to_numpy()\n",
" cost_route = []\n",
" for i in range(len(id_city)): \n",
" for x in range(7):\n",
" if route[x] == id_city[i]:\n",
" cost_route.append(((Dataz.iloc[i][2])))\n",
" Cost = sum(cost_route) \n",
" return(Cost)"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [],
"source": [
"Maximum_distance = Fitness_value.getting_max_distance()\n",
"Maximum_cost = Fitness_value.getting_max_cost()\n",
"TARGET_weather = Weather\n",
"CITY_COUNT = len(Datax)"
]
},
{
"cell_type": "code",
"execution_count": 80,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"itinerary 1 = [0, 4, 31, 23, 22, 20, 24, 0]\n",
"36.230000000000004 , 25000 , 27.432116\n",
"\n",
"\n",
"itinerary 2 = [5, 22, 4, 14, 35, 20, 31, 5]\n",
"26.85 , 35000 , 27.432116\n",
"\n",
"\n",
"itinerary 3 = [2, 4, 23, 31, 25, 9, 32, 2]\n",
"135.03 , 15000 , 27.432116\n",
"\n",
"\n",
"itinerary 4 = [0, 31, 23, 34, 16, 24, 27, 0]\n",
"94.93 , 0 , 27.432116\n",
"\n",
"\n",
"itinerary 5 = [0, 22, 2, 31, 23, 20, 7, 0]\n",
"57.129999999999995 , 10000 , 27.432116\n",
"\n",
"\n"
]
}
],
"source": [
"running = 5\n",
"global_distance = []\n",
"for run in range (running):\n",
" iterasi = 50\n",
" alpha = 2 #jejak pheromon\n",
" beta = 2#visibility\n",
" individu = 40\n",
" n_kota = jumlah_temapa\n",
" evaporation_coeff = 0.1\n",
" Q = 1\n",
"\n",
" matriks_jarak = Dat\n",
" tau = np.ones(np.shape(matriks_jarak))*0.5 #init. intensitas pheromon/jejak pada busur\n",
" delta_tau = np.zeros((n_kota,n_kota))\n",
"\n",
" shortest_distance = math.inf #infinit\n",
"\n",
" shortest_route = []\n",
" average = []\n",
" for i in range (iterasi):\n",
" tabulists = generate_start_nodes(individu,n_kota)\n",
" for j in range (1,n_kota):\n",
" for k in range (individu):\n",
" tabulists[k][j] = evaluate_best_city(tabulists[k][j-1],matriks_jarak,tau, tabulists[k],alpha,beta)\n",
" min_dist,route,L,rerata = compute_shortest_distances(tabulists,matriks_jarak)\n",
" average.append(rerata)\n",
" min_cost = get_cost(Dataz,route) \n",
"\n",
" if ((shortest_distance > min_dist) and (shortest_distance > Maximum_distance) and (min_cost <=Maximum_cost) and ((Weather >=18) and (Weather <=28))):\n",
" shortest_distance = min_dist\n",
" shortest_route = route\n",
"\n",
" tau = update_tau(individu, tau, tabulists, L, evaporation_coeff, Q,n_kota)\n",
" \n",
" \n",
" print (\"itinerary\",run+1,\"=\",route)\n",
" print (min_dist,\",\",min_cost,\",\",Weather)\n",
" \n",
" \n",
" global_distance.append(shortest_distance)\n",
" print(\"\\n\")\n"
]
},
{
"cell_type": "code",
"execution_count": 74,
"metadata": {},
"outputs": [],
"source": [
"def decoding_ACO():\n",
" name = 0\n",
" for i in range(len(route)):\n",
" name = route[i]\n",
" print(Dataz.iloc[name][1])\n",
" i+=1\n",
" return "
]
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Bukit Pahoda\n",
"Situmurun Waterfall\n",
"Balerong Onan Balige\n",
"Monumen Raja Sonakmalela\n",
"Pakkodian\n",
"Dolok Tolong\n",
"Makam Raja Sisingamangaraja XII\n",
"Bukit Pahoda\n"
]
}
],
"source": [
"decoding_ACO()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ABC"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Using TensorFlow backend.\n"
]
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import math\n",
"import random\n",
"import time\n",
"import pandas as pd\n",
"import csv\n",
"import sys\n",
"import datetime\n",
"import timeit\n",
"from sklearn.preprocessing import MinMaxScaler\n",
"from keras.models import Sequential\n",
"from keras.layers import Bidirectional, GlobalMaxPool1D\n",
"from keras.layers import LSTM\n",
"from keras.layers import Dropout, Dense"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"#Load dataset sebelum integrasi\n",
"#Datax = pd.read_csv('./Yolanda/tri/Data Toba Samosir_Sheet3.csv')\n",
"#Datax.drop(Datax.filter(regex=\"Unname\"),axis=1, inplace=True)\n",
"Datax = pd.read_csv('./Data Toba Samosir_Sheet1.csv')\n",
"#Datax = pd.read_csv('./Data_Dianalisis.csv')\n",
"Datax.drop(Datax.filter(regex=\"Unname\"),axis=1, inplace=True)\n",
"Dataz = pd.read_csv('./List_city.csv')\n",
"#Dataz = pd.read_csv('./List_city_Data_Dianalisis.csv')\n",
"Dat = Datax.to_numpy()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# User Input"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"jumlah_tempat_wisata = 7\n",
"cost = 400000\n",
"Cost = int(cost)\n",
"#min_cost = 399333"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"start = datetime.datetime.strptime(\"21-07-2020\", \"%d-%m-%Y\")\n",
"end = datetime.datetime.strptime(\"22-07-2020\", \"%d-%m-%Y\")\n",
"date_generated = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]\n",
"#print(len(date_generated))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Fitness Calculation"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"class Fitness_value:\n",
" def getting_max_distance():\n",
" max_distance = 0 \n",
" max_distance += len(date_generated) * 720\n",
" return max_distance\n",
" def getting_max_cost():\n",
" max_cost = 0\n",
" max_cost +=Cost\n",
" return max_cost"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Prediksi Suhu"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"#import dataset from data.csv file\n",
"dataset = pd.read_csv('./SuhuKabTobaSamosir.csv')\n",
"dataset = dataset.dropna(subset=[\"Temperature\"])\n",
"dataset = dataset.reset_index(drop=True)\n",
"training_set = dataset.iloc[:,2:3].values"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"#Feature Scaling \n",
"sc = MinMaxScaler(feature_range=(0,1))\n",
"training_set_scaled = sc.fit_transform(training_set)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"x_train = []\n",
"y_train = []\n",
"n_future = len(date_generated) # next 5 days temperature forecast\n",
"n_past = 30 # Past 30 days \n",
"for i in range(0,len(training_set_scaled)-n_past-n_future+1):\n",
" x_train.append(training_set_scaled[i : i + n_past , 0]) \n",
" y_train.append(training_set_scaled[i + n_past : i + n_past + n_future , 0 ])\n",
"x_train , y_train = np.array(x_train), np.array(y_train)\n",
"x_train = np.reshape(x_train, (x_train.shape[0] , x_train.shape[1], 1) )"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/20\n",
"91/91 [==============================] - 3s 31ms/step - loss: 0.1178 - acc: 0.0110\n",
"Epoch 2/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0326 - acc: 0.0110\n",
"Epoch 3/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0342 - acc: 0.0110\n",
"Epoch 4/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0241 - acc: 0.0110\n",
"Epoch 5/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0312 - acc: 0.0110\n",
"Epoch 6/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0272 - acc: 0.0110\n",
"Epoch 7/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0270 - acc: 0.0110\n",
"Epoch 8/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0257 - acc: 0.0110\n",
"Epoch 9/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0275 - acc: 0.0110\n",
"Epoch 10/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0260 - acc: 0.0110\n",
"Epoch 11/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0247 - acc: 0.0110\n",
"Epoch 12/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0252 - acc: 0.0110\n",
"Epoch 13/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0269 - acc: 0.0110\n",
"Epoch 14/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0253 - acc: 0.0110\n",
"Epoch 15/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0253 - acc: 0.0110\n",
"Epoch 16/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0233 - acc: 0.0110\n",
"Epoch 17/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0256 - acc: 0.0110\n",
"Epoch 18/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0228 - acc: 0.0110\n",
"Epoch 19/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0220 - acc: 0.0110\n",
"Epoch 20/20\n",
"91/91 [==============================] - 0s 2ms/step - loss: 0.0240 - acc: 0.0110\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.callbacks.History at 0x1f1e79adef0>"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"regressor = Sequential()\n",
"regressor.add(Bidirectional(LSTM(units=30, return_sequences=True, input_shape = (x_train.shape[1],1) ) ))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(LSTM(units= 30 , return_sequences=True))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(LSTM(units= 30 , return_sequences=True))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(LSTM(units= 30))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(Dense(units = n_future,activation='linear'))\n",
"regressor.compile(optimizer='adam', loss='mean_squared_error',metrics=['acc'])\n",
"regressor.fit(x_train, y_train, epochs=20,batch_size=32 )"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# read test dataset\n",
"testdataset = pd.read_csv('./testing.csv')\n",
"#get only the temperature column\n",
"testdataset = testdataset.iloc[:30,1:2].values\n",
"real_temperature = pd.read_csv('./SuhuKabTobaSamosir.csv')\n",
"real_temperature = real_temperature.iloc[:30,2:3].values\n",
"testing = sc.transform(testdataset)\n",
"testing = np.array(testing)\n",
"testing = np.reshape(testing,(testing.shape[1],testing.shape[0],1))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"predicted_temperature = regressor.predict(testing)\n",
"predicted_temperature = sc.inverse_transform(predicted_temperature)\n",
"predicted_temperature = np.reshape(predicted_temperature,(predicted_temperature.shape[1],predicted_temperature.shape[0]))"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"def get_weather ():\n",
" for i in range(len(predicted_temperature)):\n",
" weat= predicted_temperature[0][0]\n",
" return weat"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"27.674839"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Weather = get_weather ()\n",
"Weather"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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bKoVNXjwYN58801EhHvvvZfbbruNP/zhD9x+++3cfffdDBo0iBUrVtCuXTtuvfVWbr/9dp5++unMj70ZXFE4jlNYPvzQzEDx/gnYMkT2kKT9y3KjqclmBW3bZrddmzY2C8mwtHdoeopn0qRJXHnllYD1lujdu/cmRXHCCSdsKjv+/PPP8/zzzzNggPVjW7FiBXPmzKGhoYHzzz+fLkHxwnD9xsZGLrroIubPn8+6devYfffdARg0aBBXX301l156Keeeey49e/bM7pgzxBWF4ziFJZkjGzYrihY6gbe68//oI0u069s3fVhsMj75xMxW8dFZWZCudl779u23WO+GG27ge9/73hbr3HnnnUnLlF955ZVcffXVnHnmmUycOJGbb74ZgOuvv57TTjuN8ePHc9hhh/HCCy/kJHdzuI/CcZzCUl9vd+v777/l8h13hE6d8hv51NQEX31lvolslQSY83vjRhsjB4466ihGjRoFwPvvv8+nn37KPvvss9V6J510Evfffz8rVqwA4PPPP+fLL7/km9/8JmPGjGFxEKobmp7iy4/HYrFN43z44Yf06dOHn/70pwwcOJDZs2dvVdI8H7iicBynsDQ0wH77WcOiRPIdIvvVV5nlTqSifXuTM8ecih/+8Ids2LCBPn36cNFFFzFixAi2TXLcJ554IpdccgmHH344ffr04fzzz2f58uUccMAB/OxnP+Poo4+mX79+XH311QDcfPPNXHDBBRx55JGbzFJgs6kDDzyQfv36sd1223HKKafQt29f2rRpQ79+/fLmzPYy447jFJYePeC44+CBB7b+7JxzLGN7xoyshkxZZnz2bJtVHHBAzi1OmT/fSqL36ZNcuZUxXmbccZzSY+FCmDdva/9ESDijyMcN65o1Fu1UU5O7koDNsxHP1N5EwRSFiPQSkZdFZJaIzBSRq4Ll/UXkTRGpF5EpIpI03EFE6kRkTvCoK5ScjuMUkLC0eCrncG2tZUTn46IcjpGr2Slkm22gY0cbr4IsLi2hkDOKJuAaVd0POAz4kYjsD9wG/FJV+wP/HbzfAhHpDNwEHAocAtwkIp0KKKvjOIWgOUXRgsinLczmYbvTHXawC31L6dIF1q61GUqF0BI3Q8EUharOV9VpwevlwCygB6BAWPN3R2Beks1PAiao6hJV/QqYAJxcKFmdDFizxuLhnfR88IFdYCqF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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"plt.title(\"Forecast vs Actual using RNN\", fontsize=14)\n",
"plt.plot(pd.Series(np.ravel(real_temperature)), \"r\", label=\"Actual\")\n",
"plt.plot(pd.Series(np.ravel(predicted_temperature)), \"k\", label=\"Forecast\")\n",
"plt.legend(loc=\"upper right\")\n",
"plt.xlabel(\"Time\")\n",
"plt.ylabel(\"Temperature\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Particle Swarm Optimization (PSO) Algorithm"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"# Initialization of PSO parameters,and velocity\n",
"#Number of Agents\n",
"PARTICLE_COUNT = 40;\n",
"#Acceleration Constant\n",
"Acceleration_constant = 2; # Maximum velocity change allowed. Range: 0 >= V_MAX < CITY_COUNT\n",
"#Iterasi\n",
"MAX_EPOCHS = 2\n",
"map = [];\n",
"particles = []\n",
"Maximum_distance= Fitness_value.getting_max_distance()\n",
"CITY_COUNT = 7"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"# define particle function\n",
"class Particle:\n",
" def __init__(self):\n",
" self.mData = [0] * CITY_COUNT\n",
" self.mpBest_distance = 0.9\n",
" self.mVelocity = 0.0\n",
" def get_data(self, index): \n",
" return self.mData[index]\n",
" def set_data(self, index, value):\n",
" self.mData[index] = value\n",
" def get_pBest_distance(self):\n",
" return self.mpBest_distance\n",
" def set_pBest_distance(self, value):\n",
" self.mpBest_distance = value\n",
" def get_velocity(self):\n",
" return self.mVelocity\n",
" def set_velocity(self, velocityScore):\n",
" self.mVelocity = velocityScore "
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"class City:\n",
" def __init__(self):\n",
" self.mX = 0\n",
" self.mY = 0 \n",
"def get_total_distance(index):\n",
" particles[index].set_pBest_distance(0)\n",
" distance_route = []\n",
" distance = 0\n",
" for i in range(CITY_COUNT):\n",
" if i == CITY_COUNT - 1:\n",
" source = particles[index].get_data(CITY_COUNT -1)\n",
" target = particles[index].get_data(0)\n",
" distance_route.append(Datax.iloc[source][target])\n",
" distance = sum(distance_route)\n",
" particles[index].set_pBest_distance(distance) # Complete trip.\n",
" else:\n",
" source = particles[index].get_data(i)\n",
" target = particles[index].get_data(i + 1)\n",
" distance_route.append(Datax.iloc[source][target])\n",
" distance = sum(distance_route)\n",
" particles[index].set_pBest_distance(distance)\n",
" \n",
" return "
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"# mapping city \n",
"def initialize_map():\n",
" for i in range(CITY_COUNT):\n",
" newCity = City()\n",
" map.append(newCity)\n",
" return "
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
"def randomly_arrange(index = 0):\n",
" cityA = random.randrange(0, CITY_COUNT)\n",
" cityB = 0\n",
" done = False\n",
" while not done:\n",
" cityB = random.randrange(0, CITY_COUNT)\n",
" if cityB != cityA:\n",
" done = \tTrue\n",
" # swap cityA and cityB.\n",
" temp = particles[index].get_data(cityA)\n",
" particles[index].set_data(cityA, particles[index].get_data(cityB))\n",
" particles[index].set_data(cityB, temp)\n",
" return "
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"def initialize_particles():\n",
" for i in range(PARTICLE_COUNT):\n",
" newParticle = Particle() \n",
" for j in range(CITY_COUNT):\n",
" newParticle.set_data(j, j) \n",
" particles.append(newParticle) \n",
" for j in range(10): # just any number of times to randomize them.\n",
" randomly_arrange(len(particles) - 1) \n",
" get_total_distance(len(particles) - 1)\n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
"def quicksort(array, left, right):\n",
" pivot = quicksort_partition(array, left, right) \n",
" if left < pivot:\n",
" quicksort(array, left, pivot - 1) \n",
" if right > pivot:\n",
" quicksort(array, pivot + 1, right) \n",
" return array"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"def quicksort_partition(numbers, left, right):\n",
" # The comparison is on each particle's pBest value.\n",
" I_hold = left\n",
" r_hold = right\n",
" pivot = numbers[left] \n",
" while left < right:\n",
" while (numbers[right].get_pBest_distance() >= pivot.get_pBest_distance()) and (left < right):\n",
" right -= 1\n",
"\n",
" if left != right:\n",
" numbers[left] = numbers[right]\n",
" left += 1\n",
" \n",
" while (numbers[left].get_pBest_distance() <= pivot.get_pBest_distance()) and (left < right):\n",
" left += 1 \n",
" if left != right:\n",
" numbers[right] = numbers[left]\n",
" right -= 1 \n",
" numbers[left] = pivot\n",
" pivot = left\n",
" left = I_hold\n",
" right = r_hold\n",
" \n",
" return pivot\n"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"def get_velocity():\n",
" worstResults_distance = 0.0\n",
" vValue_distance = 0.0 \n",
" # After sorting, worst will be last in list.\n",
" worstResults_distance = particles[PARTICLE_COUNT - 1].get_pBest_distance() \n",
" for i in range(PARTICLE_COUNT):\n",
" vValue_distance = (Acceleration_constant * particles[i].get_pBest_distance()) / worstResults_distance \n",
" if (vValue_distance > Acceleration_constant): \n",
" particles[i].set_velocity(Acceleration_constant)\n",
" elif (vValue_distance < 0.0):\n",
" particles[i].set_velocity(0.0)\n",
" else:\n",
" particles[i].set_velocity(vValue_distance) \n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"def copy_from_particle(source, destination):\n",
" # push destination's data points closer to source's data points.\n",
" targetA = random.randrange(0, CITY_COUNT) # source's city to target.\n",
" targetB = 0\n",
" indexA = 0\n",
" indexB = 0\n",
" tempIndex = 0\n",
" \n",
" # targetB will be source's neighbor immediately succeeding targetA (circular).\n",
" for i in range(CITY_COUNT):\n",
" if particles[source].get_data(i) == targetA:\n",
" if i == CITY_COUNT - 1:\n",
" targetB = particles[source].get_data(0) # if end of array, take from beginning.\n",
" else:\n",
" targetB = particles[source].get_data(i + 1)\n",
" \n",
" break\n",
" \n",
" # Move targetB next to targetA by switching values.\n",
" for j in range(CITY_COUNT):\n",
" if particles[destination].get_data(j) == targetA:\n",
" indexA = j\n",
" \n",
" if particles[destination].get_data(j) == targetB:\n",
" indexB = j \n",
" # get temp index succeeding indexA.\n",
" if indexA == CITY_COUNT - 1:\n",
" tempIndex = 0\n",
" else:\n",
" tempIndex = indexA + 1\n",
" \n",
" # Switch indexB value with tempIndex value.\n",
" temp = particles[destination].get_data(tempIndex)\n",
" particles[destination].set_data(tempIndex, particles[destination].get_data(indexB))\n",
" particles[destination].set_data(indexB, temp) \n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
" # updating particles city\n",
"def update_particles():\n",
" # Best was previously sorted to index 0, so start from the second best.\n",
" for i in range(5):\n",
" if i > 0:\n",
" # The higher the velocity score, the more changes it will need.\n",
" changes = math.floor(math.fabs(particles[i].get_velocity()))\n",
" sys.stdout.write(\"Changes for particle \" + str(i) + \": \" + str(changes) + \"\\n\")\n",
" for j in range(changes):\n",
" # 50/50 chance.\n",
" if random.random() > 0.5:\n",
" randomly_arrange(i)\n",
" \n",
" # Push it closer to it's best neighbor.\n",
" copy_from_particle(i - 1, i) \n",
" # Update pBest value.\n",
" get_total_distance(i) \n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"def PSO_algorithm():\n",
" epoch = 0\n",
" done = False \n",
" initialize_particles() \n",
" while not done:\n",
" # Two conditions can end this loop:\n",
" # if the maximum number of epochs allowed has been reached, or,\n",
" # if the Target value has been found.\n",
" if epoch < MAX_EPOCHS:\n",
" for i in range(5): \n",
" sys.stdout.write(\"Route: \") \n",
" for j in range(CITY_COUNT):\n",
" sys.stdout.write(str(particles[i].get_data(j)) + \", \")\n",
" get_total_distance(i) \n",
" sys.stdout.write(\"Distance: \" + str(particles[i].get_pBest_distance()) + \"\\n\") \n",
" if (particles[i].get_pBest_distance() <= Maximum_distance):\n",
" done = True \n",
" quicksort(particles, 0, len(particles) - 1)\n",
" # list has to sorted in order for get_velocity() to work.\n",
" get_velocity() \n",
" update_particles() \n",
" sys.stdout.write(\"epoch number: \" + str(epoch) + \"\\n\") \n",
" epoch += 1 \n",
" else:\n",
" done = True \n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
"def print_best_solution():\n",
" if (particles[0].get_pBest_distance() <= Maximum_distance):\n",
" sys.stdout.write(\"Target reached.\\n\")\n",
" else:\n",
" sys.stdout.write(\"Target not reached.\\n\") \n",
" sys.stdout.write(\"Best Route: \")\n",
" for j in range(CITY_COUNT):\n",
" sys.stdout.write(str(particles[0].get_data(j)) + \", \") \n",
" sys.stdout.write(\"Distance: \" + str(particles[0].get_pBest_distance()) +\"\\n\")\n",
" return"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Route: 4, 0, 5, 3, 1, 6, 2, Distance: 225.4\n",
"Route: 0, 1, 6, 3, 2, 5, 4, Distance: 158.00000000000003\n",
"Route: 5, 1, 4, 6, 3, 0, 2, Distance: 243.10000000000005\n",
"Route: 5, 1, 4, 6, 0, 2, 3, Distance: 331.40000000000003\n",
"Route: 0, 5, 6, 1, 2, 3, 4, Distance: 305.4\n",
"Changes for particle 1: 0\n",
"Changes for particle 2: 0\n",
"Changes for particle 3: 0\n",
"Changes for particle 4: 0\n",
"epoch number: 0\n",
"Target reached.\n",
"Best Route: 4, 5, 2, 0, 6, 1, 3, Distance: 152.20000000000002\n"
]
}
],
"source": [
" if __name__ == '__main__':\n",
" initialize_map()\n",
" PSO_algorithm()\n",
" print_best_solution() "
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[4, 5, 2, 0, 6, 1, 3]"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Decode PSO\n",
"def checking_city():\n",
" if (particles[0].get_pBest_distance() <= Maximum_distance):\n",
" Route = []\n",
" for j in range(CITY_COUNT):\n",
" Route.append(particles[0].get_data(j))\n",
" return Route\n",
"Route= checking_city()\n",
"Route"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
"def decoding(Route):\n",
" id_ = 0\n",
" name = []\n",
" for i in range(len(Route)):\n",
" id_= Route[i]\n",
" print(Dataz.iloc[id_][1])\n",
" i+=1\n",
" return "
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Water Park Tambunan\n",
"Bukit Pahoda\n",
"Pakkodian\n",
"Pantai BUL BUL\n",
"Bukit Senyum\n",
"BUKIT travel Gibeon\n",
"Taman Eden 100 Tobasa\n"
]
}
],
"source": [
"decoding(Route)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Ant Colony Optimization (ACO) Algorithm"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"def generate_start_nodes (individu,n_kota):\n",
" #return : tabulist yang masih berisi start (dan end) node untuk semua individu semut\n",
" start_nodes= []\n",
" for i in range (individu): \n",
" \n",
" start_nodes.append([0 for i in range(n_kota+1)])\n",
" start_nodes[-1][0] = random.randint(0,(n_kota-1))\n",
" start_nodes[-1][-1] = start_nodes[-1][0]\n",
" return start_nodes"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [],
"source": [
"def evaluate_best_city (kota_sekarang, matriks_jarak ,tau, tabulist, alpha, beta):\n",
" #Mengevaluasi kota terbaik yang memungkinkan berdasarkan probabilitas dan tabulist \n",
" \n",
" probability = [0] * np.size(matriks_jarak[1])\n",
" allowed = []\n",
" allowed[:] = [x for x in range(np.size(matriks_jarak[1])) if x not in tabulist]\n",
" p = 0\n",
" for i in allowed:\n",
" visibility = 1/matriks_jarak[kota_sekarang][i]\n",
" p += (tau[kota_sekarang][i]**alpha)*(visibility**beta)\n",
" for i in allowed:\n",
" visibility = 1/matriks_jarak[kota_sekarang][i]\n",
" probability[i] = (tau[kota_sekarang][i]**alpha)*(visibility**beta)/p\n",
" tmp = max(probability)\n",
" return probability.index(tmp)"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [],
"source": [
"def update_tau(individu, tau, tabulists, L, evaporation_coeff, Q,n_kota):\n",
" \"\"\"\n",
" param evaporation: koefisien evaporation\n",
" param tau : matriks tau seukuran kota x kota\n",
" param L : matriks/array[1x16] yang mengandung informasi jarak tour yang\n",
" dihasilkan oleh satu semut\n",
" param delta_tau : matriks seukuran kota x kota\n",
" return : tau yang baru\n",
" \"\"\"\n",
" for i in range (individu):\n",
" for j in range (n_kota):\n",
" delta_tau = Q/L[i]\n",
" tau[tabulists[i][j],tabulists[i][j+1]] = evaporation_coeff * tau[tabulists[i][j],tabulists[i][j+1]] + delta_tau\n",
" return (tau)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [],
"source": [
"def hitung_jarak_1_rute(single_solution,matriks_jarak):\n",
" \"\"\"\n",
" param single_solution: Sebuah tabulist dari seekor semut (1 solusi) [0..16]\n",
" param matriks_jarak : matriks jarak antar node\n",
" return : Total jarak yang dihasilkan solusi tersebut\n",
" \"\"\"\n",
" jarak = 0\n",
" for i in range (len(single_solution)-1):\n",
" jarak += matriks_jarak[single_solution[i]][single_solution[i+1]] \n",
" return (jarak)"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [],
"source": [
"def compute_shortest_distances(tabulists, matriks_jarak):\n",
" \"\"\"\n",
" param tabulists: Tabulist sejumlah individu x banyak kota\n",
" return : tuple (jarak terkecil yang di temukan (float)\n",
" rute dengan jarak terkecil (list),\n",
" list jarak (L)(list)\n",
" rata2 jarak yang ditemukan (float))\n",
" :>>>(min_dist,route,L,rerata)\n",
" \"\"\"\n",
" distances = []\n",
" distances = [0] * len(tabulists)\n",
" for i in range(0,len(tabulists)):\n",
" distances[i] = hitung_jarak_1_rute(tabulists[i],matriks_jarak)\n",
" L = distances\n",
" L = L- 0.97*min(L)\n",
" return (min(distances) , tabulists[distances.index(min(distances))] , L, np.mean(distances))"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [],
"source": [
"def get_cost(Dataz,route):\n",
" Cost = 0 \n",
" id_city = Dataz['ID_City'].to_numpy()\n",
" cost_route = []\n",
" for i in range(len(id_city)): \n",
" for x in range(7):\n",
" if route[x] == id_city[i]:\n",
" cost_route.append(((Dataz.iloc[i][2])))\n",
" Cost = sum(cost_route) \n",
" return(Cost)"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [],
"source": [
"def get_cost(Dataz,route):\n",
" Cost = 0 \n",
" id_city = Dataz['ID_City'].to_numpy()\n",
" cost_route = []\n",
" for i in range(len(id_city)): \n",
" for x in range(7):\n",
" if route[x] == id_city[i]:\n",
" cost_route.append(((Dataz.iloc[i][2])))\n",
" Cost = sum(cost_route) \n",
" return(Cost)"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [],
"source": [
"Maximum_distance = Fitness_value.getting_max_distance()\n",
"Maximum_cost = Fitness_value.getting_max_cost()\n",
"TARGET_weather = Weather\n",
"CITY_COUNT = len(Datax)"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"itinerary 1 = [0, 33, 10, 4, 13, 21, 20, 0]\n",
"255.2 , 32000 , 27.674839\n",
"\n",
"\n",
"itinerary 2 = [4, 23, 31, 35, 14, 5, 22, 4]\n",
"20.88 , 25000 , 27.674839\n",
"\n",
"\n",
"itinerary 3 = [4, 27, 18, 23, 31, 22, 35, 4]\n",
"100.92999999999999 , 15000 , 27.674839\n",
"\n",
"\n",
"itinerary 4 = [0, 23, 31, 35, 14, 16, 34, 0]\n",
"31.08 , 10000 , 27.674839\n",
"\n",
"\n",
"itinerary 5 = [0, 20, 25, 9, 31, 23, 33, 0]\n",
"157.32999999999998 , 12000 , 27.674839\n",
"\n",
"\n"
]
}
],
"source": [
"running = 5\n",
"global_distance = []\n",
"for run in range (running):\n",
" iterasi = 50\n",
" alpha = 2 #jejak pheromon\n",
" beta = 2#visibility\n",
" individu = 40\n",
" n_kota = 7\n",
" evaporation_coeff = 0.1\n",
" Q = 1\n",
"\n",
" matriks_jarak = Dat\n",
" tau = np.ones(np.shape(matriks_jarak))*0.5 #init. intensitas pheromon/jejak pada busur\n",
" delta_tau = np.zeros((n_kota,n_kota))\n",
"\n",
" shortest_distance = math.inf #infinit\n",
"\n",
" shortest_route = []\n",
" average = []\n",
" for i in range (iterasi):\n",
" tabulists = generate_start_nodes(individu,n_kota)\n",
" for j in range (1,n_kota):\n",
" for k in range (individu):\n",
" tabulists[k][j] = evaluate_best_city(tabulists[k][j-1],matriks_jarak,tau, tabulists[k],alpha,beta)\n",
" min_dist,route,L,rerata = compute_shortest_distances(tabulists,matriks_jarak)\n",
" average.append(rerata)\n",
" min_cost = get_cost(Dataz,route) \n",
"\n",
" if ((shortest_distance > min_dist) and (shortest_distance > Maximum_distance) and (min_cost <=Maximum_cost) and ((Weather >=18) and (Weather <=28))):\n",
" shortest_distance = min_dist\n",
" shortest_route = route\n",
"\n",
" tau = update_tau(individu, tau, tabulists, L, evaporation_coeff, Q,n_kota)\n",
" \n",
" \n",
" print (\"itinerary\",run+1,\"=\",route)\n",
" print (min_dist,\",\",min_cost,\",\",Weather)\n",
" \n",
" \n",
" global_distance.append(shortest_distance)\n",
" print(\"\\n\")\n"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [],
"source": [
"def decoding_ACO():\n",
" name = 0\n",
" for i in range(len(route)):\n",
" name = route[i]\n",
" print(Dataz.iloc[name][1])\n",
" i+=1\n",
" return "
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Pantai BUL BUL\n",
"Lumban Silintong\n",
"Pantai Pasir Putih Parparean\n",
"PANTAI AGADON\n",
"Monumen Raja Sonakmalela\n",
"Balerong Onan Balige\n",
"Pantai Pasifik Porsea\n",
"Pantai BUL BUL\n"
]
}
],
"source": [
"decoding_ACO()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Artificial Bee Colony (ABC) Algorithm"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
,Water Park Tambunan,Bukit Senyum,Air Terjun Pandumaan,Air Terjun Sigura Gura,Air Terjun Siboruon,Balerong Onan Balige,Makam Raja Sisingamangaraja XII
Water Park Tambunan,0,57,13.8,48.2,10.4,4.8,7.1
Bukit Senyum,57,0,61.4,68.7,65.1,59.5,61.8
Air Terjun Pandumaan,11.3,61.4,0,52.6,15,11.3,13.6
Air Terjun Sigura Gura,48.2,68.7,52.8,0,56.4,50.8,53
Air Terjun Siboruon,10.4,65.1,15,56.4,0,6,8.3
Balerong Onan Balige,4.8,59.5,11.3,44.6,6,0,2.3
Makam Raja Sisingamangaraja XII,7.1,61.8,13.6,46.8,8.3,2.3,0
ID_City,City,Biaya
4,Water Park Tambunan,10000
6,Bukit Senyum,10000
7,Air Terjun Pandumaan,10000
12,Air Terjun Sigura Gura,10000
18,Air Terjun Siboruon,10000
23,Balerong Onan Balige,10000
35,Makam Raja Sisingamangaraja XII,10000
Lokasi,Dates,Temperature,Chance of Rain,Cuaca,max,min
Kabupaten Toba Samosir,01-Jan-20,27,0,Mostly Cloudy,31,23
Kabupaten Toba Samosir,02-Jan-20,26.5,0.02,Mostly Cloudy,32,21
Kabupaten Toba Samosir,03-Jan-20,27,0.12,Rain,31,23
Kabupaten Toba Samosir,04-Jan-20,27,0,Mostly Cloudy,31,23
Kabupaten Toba Samosir,05-Jan-20,27.5,0.07,Mostly Cloudy,31,24
Kabupaten Toba Samosir,06-Jan-20,27,0,Mostly Cloudy,32,22
Kabupaten Toba Samosir,07-Jan-20,27.5,0,Mostly Cloudy,32,23
Kabupaten Toba Samosir,08-Jan-20,28,0,Mostly Cloudy,33,23
Kabupaten Toba Samosir,09-Jan-20,27.5,0.27,Mostly Cloudy,32,23
Kabupaten Toba Samosir,10-Jan-20,25.5,2.1,Rain,28,23
Kabupaten Toba Samosir,11-Jan-20,26.5,5.79,Mostly Cloudy,30,23
Kabupaten Toba Samosir,12-Jan-20,26.5,0,Mostly Cloudy,30,23
Kabupaten Toba Samosir,13-Jan-20,27,0,Light Rain,31,23
Kabupaten Toba Samosir,14-Jan-20,27.5,0.02,Mostly Cloudy,31,24
Kabupaten Toba Samosir,15-Jan-20,28,0,Mostly Cloudy,31,25
Kabupaten Toba Samosir,16-Jan-20,27.5,0,Mostly Cloudy,30,25
Kabupaten Toba Samosir,17-Jan-20,27,0,Cloudy,30,24
Kabupaten Toba Samosir,18-Jan-20,27.5,0,Thunder,32,23
Kabupaten Toba Samosir,19-Jan-20,27.5,0,Light Rain Shower,32,23
Kabupaten Toba Samosir,20-Jan-20,28,0,Mostly Cloudy,32,24
Kabupaten Toba Samosir,21-Jan-20,27.5,0.76,Mostly Cloudy,32,23
Kabupaten Toba Samosir,22-Jan-20,28.5,0,Mostly Cloudy,32,25
Kabupaten Toba Samosir,23-Jan-20,27,0,Partly Cloudy,32,22
Kabupaten Toba Samosir,24-Jan-20,28,0,Mostly Cloudy,33,23
Kabupaten Toba Samosir,25-Jan-20,28.5,0.02,Mostly Cloudy,32,25
Kabupaten Toba Samosir,26-Jan-20,28,0.07,Light Rain,31,25
Kabupaten Toba Samosir,27-Jan-20,27.5,0.17,Mostly Cloudy,31,24
Kabupaten Toba Samosir,28-Jan-20,27.5,6.5,Light Rain Shower,32,23
Kabupaten Toba Samosir,29-Jan-20,25,3.47,Mostly Cloudy,28,22
Kabupaten Toba Samosir,30-Jan-20,27,0,Mostly Cloudy,31,23
Kabupaten Toba Samosir,31-Jan-20,27,0.38,Mostly Cloudy,31,23
Kabupaten Toba Samosir,01-Feb-20,27.5,0,Mostly Cloudy,32,23
Kabupaten Toba Samosir,02-Feb-20,28.5,0.15,Partly Cloudy,32,25
Kabupaten Toba Samosir,03-Feb-20,28,0.1,Cloudy,31,25
Kabupaten Toba Samosir,04-Feb-20,28,0.02,Mostly Cloudy,33,23
Kabupaten Toba Samosir,05-Feb-20,28,0,Mostly Cloudy,33,23
Kabupaten Toba Samosir,06-Feb-20,26.5,0.02,Mostly Cloudy,30,23
Kabupaten Toba Samosir,07-Feb-20,26.5,0.19,Cloudy,30,23
Kabupaten Toba Samosir,08-Feb-20,31.5,0.2,Light Rain,30,33
Kabupaten Toba Samosir,09-Feb-20,27.5,0,Cloudy,32,23
Kabupaten Toba Samosir,10-Feb-20,28,0.07,Mostly Cloudy,31,25
Kabupaten Toba Samosir,11-Feb-20,27,0.02,Cloudy,31,23
Kabupaten Toba Samosir,12-Feb-20,28.5,0,Cloudy,33,24
Kabupaten Toba Samosir,13-Feb-20,28,1.95,Mostly Cloudy,32,24
Kabupaten Toba Samosir,14-Feb-20,27,0.6,Mostly Cloudy,31,23
Kabupaten Toba Samosir,15-Feb-20,25,1.37,Rain,28,22
Kabupaten Toba Samosir,16-Feb-20,27,0,Mostly Cloudy,32,22
Kabupaten Toba Samosir,17-Feb-20,27.5,0,Mostly Cloudy,32,23
Kabupaten Toba Samosir,18-Feb-20,27,0.07,Mostly Cloudy,31,23
Kabupaten Toba Samosir,19-Feb-20,27.5,0,Mostly Cloudy,32,23
Kabupaten Toba Samosir,20-Feb-20,28.5,0.07,Partly Cloudy,34,23
Kabupaten Toba Samosir,21-Feb-20,28.5,0,Mostly Cloudy,35,22
Kabupaten Toba Samosir,22-Feb-20,29,0,Mostly Cloudy,35,23
Kabupaten Toba Samosir,23-Feb-20,29,0,Clear,35,23
Kabupaten Toba Samosir,24-Feb-20,28,0,Clear,34,22
Kabupaten Toba Samosir,25-Feb-20,28.5,0,Partly Cloudy,34,23
Kabupaten Toba Samosir,26-Feb-20,28.5,0.05,Mostly Cloudy,34,23
Kabupaten Toba Samosir,27-Feb-20,29.5,0,Partly Cloudy,35,24
Kabupaten Toba Samosir,28-Feb-20,29.5,0.02,Partly Cloudy,34,25
Kabupaten Toba Samosir,29-Feb-20,29,0.15,Mostly Cloudy,35,23
Kabupaten Toba Samosir,01-Mar-20,28.5,0.05,Cloudy,33,24
Kabupaten Toba Samosir,02-Mar-20,27.5,1.85,Thunderstorm,32,23
Kabupaten Toba Samosir,03-Mar-20,27.5,0.43,Rain,32,23
Kabupaten Toba Samosir,04-Mar-20,29,0,Mostly Cloudy,33,25
Kabupaten Toba Samosir,05-Mar-20,26.5,0.07,Cloudy,29,24
Kabupaten Toba Samosir,06-Mar-20,28,0,Cloudy,32,24
Kabupaten Toba Samosir,07-Mar-20,27.5,0,Cloudy,33,22
Kabupaten Toba Samosir,08-Mar-20,28,0.17,Light Rain,32,24
Kabupaten Toba Samosir,09-Mar-20,28.5,0,Cloudy,32,25
Kabupaten Toba Samosir,10-Mar-20,29,0,Mostly Cloudy,33,25
Kabupaten Toba Samosir,11-Mar-20,29,0,Mostly Cloudy,33,25
Kabupaten Toba Samosir,12-Mar-20,28.5,0.58,Rain,33,24
Kabupaten Toba Samosir,13-Mar-20,27.5,0.05,Partly Cloudy,32,23
Kabupaten Toba Samosir,14-Mar-20,28.5,0.25,Partly Cloudy,33,24
Kabupaten Toba Samosir,15-Mar-20,29,0.15,Partly Cloudy,34,24
Kabupaten Toba Samosir,16-Mar-20,29,0.43,Mostly Cloudy,33,25
Kabupaten Toba Samosir,17-Mar-20,28.5,0.05,Light Rain,33,24
Kabupaten Toba Samosir,18-Mar-20,27.5,0.2,Light Rain,32,23
Kabupaten Toba Samosir,19-Mar-20,25.5,0.99,Rain,28,23
Kabupaten Toba Samosir,20-Mar-20,27,0,Cloudy,32,22
Kabupaten Toba Samosir,21-Mar-20,27,0,Mostly Cloudy,31,23
Kabupaten Toba Samosir,22-Mar-20,27.5,0.02,Mostly Cloudy,32,23
Kabupaten Toba Samosir,23-Mar-20,27.5,0.05,Cloudy,30,25
Kabupaten Toba Samosir,24-Mar-20,28,0.22,Mostly Cloudy,33,23
Kabupaten Toba Samosir,25-Mar-20,27.5,0.68,Light Rain,32,23
Kabupaten Toba Samosir,26-Mar-20,27,1.39,Mostly Cloudy,31,23
Kabupaten Toba Samosir,27-Mar-20,27.5,1.67,Light Rain With Thunder,32,23
Kabupaten Toba Samosir,28-Mar-20,27.5,0.22,Cloudy,31,24
Kabupaten Toba Samosir,29-Mar-20,27.5,0.27,Mostly Cloudy,32,23
Kabupaten Toba Samosir,30-Mar-20,27,0.07,Mostly Cloudy,31,23
Kabupaten Toba Samosir,31-Mar-20,27.5,0,Cloudy,32,23
Kabupaten Toba Samosir,01-Apr-20,27.5,0.07,Cloudy,32,23
Kabupaten Toba Samosir,02-Apr-20,27.5,0.83,Mostly Cloudy,32,23
Kabupaten Toba Samosir,03-Apr-20,28.5,0.53,Rain,33,24
Kabupaten Toba Samosir,04-Apr-20,29,2.1,Mostly Cloudy,33,25
Kabupaten Toba Samosir,05-Apr-20,27.5,2.31,Cloudy,32,23
Kabupaten Toba Samosir,06-Apr-20,26.5,2.94,Mostly Cloudy,30,23
Kabupaten Toba Samosir,07-Apr-20,27.5,0,Mostly Cloudy,32,23
Kabupaten Toba Samosir,08-Apr-20,27,0.96,Rain,31,23
Kabupaten Toba Samosir,09-Apr-20,27.5,0.38,Mostly Cloudy,32,23
Kabupaten Toba Samosir,10-Apr-20,28.5,0.12,Cloudy,34,23
Kabupaten Toba Samosir,11-Apr-20,28,0,Mostly Cloudy,33,23
Kabupaten Toba Samosir,12-Apr-20,28,0.02,Mostly Cloudy,31,25
Kabupaten Toba Samosir,13-Apr-20,28.5,0.17,Light Rain,33,24
Kabupaten Toba Samosir,14-Apr-20,27,1.04,Mostly Cloudy,31,23
Kabupaten Toba Samosir,15-Apr-20,27.5,0.1,Cloudy,31,24
Kabupaten Toba Samosir,16-Apr-20,26,0.45,Mostly Cloudy,29,23
Kabupaten Toba Samosir,17-Apr-20,26.5,0.83,Mostly Cloudy,30,23
Kabupaten Toba Samosir,18-Apr-20,27.5,0.05,Mostly Cloudy,32,23
Kabupaten Toba Samosir,19-Apr-20,27.5,0.02,Light Rain Shower,31,24
Kabupaten Toba Samosir,20-Apr-20,28,0.25,Mostly Cloudy,32,24
Kabupaten Toba Samosir,21-Apr-20,28.5,2.18,Thunder,33,24
Kabupaten Toba Samosir,22-Apr-20,29,0.02,Mostly Cloudy,33,25
Kabupaten Toba Samosir,23-Apr-20,27,2.1,Mostly Cloudy,31,23
Kabupaten Toba Samosir,24-Apr-20,27.5,0.58,Mostly Cloudy,32,23
Kabupaten Toba Samosir,25-Apr-20,28,0.83,Light Rain Shower,32,24
Kabupaten Toba Samosir,26-Apr-20,27,1.52,Light Rain Shower,30,24
Kabupaten Toba Samosir,27-Apr-20,27.5,0.45,Mostly Cloudy,31,24
Kabupaten Toba Samosir,28-Apr-20,27.5,0.05,Mostly Cloudy,31,24
Kabupaten Toba Samosir,29-Apr-20,27.5,0.07,Mostly Cloudy,31,24
Kabupaten Toba Samosir,30-Apr-20,26.5,0.17,Light Rain,30,23
......@@ -4,7 +4,15 @@
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Using TensorFlow backend.\n"
]
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
......@@ -15,7 +23,12 @@
"import csv\n",
"import sys\n",
"import datetime\n",
"import timeit"
"import timeit\n",
"from sklearn.preprocessing import MinMaxScaler\n",
"from keras.models import Sequential\n",
"from keras.layers import Bidirectional, GlobalMaxPool1D\n",
"from keras.layers import LSTM\n",
"from keras.layers import Dropout, Dense"
]
},
{
......@@ -36,8 +49,27 @@
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# User Input"
]
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 81,
"metadata": {},
"outputs": [],
"source": [
"jumlah_tempat_wisata = 7\n",
"cost = 400000\n",
"Cost = int(cost)\n",
"#min_cost = 399333"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
......@@ -48,15 +80,10 @@
]
},
{
"cell_type": "code",
"execution_count": 4,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"cost = 400000\n",
"Cost = int(cost)\n",
"#min_cost = 399333\n",
"Weather = 26.897694"
"# Fitness Calculation"
]
},
{
......@@ -80,7 +107,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# PSO"
"# Prediksi Suhu"
]
},
{
......@@ -89,6 +116,220 @@
"metadata": {},
"outputs": [],
"source": [
"#import dataset from data.csv file\n",
"dataset = pd.read_csv('./SuhuKabTobaSamosir.csv')\n",
"dataset = dataset.dropna(subset=[\"Temperature\"])\n",
"dataset = dataset.reset_index(drop=True)\n",
"training_set = dataset.iloc[:,2:3].values"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"#Feature Scaling \n",
"sc = MinMaxScaler(feature_range=(0,1))\n",
"training_set_scaled = sc.fit_transform(training_set)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"x_train = []\n",
"y_train = []\n",
"n_future = len(date_generated) # next 5 days temperature forecast\n",
"n_past = 30 # Past 30 days \n",
"for i in range(0,len(training_set_scaled)-n_past-n_future+1):\n",
" x_train.append(training_set_scaled[i : i + n_past , 0]) \n",
" y_train.append(training_set_scaled[i + n_past : i + n_past + n_future , 0 ])\n",
"x_train , y_train = np.array(x_train), np.array(y_train)\n",
"x_train = np.reshape(x_train, (x_train.shape[0] , x_train.shape[1], 1) )"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/20\n",
"91/91 [==============================] - 3s 36ms/step - loss: 0.1736 - acc: 0.0110\n",
"Epoch 2/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0574 - acc: 0.0110\n",
"Epoch 3/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0410 - acc: 0.0000e+00\n",
"Epoch 4/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0481 - acc: 0.0220\n",
"Epoch 5/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0250 - acc: 0.0000e+00\n",
"Epoch 6/20\n",
"91/91 [==============================] - 0s 4ms/step - loss: 0.0372 - acc: 0.0110\n",
"Epoch 7/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0314 - acc: 0.0110\n",
"Epoch 8/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0264 - acc: 0.0110\n",
"Epoch 9/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0244 - acc: 0.0000e+00\n",
"Epoch 10/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0278 - acc: 0.0000e+00\n",
"Epoch 11/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0228 - acc: 0.0110\n",
"Epoch 12/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0263 - acc: 0.0110\n",
"Epoch 13/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0264 - acc: 0.0110\n",
"Epoch 14/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0250 - acc: 0.0110\n",
"Epoch 15/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0230 - acc: 0.0110\n",
"Epoch 16/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0269 - acc: 0.0110\n",
"Epoch 17/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0247 - acc: 0.0110\n",
"Epoch 18/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0263 - acc: 0.0110\n",
"Epoch 19/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0246 - acc: 0.0110\n",
"Epoch 20/20\n",
"91/91 [==============================] - 0s 3ms/step - loss: 0.0250 - acc: 0.0110\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.callbacks.History at 0x1e05e61bef0>"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"regressor = Sequential()\n",
"regressor.add(Bidirectional(LSTM(units=30, return_sequences=True, input_shape = (x_train.shape[1],1) ) ))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(LSTM(units= 30 , return_sequences=True))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(LSTM(units= 30 , return_sequences=True))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(LSTM(units= 30))\n",
"regressor.add(Dropout(0.2))\n",
"regressor.add(Dense(units = n_future,activation='linear'))\n",
"regressor.compile(optimizer='adam', loss='mean_squared_error',metrics=['acc'])\n",
"regressor.fit(x_train, y_train, epochs=20,batch_size=32 )"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# read test dataset\n",
"testdataset = pd.read_csv('./testing.csv')\n",
"#get only the temperature column\n",
"testdataset = testdataset.iloc[:30,1:2].values\n",
"real_temperature = pd.read_csv('./SuhuKabTobaSamosir.csv')\n",
"real_temperature = real_temperature.iloc[:30,2:3].values\n",
"testing = sc.transform(testdataset)\n",
"testing = np.array(testing)\n",
"testing = np.reshape(testing,(testing.shape[1],testing.shape[0],1))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"predicted_temperature = regressor.predict(testing)\n",
"predicted_temperature = sc.inverse_transform(predicted_temperature)\n",
"predicted_temperature = np.reshape(predicted_temperature,(predicted_temperature.shape[1],predicted_temperature.shape[0]))"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"def get_weather ():\n",
" for i in range(len(predicted_temperature)):\n",
" weat= predicted_temperature[0][0]\n",
" return weat"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"27.432116"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Weather = get_weather ()\n",
"Weather"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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bKoVNXjwYN58801EhHvvvZfbbruNP/zhD9x+++3cfffdDBo0iBUrVtCuXTtuvfVWbr/9dp5++unMj70ZXFE4jlNYPvzQzEDx/gnYMkT2kKT9y3KjqclmBW3bZrddmzY2C8mwtHdoeopn0qRJXHnllYD1lujdu/cmRXHCCSdsKjv+/PPP8/zzzzNggPVjW7FiBXPmzKGhoYHzzz+fLkHxwnD9xsZGLrroIubPn8+6devYfffdARg0aBBXX301l156Keeeey49e/bM7pgzxBWF4ziFJZkjGzYrihY6gbe68//oI0u069s3fVhsMj75xMxW8dFZWZCudl779u23WO+GG27ge9/73hbr3HnnnUnLlF955ZVcffXVnHnmmUycOJGbb74ZgOuvv57TTjuN8ePHc9hhh/HCCy/kJHdzuI/CcZzCUl9vd+v777/l8h13hE6d8hv51NQEX31lvolslQSY83vjRhsjB4466ihGjRoFwPvvv8+nn37KPvvss9V6J510Evfffz8rVqwA4PPPP+fLL7/km9/8JmPGjGFxEKobmp7iy4/HYrFN43z44Yf06dOHn/70pwwcOJDZs2dvVdI8H7iicBynsDQ0wH77WcOiRPIdIvvVV5nlTqSifXuTM8ecih/+8Ids2LCBPn36cNFFFzFixAi2TXLcJ554IpdccgmHH344ffr04fzzz2f58uUccMAB/OxnP+Poo4+mX79+XH311QDcfPPNXHDBBRx55JGbzFJgs6kDDzyQfv36sd1223HKKafQt29f2rRpQ79+/fLmzPYy447jFJYePeC44+CBB7b+7JxzLGN7xoyshkxZZnz2bJtVHHBAzi1OmT/fSqL36ZNcuZUxXmbccZzSY+FCmDdva/9ESDijyMcN65o1Fu1UU5O7koDNsxHP1N5EwRSFiPQSkZdFZJaIzBSRq4Ll/UXkTRGpF5EpIpI03EFE6kRkTvCoK5ScjuMUkLC0eCrncG2tZUTn46IcjpGr2Slkm22gY0cbr4IsLi2hkDOKJuAaVd0POAz4kYjsD9wG/FJV+wP/HbzfAhHpDNwEHAocAtwkIp0KKKvjOIWgOUXRgsinLczmYbvTHXawC31L6dIF1q61GUqF0BI3Q8EUharOV9VpwevlwCygB6BAWPN3R2Beks1PAiao6hJV/QqYAJxcKFmdDFizxuLhnfR88IFdYCqF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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"plt.title(\"Forecast vs Actual using RNN\", fontsize=14)\n",
"plt.plot(pd.Series(np.ravel(real_temperature)), \"r\", label=\"Actual\")\n",
"plt.plot(pd.Series(np.ravel(predicted_temperature)), \"k\", label=\"Forecast\")\n",
"plt.legend(loc=\"upper right\")\n",
"plt.xlabel(\"Time\")\n",
"plt.ylabel(\"Temperature\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Particle Swarm Optimization (PSO) Algorithm"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"# Initialization of PSO parameters,and velocity\n",
"#Number of Agents\n",
"PARTICLE_COUNT = 40;\n",
......@@ -104,7 +345,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
......@@ -130,7 +371,7 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
......@@ -161,7 +402,7 @@
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
......@@ -175,7 +416,7 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
......@@ -196,7 +437,7 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
......@@ -214,7 +455,7 @@
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
......@@ -229,7 +470,7 @@
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
......@@ -261,7 +502,7 @@
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
......@@ -283,7 +524,7 @@
},
{
"cell_type": "code",
"execution_count": 15,
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
......@@ -327,7 +568,7 @@
},
{
"cell_type": "code",
"execution_count": 16,
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
......@@ -353,7 +594,7 @@
},
{
"cell_type": "code",
"execution_count": 17,
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
......@@ -387,7 +628,7 @@
},
{
"cell_type": "code",
"execution_count": 18,
"execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
......@@ -405,25 +646,25 @@
},
{
"cell_type": "code",
"execution_count": 19,
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Route: 2, 5, 4, 1, 0, 3, 6, Distance: 248.0\n",
"Route: 6, 3, 4, 2, 5, 0, 1, Distance: 153.1\n",
"Route: 2, 4, 3, 6, 5, 0, 1, Distance: 251.5\n",
"Route: 2, 4, 3, 6, 5, 0, 1, Distance: 251.5\n",
"Route: 6, 1, 2, 0, 3, 4, 5, Distance: 241.39999999999998\n",
"Route: 5, 1, 2, 6, 0, 3, 4, Distance: 336.40000000000003\n",
"Route: 0, 2, 6, 3, 1, 4, 5, Distance: 166.60000000000002\n",
"Route: 2, 5, 6, 3, 0, 1, 4, Distance: 248.10000000000002\n",
"Route: 0, 1, 5, 3, 6, 2, 4, Distance: 256.5\n",
"Route: 2, 0, 5, 6, 1, 3, 4, Distance: 220.49999999999997\n",
"Changes for particle 1: 0\n",
"Changes for particle 2: 0\n",
"Changes for particle 3: 0\n",
"Changes for particle 4: 1\n",
"Changes for particle 4: 0\n",
"epoch number: 0\n",
"Target reached.\n",
"Best Route: 6, 3, 4, 2, 5, 0, 1, Distance: 153.1\n"
"Best Route: 4, 2, 5, 0, 3, 1, 6, Distance: 153.10000000000002\n"
]
}
],
......@@ -436,16 +677,16 @@
},
{
"cell_type": "code",
"execution_count": 20,
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[6, 3, 4, 2, 5, 0, 1]"
"[4, 2, 5, 0, 3, 1, 6]"
]
},
"execution_count": 20,
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
......@@ -464,7 +705,7 @@
},
{
"cell_type": "code",
"execution_count": 21,
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
......@@ -480,20 +721,20 @@
},
{
"cell_type": "code",
"execution_count": 22,
"execution_count": 31,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Bukit Senyum\n",
"Taman Eden 100 Tobasa\n",
"Water Park Tambunan\n",
"Pakkodian\n",
"Bukit Pahoda\n",
"Pantai BUL BUL\n",
"BUKIT travel Gibeon\n"
"Taman Eden 100 Tobasa\n",
"BUKIT travel Gibeon\n",
"Bukit Senyum\n"
]
}
],
......@@ -512,21 +753,17 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# ACO"
"# Ant Colony Optimization (ACO) Algorithm"
]
},
{
"cell_type": "code",
"execution_count": 23,
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"def generate_start_nodes (individu,n_kota):\n",
" \"\"\"\n",
" :param individu:(int) jumlah semut\n",
" :param n_kota :(int) jumlah kota\n",
" :return : tabulist yang masih berisi start (dan end) node untuk semua individu semut\n",
" \"\"\"\n",
" #return : tabulist yang masih berisi start (dan end) node untuk semua individu semut\n",
" start_nodes= []\n",
" for i in range (individu): \n",
" \n",
......@@ -538,19 +775,13 @@
},
{
"cell_type": "code",
"execution_count": 24,
"execution_count": 33,
"metadata": {},
"outputs": [],
"source": [
"def evaluate_best_city (kota_sekarang, matriks_jarak ,tau, tabulist, alpha, beta):\n",
" \"\"\"\n",
" Mengevaluasi kota terbaik yang memungkinkan berdasarkan probabilitas dan tabulist\n",
" :param kota_sekarang: (int 0..15) \n",
" :param tabulist : (int[0..15]) merupakan kota yang sudah pernah dikunjungi oleh semut\n",
" :param tau : (list) intensitas pheromon pada \n",
" :param matriks_jarak: (matriks[16][16]) matriks yang berisi jarak antar kota\n",
" :return : kota dengan probabilitas tertinggi\n",
" \"\"\"\n",
" #Mengevaluasi kota terbaik yang memungkinkan berdasarkan probabilitas dan tabulist \n",
" \n",
" probability = [0] * np.size(matriks_jarak[1])\n",
" allowed = []\n",
" allowed[:] = [x for x in range(np.size(matriks_jarak[1])) if x not in tabulist]\n",
......@@ -567,18 +798,18 @@
},
{
"cell_type": "code",
"execution_count": 25,
"execution_count": 34,
"metadata": {},
"outputs": [],
"source": [
"def update_tau(individu, tau, tabulists, L, evaporation_coeff, Q,n_kota):\n",
" \"\"\"\n",
" :param evaporation: koefisien evaporation\n",
" :param tau : matriks tau seukuran kota x kota\n",
" :param L : matriks/array[1x16] yang mengandung informasi jarak tour yang\n",
" param evaporation: koefisien evaporation\n",
" param tau : matriks tau seukuran kota x kota\n",
" param L : matriks/array[1x16] yang mengandung informasi jarak tour yang\n",
" dihasilkan oleh satu semut\n",
" :param delta_tau : matriks seukuran kota x kota\n",
" :return : tau yang baru\n",
" param delta_tau : matriks seukuran kota x kota\n",
" return : tau yang baru\n",
" \"\"\"\n",
" for i in range (individu):\n",
" for j in range (n_kota):\n",
......@@ -589,15 +820,15 @@
},
{
"cell_type": "code",
"execution_count": 26,
"execution_count": 35,
"metadata": {},
"outputs": [],
"source": [
"def hitung_jarak_1_rute(single_solution,matriks_jarak):\n",
" \"\"\"\n",
" :param single_solution: Sebuah tabulist dari seekor semut (1 solusi) [0..16]\n",
" :param matriks_jarak : matriks jarak antar node\n",
" :return : Total jarak yang dihasilkan solusi tersebut\n",
" param single_solution: Sebuah tabulist dari seekor semut (1 solusi) [0..16]\n",
" param matriks_jarak : matriks jarak antar node\n",
" return : Total jarak yang dihasilkan solusi tersebut\n",
" \"\"\"\n",
" jarak = 0\n",
" for i in range (len(single_solution)-1):\n",
......@@ -607,14 +838,14 @@
},
{
"cell_type": "code",
"execution_count": 27,
"execution_count": 36,
"metadata": {},
"outputs": [],
"source": [
"def compute_shortest_distances(tabulists, matriks_jarak):\n",
" \"\"\"\n",
" :param tabulists: Tabulist sejumlah individu x banyak kota\n",
" :return : tuple (jarak terkecil yang di temukan (float)\n",
" param tabulists: Tabulist sejumlah individu x banyak kota\n",
" return : tuple (jarak terkecil yang di temukan (float)\n",
" rute dengan jarak terkecil (list),\n",
" list jarak (L)(list)\n",
" rata2 jarak yang ditemukan (float))\n",
......@@ -631,7 +862,7 @@
},
{
"cell_type": "code",
"execution_count": 28,
"execution_count": 37,
"metadata": {},
"outputs": [],
"source": [
......@@ -649,7 +880,7 @@
},
{
"cell_type": "code",
"execution_count": 29,
"execution_count": 38,
"metadata": {},
"outputs": [],
"source": [
......@@ -667,7 +898,7 @@
},
{
"cell_type": "code",
"execution_count": 30,
"execution_count": 39,
"metadata": {},
"outputs": [],
"source": [
......@@ -679,31 +910,31 @@
},
{
"cell_type": "code",
"execution_count": 31,
"execution_count": 80,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Route : [0, 14, 31, 23, 30, 27, 4, 0]\n",
"117.53 , 30000 , 26.897694\n",
"itinerary 1 = [0, 4, 31, 23, 22, 20, 24, 0]\n",
"36.230000000000004 , 25000 , 27.432116\n",
"\n",
"\n",
"Route : [0, 18, 31, 23, 35, 20, 21, 0]\n",
"94.23 , 15000 , 26.897694\n",
"itinerary 2 = [5, 22, 4, 14, 35, 20, 31, 5]\n",
"26.85 , 35000 , 27.432116\n",
"\n",
"\n",
"Route : [0, 23, 31, 33, 16, 27, 5, 0]\n",
"134.83 , 2000 , 26.897694\n",
"itinerary 3 = [2, 4, 23, 31, 25, 9, 32, 2]\n",
"135.03 , 15000 , 27.432116\n",
"\n",
"\n",
"Route : [5, 12, 23, 31, 16, 34, 24, 5]\n",
"132.22999999999996 , 10000 , 26.897694\n",
"itinerary 4 = [0, 31, 23, 34, 16, 24, 27, 0]\n",
"94.93 , 0 , 27.432116\n",
"\n",
"\n",
"Route : [0, 16, 2, 31, 23, 34, 24, 0]\n",
"50.43000000000001 , 0 , 26.897694\n",
"itinerary 5 = [0, 22, 2, 31, 23, 20, 7, 0]\n",
"57.129999999999995 , 10000 , 27.432116\n",
"\n",
"\n"
]
......@@ -720,7 +951,6 @@
" n_kota = 7\n",
" evaporation_coeff = 0.1\n",
" Q = 1\n",
" nodelist = []\n",
"\n",
" matriks_jarak = Dat\n",
" tau = np.ones(np.shape(matriks_jarak))*0.5 #init. intensitas pheromon/jejak pada busur\n",
......@@ -745,21 +975,18 @@
"\n",
" tau = update_tau(individu, tau, tabulists, L, evaporation_coeff, Q,n_kota)\n",
" \n",
" print (\"Route : \",route)\n",
" \n",
" print (\"itinerary\",run+1,\"=\",route)\n",
" print (min_dist,\",\",min_cost,\",\",Weather)\n",
" \n",
" \n",
" global_distance.append(shortest_distance)\n",
" print(\"\\n\")\n",
"\n",
"#for shortest in global_distance:\n",
"# print (shortest) \n",
"\n",
"\n",
"#print (\"Rata-rata rute terpendek yang dihasilkan: \",np.average(global_distance))\n"
" print(\"\\n\")\n"
]
},
{
"cell_type": "code",
"execution_count": 32,
"execution_count": 74,
"metadata": {},
"outputs": [],
"source": [
......@@ -774,21 +1001,21 @@
},
{
"cell_type": "code",
"execution_count": 33,
"execution_count": 75,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Pantai BUL BUL\n",
"Pantai Meat\n",
"Pakkodian\n",
"Monumen Raja Sonakmalela\n",
"Bukit Pahoda\n",
"Situmurun Waterfall\n",
"Balerong Onan Balige\n",
"Desa Adat Ragi Hotang\n",
"Monumen Raja Sonakmalela\n",
"Pakkodian\n",
"Dolok Tolong\n",
"Pantai BUL BUL\n"
"Makam Raja Sisingamangaraja XII\n",
"Bukit Pahoda\n"
]
}
],
......@@ -797,130 +1024,10 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ABC"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [],
"source": [
"path = list(Dataz[\"ID_City\"])\n",
"Maximum_distance = Fitness_value.getting_max_distance()\n",
"Maximum_cost = Fitness_value.getting_max_cost()\n",
"def get_total_cost(path):\n",
" cost_route = []\n",
" cost = 0\n",
" for i in range(len(path)):\n",
" cost_route.append(Dataz.iloc[i][2])\n",
" cost = sum(cost_route)\n",
" return cost "
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [],
"source": [
"#Datax"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [],
"source": [
"path = [5, 12, 23, 31, 16, 34, 24, 5]"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [],
"source": [
"def calculate_distance():\n",
" distance_route = []\n",
" last_distance = 0\n",
" distance = 0\n",
" for i in range(0,4):\n",
" source = path[i]\n",
" target = path[i+1]\n",
" distance_route.append(Datax.iloc[source][target])\n",
" for i in range(0,4):\n",
" source = path[len(path)-1]\n",
" target = path[len(path)-len(path)]\n",
" last_distance = Datax.iloc[source][target] \n",
" distance = sum(distance_route)+last_distance\n",
" return distance"
]
},
{
"cell_type": "code",
"execution_count": 70,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"116.62999999999998"
]
},
"execution_count": 70,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"calculate_distance()"
]
},
{
"cell_type": "code",
"execution_count": 65,
"metadata": {},
"outputs": [],
"source": [
"def get_last_distance():\n",
" last_distance = 0\n",
" for i in range(0,4):\n",
" source = path[len(path)-1]\n",
" target = path[len(path)-len(path)]\n",
" last_distance = Datax.iloc[source][target]\n",
" return last_distance "
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.0"
]
},
"execution_count": 66,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"get_last_distance()"
"# Artificial Bee Colony (ABC) Algorithm"
]
},
{
......
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Using TensorFlow backend.\n"
]
}
],
"source": [
"import csv\n",
"import math\n",
"import random\n",
"import sys\n",
"from scipy.spatial import distance\n",
"import pandas as pd\n",
"from numpy import * \n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import math\n",
"import csv\n",
"import random\n",
"import time\n",
"import sys\n",
"import datetime\n",
"import timeit\n",
"from sklearn.neighbors import DistanceMetric\n",
"from math import radians,cos,sin\n",
"from haversine import haversine, Unit\n",
"from scipy.spatial import distance\n",
"from sklearn.preprocessing import MinMaxScaler\n",
"from keras.models import Sequential\n",
"from keras.layers import Bidirectional, GlobalMaxPool1D\n",
"from keras.layers import LSTM\n",
"from keras.layers import Dropout, Dense\n",
"from math import sqrt\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"#Load dataset sebelum integrasi\n",
"Data1 = pd.read_csv('./tri/Data Toba Samosir - Sheet3.csv')\n",
"Data1.drop(Data1.filter(regex=\"Unname\"),axis=1, inplace=True)\n",
"Data2 = pd.read_csv('./tri/Data Toba Samosir - Sheet1.csv')\n",
"Data2.drop(Data2.filter(regex=\"Unname\"),axis=1, inplace=True)\n",
"Data3 = pd.read_csv('./tri/List_city.csv')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>ID_City</th>\n",
" <th>City</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>Pantai BUL BUL</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>1</td>\n",
" <td>BUKIT travel Gibeon</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2</td>\n",
" <td>Pakkodian</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>3</td>\n",
" <td>Taman Eden 100 Tobasa</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>4</td>\n",
" <td>Water Park Tambunan</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" ID_City City\n",
"0 0 Pantai BUL BUL\n",
"1 1 BUKIT travel Gibeon\n",
"2 2 Pakkodian\n",
"3 3 Taman Eden 100 Tobasa\n",
"4 4 Water Park Tambunan"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Data3.head()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"start = datetime.datetime.strptime(\"21-07-2020\", \"%d-%m-%Y\")\n",
"end = datetime.datetime.strptime(\"22-07-2020\", \"%d-%m-%Y\")\n",
"date_generated = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]\n",
"#print(len(date_generated))"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"#cost = input()\n",
"cost = 400000\n",
"Cost = int(cost)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Random Data"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"209.0"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def getting_distance(Data):\n",
" distance_route = []\n",
" last_distance = 0\n",
" distance = 0\n",
" for i in range(0,len(Data)-1):\n",
" source = Data[i]\n",
" target = Data[i+1]\n",
" distance_route.append(Data2.iloc[source][target])\n",
" for i in range(0,len(Data)-1):\n",
" source = Data[len(Data)-1]\n",
" target = Data[len(Data)-len(Data)]\n",
" last_distance = Data2.iloc[source][target] \n",
" distance = sum(distance_route)+last_distance\n",
" return distance\n",
"\n",
"\n",
"id_city = list(Data3['ID_City'])\n",
"Data4 = random.sample(range(len(id_city)), 7)\n",
"getting_distance(Data4)"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[30, 0, 16, 32, 20, 29, 1]"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Data4"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
"class Fitness_value:\n",
" def getting_max_distance():\n",
" max_distance = 0 \n",
" max_distance += len(date_generated) * 720\n",
" return max_distance\n",
" def getting_max_cost():\n",
" max_cost = 0\n",
" max_cost +=Cost\n",
" return max_cost"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"720"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Fitness_value.getting_max_distance()"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"class Bee:\n",
" def __init__(self, node_set):\n",
" self.role = ''\n",
" self.path = list(node_set) # stores all nodes in each bee, will randomize foragers\n",
" self.distance = 0\n",
" self.temperature = 0\n",
" self.cycle = 0 \n",
" self.cost = 0"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [],
"source": [
"def initialize_hive(population, data):\n",
" path = Data4\n",
" hive = [Bee(path) for i in range (0, population)]\n",
" return hive"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [],
"source": [
"def assign_roles(hive, role_percentiles):\n",
" forager_percent = 0.5\n",
" onlooker_percent = 0.5\n",
" role_percent = [onlooker_percent, forager_percent]\n",
" scout_percent = 0.2\n",
" population = len(hive)\n",
" onlooker_count = math.floor(population * role_percentiles[0])\n",
" forager_count = math.floor(population * role_percentiles[1])\n",
" for i in range(0, onlooker_count):\n",
" hive[i].role = 'O'\n",
" for i in range(onlooker_count, (onlooker_count + forager_count)):\n",
" hive[i].role = 'F'\n",
" random.shuffle(hive[i].path)\n",
" hive[i].distance = getting_distance(hive[i].path)\n",
" return hive"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [],
"source": [
"def mutate_path(path):\n",
" # - will go out of range if last element is chosen.\n",
" path = Data4\n",
" new_path = random.sample(path,len(path))\n",
" return new_path"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [],
"source": [
"def forage(bee,limit):\n",
" new_path = mutate_path(bee.path)\n",
" new_distance = getting_distance(new_path)\n",
" if new_distance < bee.distance:\n",
" bee.path = new_path\n",
" bee.distance = new_distance\n",
" bee.cycle = 0 # reset cycle so bee can continue to make progress\n",
" else:\n",
" bee.cycle += 1\n",
" if bee.cycle >= limit: # if bee is not making progress\n",
" bee.role = 'S'\n",
" return bee.distance, list(bee.path)"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [],
"source": [
"def scout(bee):\n",
" new_path = list(bee.path)\n",
" random.shuffle(new_path)\n",
" bee.path = new_path\n",
" bee.distance = getting_distance(bee.path)\n",
" # bee.temperature = Weather\n",
" bee.role = 'F'\n",
" bee.cycle = 0"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [],
"source": [
"def waggle(hive, best_distance,forager_limit, scout_count):\n",
" best_path = []\n",
" results = []\n",
" for i in range(0, len(hive)):\n",
" if hive[i].role == 'F':\n",
" distance, path = forage(hive[i], forager_limit)\n",
" if distance < best_distance:\n",
" best_distance = distance\n",
" best_path = list(hive[i].path)\n",
" results.append((i, distance))\n",
"\n",
" elif hive[i].role == 'S':\n",
" scout(hive[i])\n",
" # after processing all bees, set worst performers to scout\n",
" results.sort(reverse = True, key=lambda tup: tup[1])\n",
" scouts = [ tup[0] for tup in results[0:int(scout_count)] ]\n",
" for new_scout in scouts:\n",
" hive[new_scout].role = 'S'\n",
" return best_distance, best_path"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [],
"source": [
"def recruit(hive, best_distance, best_path):\n",
" for i in range(0, len(hive)):\n",
" if hive[i].role == 'O':\n",
" new_path = mutate_path(best_path)\n",
" new_distance = getting_distance(new_path)\n",
" if new_distance < best_distance:\n",
" best_distance = new_distance\n",
" best_path = new_path\n",
" return best_distance, best_path"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [],
"source": [
"def print_details(cycle, path, distance,bee):\n",
" \"\"\"\n",
" Prints cycle details to console.\n",
" \"\"\"\n",
" print(\"CYCLE: {}\".format(cycle))\n",
" print(\"PATH: {}\".format(path))\n",
" print(\"DISTANCE: {}\".format(distance))\n",
" # print(\"COST: {}\".format(cost))\n",
" # print(\"TEMPERATURE: {}\".format(temperature))\n",
" print(\"BEE: {}\".format(bee))\n",
" print(\"\\n\")"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [],
"source": [
"Maximum_distance = Fitness_value.getting_max_distance()"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [],
"source": [
"def main():\n",
" # Control parameters\n",
" population = 40\n",
" forager_percent = 0.5\n",
" onlooker_percent = 0.4\n",
" role_percent = [onlooker_percent, forager_percent]\n",
" scout_percent = 0.01\n",
" scout_count = math.ceil(population * scout_percent)\n",
" forager_limit = 500\n",
" cycle_limit = 100\n",
" cycle = 1\n",
" # temperature = Weather\n",
" # Data source\n",
" # data = read_data_from_csv(\"data/data_10.csv\")\n",
" # data = read_data_from_csv(\"data/data_11.csv\")\n",
" data = Data4\n",
" # Global vars\n",
" best_distance = sys.maxsize\n",
" best_path = []\n",
" result = ()\n",
" # Initialization\n",
" hive = initialize_hive(population, data)\n",
" assign_roles(hive, role_percent)\n",
"# cost = get_total_cost(path)\n",
" while cycle < cycle_limit:\n",
" waggle_distance,waggle_path = waggle(hive, best_distance,forager_limit,scout_count)\n",
" if (waggle_distance < best_distance) and (waggle_distance <= Maximum_distance):\n",
" best_distance = waggle_distance\n",
" best_path = list(waggle_path)\n",
" # cost = get_total_cost(path)\n",
" # temperature = Weather\n",
" print_details(cycle, best_path, best_distance,'F')\n",
" result = (cycle, best_path, best_distance,'F')\n",
" recruit_distance,recruit_path = recruit(hive, best_distance,best_path)\n",
" if (recruit_distance < best_distance) and (recruit_distance <= Maximum_distance):\n",
" best_path = list(recruit_path)\n",
" best_distance = recruit_distance \n",
"# cost = get_total_cost(path)\n",
" print_details(cycle, best_path, best_distance,'R')\n",
" result = (cycle, best_path, best_distance,'R')\n",
" if cycle % 100 == 0:\n",
" print(\"CYCLE #: {}\\n\".format(cycle))\n",
" cycle += 1"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CYCLE: 1\n",
"PATH: [20, 1, 32, 30, 29, 0, 16]\n",
"DISTANCE: 191.70000000000002\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [30, 16, 20, 0, 29, 1, 32]\n",
"DISTANCE: 185.30000000000004\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 2\n",
"PATH: [16, 20, 0, 1, 29, 32, 30]\n",
"DISTANCE: 185.20000000000002\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 2\n",
"PATH: [30, 1, 29, 0, 20, 16, 32]\n",
"DISTANCE: 185.10000000000002\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 3\n",
"PATH: [30, 32, 1, 29, 20, 16, 0]\n",
"DISTANCE: 185.0\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 15\n",
"PATH: [32, 30, 29, 1, 16, 20, 0]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [29, 20, 16, 0, 30, 32, 1]\n",
"DISTANCE: 185.0\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 3\n",
"PATH: [30, 1, 29, 16, 20, 0, 32]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [1, 29, 20, 16, 0, 32, 30]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [32, 30, 0, 20, 16, 1, 29]\n",
"DISTANCE: 185.3\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [20, 0, 32, 30, 29, 1, 16]\n",
"DISTANCE: 185.0\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 4\n",
"PATH: [30, 29, 1, 16, 20, 0, 32]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [20, 16, 0, 1, 29, 30, 32]\n",
"DISTANCE: 185.4\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [0, 20, 16, 32, 30, 1, 29]\n",
"DISTANCE: 185.1\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 5\n",
"PATH: [20, 0, 32, 30, 29, 1, 16]\n",
"DISTANCE: 185.0\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 6\n",
"PATH: [0, 30, 32, 1, 29, 20, 16]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [1, 0, 20, 16, 30, 32, 29]\n",
"DISTANCE: 185.2\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 2\n",
"PATH: [30, 32, 1, 29, 0, 20, 16]\n",
"DISTANCE: 185.1\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 3\n",
"PATH: [29, 1, 16, 20, 0, 32, 30]\n",
"DISTANCE: 185.0\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 12\n",
"PATH: [32, 30, 29, 1, 16, 20, 0]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [29, 1, 16, 20, 0, 32, 30]\n",
"DISTANCE: 185.0\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 4\n",
"PATH: [0, 30, 32, 1, 29, 20, 16]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [1, 16, 20, 0, 32, 30, 29]\n",
"DISTANCE: 185.0\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 2\n",
"PATH: [0, 30, 32, 1, 29, 20, 16]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [20, 0, 1, 29, 30, 32, 16]\n",
"DISTANCE: 185.4\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 2\n",
"PATH: [32, 30, 1, 29, 0, 20, 16]\n",
"DISTANCE: 185.10000000000002\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 2\n",
"PATH: [29, 1, 0, 16, 20, 32, 30]\n",
"DISTANCE: 185.00000000000003\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 5\n",
"PATH: [0, 32, 30, 29, 1, 16, 20]\n",
"DISTANCE: 185.0\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 21\n",
"PATH: [1, 29, 20, 16, 0, 32, 30]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [20, 16, 0, 32, 30, 29, 1]\n",
"DISTANCE: 185.10000000000002\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 4\n",
"PATH: [1, 29, 0, 16, 20, 30, 32]\n",
"DISTANCE: 185.0\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 21\n",
"PATH: [0, 32, 30, 1, 29, 20, 16]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [0, 30, 32, 1, 29, 20, 16]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [16, 0, 1, 29, 30, 32, 20]\n",
"DISTANCE: 185.4\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 2\n",
"PATH: [32, 1, 29, 0, 20, 16, 30]\n",
"DISTANCE: 185.1\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 3\n",
"PATH: [32, 1, 29, 20, 16, 0, 30]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [30, 32, 1, 29, 20, 16, 0]\n",
"DISTANCE: 185.0\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 6\n",
"PATH: [30, 32, 1, 29, 16, 20, 0]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [32, 1, 29, 0, 20, 16, 30]\n",
"DISTANCE: 185.1\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 4\n",
"PATH: [16, 20, 32, 30, 29, 1, 0]\n",
"DISTANCE: 185.0\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 34\n",
"PATH: [32, 30, 1, 29, 20, 16, 0]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [32, 30, 20, 16, 0, 1, 29]\n",
"DISTANCE: 185.3\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [30, 32, 1, 29, 0, 20, 16]\n",
"DISTANCE: 185.1\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 4\n",
"PATH: [29, 20, 16, 0, 30, 32, 1]\n",
"DISTANCE: 185.0\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 61\n",
"PATH: [30, 29, 1, 16, 20, 0, 32]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [0, 30, 1, 29, 32, 16, 20]\n",
"DISTANCE: 190.4\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 4\n",
"PATH: [32, 29, 1, 0, 16, 20, 30]\n",
"DISTANCE: 185.10000000000002\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 4\n",
"PATH: [30, 32, 1, 29, 20, 16, 0]\n",
"DISTANCE: 185.0\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 72\n",
"PATH: [30, 32, 1, 29, 16, 20, 0]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [20, 30, 32, 1, 29, 0, 16]\n",
"DISTANCE: 185.0\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 11\n",
"PATH: [30, 32, 1, 29, 16, 20, 0]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [1, 29, 0, 20, 16, 32, 30]\n",
"DISTANCE: 185.1\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 3\n",
"PATH: [20, 32, 30, 29, 1, 0, 16]\n",
"DISTANCE: 185.0\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 7\n",
"PATH: [32, 30, 29, 1, 16, 20, 0]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [29, 32, 30, 16, 20, 0, 1]\n",
"DISTANCE: 185.20000000000002\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 2\n",
"PATH: [16, 20, 30, 32, 29, 1, 0]\n",
"DISTANCE: 185.1\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 4\n",
"PATH: [0, 16, 20, 30, 32, 1, 29]\n",
"DISTANCE: 185.0\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 19\n",
"PATH: [1, 29, 20, 16, 0, 32, 30]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [16, 32, 29, 1, 30, 0, 20]\n",
"DISTANCE: 190.5\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 1\n",
"PATH: [29, 1, 30, 32, 0, 20, 16]\n",
"DISTANCE: 185.60000000000002\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 2\n",
"PATH: [30, 0, 16, 20, 1, 29, 32]\n",
"DISTANCE: 185.20000000000002\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 2\n",
"PATH: [32, 30, 29, 1, 20, 16, 0]\n",
"DISTANCE: 185.1\n",
"BEE: R\n",
"\n",
"\n",
"CYCLE: 4\n",
"PATH: [20, 0, 32, 30, 29, 1, 16]\n",
"DISTANCE: 185.0\n",
"BEE: F\n",
"\n",
"\n",
"CYCLE: 6\n",
"PATH: [0, 32, 30, 1, 29, 20, 16]\n",
"DISTANCE: 184.99999999999997\n",
"BEE: F\n",
"\n",
"\n"
]
}
],
"source": [
"if __name__ == '__main__':\n",
" for i in range (0, 20):\n",
" \n",
" main()\n",
"\n",
" # main()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def getting_best_path():\n",
" # Control parameters\n",
" population = 40\n",
" forager_percent = 0.5\n",
" onlooker_percent = 0.4\n",
" role_percent = [onlooker_percent, forager_percent]\n",
" scout_percent = 0.01\n",
" scout_count = math.ceil(population * scout_percent)\n",
" forager_limit = 500\n",
" cycle_limit = 100\n",
" cycle = 1\n",
" best_distance = sys.maxsize\n",
" best_path = []\n",
" result = ()\n",
" data = Data4\n",
" # Initialization\n",
" hive = initialize_hive(population, data)\n",
" assign_roles(hive, role_percent)\n",
" #cost = get_total_cost(path)\n",
" waggle_distance,waggle_path = waggle(hive, best_distance,forager_limit,scout_count)\n",
" if (waggle_distance < best_distance) and (waggle_distance <= Maximum_distance):\n",
" best_distance = waggle_distance\n",
" best_path = list(waggle_path)\n",
" recruit_distance,recruit_path = recruit(hive, best_distance,best_path)\n",
" if (recruit_distance < best_distance) and (recruit_distance <= Maximum_distance):\n",
" best_path = list(recruit_path)\n",
" best_distance = recruit_distance \n",
" return best_path"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"best_path = getting_best_path()\n",
"best_path"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Dates,Temperature,Chance of Rain,Cuaca
01-Jan-20,27,0,Mostly Cloudy
02-Jan-20,26.5,0.02,Mostly Cloudy
03-Jan-20,27,0.12,Rain
04-Jan-20,27,0,Mostly Cloudy
05-Jan-20,27.5,0.07,Mostly Cloudy
06-Jan-20,27,0,Mostly Cloudy
07-Jan-20,27.5,0,Mostly Cloudy
08-Jan-20,28,0,Mostly Cloudy
09-Jan-20,27.5,0.27,Mostly Cloudy
10-Jan-20,25.5,2.1,Rain
11-Jan-20,26.5,5.79,Mostly Cloudy
12-Jan-20,26.5,0,Mostly Cloudy
13-Jan-20,27,0,Light Rain
14-Jan-20,27.5,0.02,Mostly Cloudy
15-Jan-20,28,0,Mostly Cloudy
16-Jan-20,27.5,0,Mostly Cloudy
17-Jan-20,27,0,Cloudy
18-Jan-20,27.5,0,Thunder
19-Jan-20,27.5,0,Light Rain Shower
20-Jan-20,28,0,Mostly Cloudy
21-Jan-20,27.5,0.76,Mostly Cloudy
22-Jan-20,28.5,0,Mostly Cloudy
23-Jan-20,27,0,Partly Cloudy
24-Jan-20,28,0,Mostly Cloudy
25-Jan-20,28.5,0.02,Mostly Cloudy
26-Jan-20,28,0.07,Light Rain
27-Jan-20,27.5,0.17,Mostly Cloudy
28-Jan-20,27.5,6.5,Light Rain Shower
29-Jan-20,25,3.47,Mostly Cloudy
30-Jan-20,27,0,Mostly Cloudy
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment