This repository was archived by the owner on Apr 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathspike_cluster_kmeans.py
More file actions
117 lines (98 loc) · 3.4 KB
/
Copy pathspike_cluster_kmeans.py
File metadata and controls
117 lines (98 loc) · 3.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import logging
import numpy as np
import random
from pyspark.sql import *
from pyspark import SparkContext, SparkConf
from pyspark.sql import functions as F
from math import sqrt
from spike_cluster_type import SpikeClustering
class SpikeClusterKMeans(SpikeClustering):
def __init__(self, spark):
self.sp = spark
# Helper function to calculate euclidean distance
# Note that this is square as is!!!
@staticmethod
def e_dist (point_a, point_b):
diff = point_a - point_b
ret = diff * diff
return ret
@staticmethod
def eval_cnt (point, center):
min_dist = -1
new_cluster = None
int_k = len (center)
for cnt_idx in range (0, int_k):
ret = SpikeClusterKMeans.e_dist (center[cnt_idx], point)
measure = sum (ret)
if min_dist == -1 or min_dist > measure:
new_cluster = cnt_idx
min_dist = measure
return (new_cluster, ret, point)
@staticmethod
def update_cent (entry, center):
idx = entry[0]
total = entry[1][0]
count = entry[1][1]
center[idx] = total/count
return entry
# Evaluate clustering by computing Within Set Sum of Squared Errors
@staticmethod
def error(point, centers):
min_dist = -1
new_cluster = None
int_k = len (centers)
for cnt_idx in range (0, int_k):
ret = SpikeClusterKMeans.e_dist (centers[cnt_idx], point)
measure = sum (ret)
if min_dist == -1 or min_dist > measure:
new_cluster = cnt_idx
min_dist = measure
return (new_cluster, (ret, 1))
@staticmethod
def far_init(waveforms, k):
# Randomly pick the first centroid
centroids = [random.choice(waveforms)]
# from https://stackoverflow.com/questions/5466323/how-could-one-implement-the-k-means-algorithm
for _ in range(k-1):
dist_sq = np.array([min([np.inner(c-x,c-x) for c in centroids]) for x in waveforms])
probs = dist_sq/dist_sq.sum()
cumulative_probs = probs.cumsum()
r = np.random.rand()
for j, p in enumerate(cumulative_probs):
if r < p:
i = j
break
centroids.append(waveforms[i])
return centroids
# Implement k-means
def Cluster(self, waveforms, k=3, max_iter=20, init='kpp'):
if init == 'kpp':
# for initialization, we randomly select k centroids
centroids = SpikeClusterKMeans.far_init(waveforms=waveforms, k=k)
else:
centroids = [None] * k
for idx in range (k):
centroids[idx] = random.choice(waveforms)
# 3: for iteration := 1 to MAX ITER do
for _ in range (0, max_iter + 1):
clusters = [ [] for _ in range(k) ]
# 4: for each point x in the dataset do
# 5: Cluster of x ← the cluster with the closest centroid to x
# 6: end for
for idx in range (len(waveforms)):
res = SpikeClusterKMeans.eval_cnt (waveforms[idx], centroids)
clusters[res[0]].append ((idx, res[1], res[2]))
# 7: for each cluster P do
# 8: Centroid of P ← the mean of all the data points assigned to P
# 9: end for
for idx in range(k):
cluster = clusters[idx]
if len (cluster) > 0:
centroids[idx] = sum(point for _, _, point in cluster) / len (cluster)
# 7: for each cluster P do
# 8: Centroid of P ← the mean of all the data points assigned to P
# 9: end for
for idx in range(k):
clusters[idx] = [i for i, _, _ in clusters[idx]]
# 11: end for
return clusters