I've tried to implement the Kohonen algorithm using Python and I've managed to do this, but my result is so slow. I want to know if anyone knows how I can improve it.
Objective:
- I have to read a file with X and Y position of 3000 points
- I generate N number of neutrons and arrange them uniformly over the whole chart (over the whole points)
- I check the distance between each point and each neutron, and when I find the minimal distance between one point and a neutron, I move that neutron and his neighborhoods with an alpha value to that point.
I need to mention I'm still quite a beginner using Python.
-UPDATE-
Code:
from chart import save_image, draw_centroids, draw_mesh_between_centroids, chart, draw_centroid
import math
from copy import deepcopy
neurons = []
x = []
y = []
N = 15
t = 0
_alfa = 0
neuron = dict(x=0, y=0, row=0, col=0)
def alfa(t):
return 0.7 * math.pow(math.e, -t / N)
def neighborhood(t):
return int(7 * math.pow(math.e, -t / N) + 1)
def divisors(n):
sqrt = int(math.sqrt(n))
for num in range(sqrt, 2, -1):
if n % num == 0:
return num, int(n / num)
return 0
def generate_neurons(x_range, y_range, size):
div = divisors(size)
if div == 0:
sqrt = int(math.sqrt(size))
size = sqrt * (sqrt + 1)
row, col = divisors(size)
else:
row, col = divisors(size)
step_x = x_range / (row + 1)
step_y = y_range / (col + 1)
for m in range(size):
neuron["row"] = row
neuron["col"] = col
neurons.append(deepcopy(neuron))
step_y_tmp = step_y
for i in range(row):
for j in range(col):
if j == 0:
neurons[i * col + j]["x"] = step_x
else:
neurons[i * col + j]["x"] = neurons[i * col + (j - 1)]["x"] + step_x
neurons[i * col + j]["y"] = step_y_tmp
step_y_tmp += step_y
def read_file(name):
lines = [line.rstrip('\n') for line in open('../generate_file/' + name)]
global x
global y
zone = []
for index in range(len(lines)):
x.append(int(lines[index].split()[0]))
y.append(int(lines[index].split()[1]))
zone.append(int(lines[index].split()[2]))
def run():
global t
global _alfa
distances = []
for j in range(len(x)):
for c in neurons:
dist = distance(x[j], y[j], int(c["x"]), int(c["y"]))
distances.append(dist)
minim = min(float(s) for s in distances)
index = distances.index(minim)
_alfa = alfa(t)
move_neurons(x[j], y[j], neurons[index], _alfa)
distances.clear()
t += 1
def draw_result():
chart(x, y)
draw_mesh_between_centroids(neurons)
draw_centroids(neurons, "black")
save_image()
def detect_neighborhood(neuron, neighborhood):
global neurons
neighborhoods = []
col = neurons[0]["col"]
row = neurons[0]["row"]
for i in range(row):
for j in range(col):
if neuron["x"] == neurons[i * col + j]["x"] and neuron["y"] == neurons[i * col + j]["y"]:
check = -neighborhood + 1
check_2 = neighborhood / 2
if i - neighborhood >= check and j - neighborhood >= check:
for _i in range(i - neighborhood, i + 1):
for _j in range(j - neighborhood, j + 1):
if _i >= 0 and _j >= 0:
neighborhoods.append(neurons[_i * col + _j])
if i - neighborhood >= check and j + neighborhood <= col + check_2:
for _i in range(i - neighborhood, i + 1):
for _j in range(j, (j + neighborhood) + 1):
if _i >= 0 and _j < col:
neighborhoods.append(neurons[_i * col + _j])
if i + neighborhood <= row + check_2 and j - neighborhood >= check:
for _i in range(i, (i + neighborhood) + 1):
for _j in range(j - neighborhood, j + 1):
if _i < row and _j >= 0:
neighborhoods.append(neurons[_i * col + _j])
if i + neighborhood <= row + check_2 and j + neighborhood <= col + check_2:
for _i in range(i, (i + neighborhood) + 1):
for _j in range(j, (j + neighborhood) + 1):
if _i < row and _j < col:
neighborhoods.append(neurons[_i * col + _j])
# draw_centroids(uniqe_dic_list(neighborhoods), "yellow")
# draw_centroid(neuron, "red")
return uniqe_dic_list(neighborhoods)
def distance(x1, y1, x2, y2):
return math.sqrt((x1 - x2) ** 2 + ((y1 - y2) ** 2))
def move_neurons(x, y, neuron, alfa):
global neurons
neighborhoods = detect_neighborhood(neuron, neighborhood(t))
for neuron in neurons:
for n in neighborhoods:
if neuron == n:
neuron["x"] = x + alfa * (x - neuron["x"])
neuron["y"] = y + alfa * (y - neuron["y"])
def uniqe_dic_list(seq):
new_d = []
for x in seq:
if x not in new_d:
new_d.append(x)
return new_d
generate_neurons(300, 300, 100)
read_file("input.txt")
run()
print(_alfa)
while _alfa > 0.2:
run()
print(_alfa)
draw_result()
Input file:
120 52 3
200 10 1
133 200 2
...so on...
20 200 1