ClusterAlgorithm

聚類算法:

聚類算法屬于無監督學習,沒有給出分類,通過相似度得到種類。

主要會講四種:Kmeans均值,層次聚類,DBSCAN,譜聚類。

再講算法前先講一下幾種衡量相似度的方法:

1.歐氏距離:

p=2時就說平時計算的幾何距離,當p趨向于正無窮的時候,其實求的就不是x,y的距離了,而是求x y中最長的一個了。因為如果x大于y,在指數增長下x回遠大于y,所以y會被忽略的。這也是比較常用的了。

2.杰卡得相似度:

image

這個一般用于是推薦系統的應用,比如推薦的是A,用戶選的是B,那么就可以用這個來衡量了。

3.余弦相似度:

余弦相似度一般用于對詞向量的相似度判斷,他會省略刻度的變化,正好符合向量的判斷方法。

4.Pearson相似度:

image

pearson相似度和cos相似度其實很像,其實就是平移到原點求余弦

5.相對熵:

image

這個在決策樹會用到判斷熵增變化

一下的算法中我們只會用到歐氏距離,想用其他的改一下distance函數就OK了。

==================================================================================================================

Kmeans均值算法:

算是比較簡單而且實用的方法了。

實現步驟:

1.選定k個類別中心點,u1,u2......un

2.對于每個樣本點,選定離他最近的那個類別作為一個類別。

3.將類別中心更新為所有樣本點的均值

4.重復步驟,只到均值點不再更新為止。

簡單python實現Kmeans均值:

首先是數據的準備:


import numpy as np

import matplotlib.pyplot as plt

import seaborn as sea

import pandas as pd

import random

def read_file(filename):

  df = pd.read_csv(filename)

  df.drop('編號' , axis=1 , inplace=True)

  return df

導包,文件讀取方法。

這是數據:

編號,密度,含糖率

1,0.697,0.46

2,0.774,0.376

3,0.634,0.264

4,0.608,0.318

5,0.556,0.215

6,0.403,0.237

7,0.481,0.149

8,0.437,0.211

9,0.666,0.091

10,0.243,0.267

11,0.245,0.057

12,0.343,0.099

13,0.639,0.161

14,0.657,0.198

15,0.36,0.37

16,0.593,0.042

17,0.719,0.103

18,0.359,0.188

19,0.339,0.241

20,0.282,0.257

21,0.784,0.232

22,0.714,0.346

23,0.483,0.312

24,0.478,0.437

25,0.525,0.369

26,0.751,0.489

27,0.532,0.472

28,0.473,0.376

29,0.725,0.445

30,0.446,0.459

需要的復制到Data.txt文件里面就可以了。

dataFile = read_file('Data.txt')

data = dataFile.values

mean_data = np.mean(data , axis=0)

data -= mean_data

data = list(data)

k = 3

mean_vectors = random.sample(data , k)

'''

計算距離

'''

def dist(p1 , p2):

return np.sqrt(sum(np.square(p1 - p2)))

這是讀取文件,去均值化的操作。mean_vectors = random.sample(data , k)選取k個點作為均值。下面的就是計算歐氏距離的了。

聚類過程:

while True:

  clusters = list(map((lambda x : [x]) , mean_vectors))

  for sample in data:

      distances = list(map((lambda m : dist(sample , m)) , mean_vectors))

      min_indexs = distances.index(min(distances))

      clusters[min_indexs].append(sample)

  new_mean_vectors = []

  for c , v in zip(clusters , mean_vectors):

      new_mean_vector = sum(c)/len(c)

      if all(np.divide((new_mean_vector-v),v) < np.array([0.0001,0.0001]) ):

          new_mean_vectors.append(v)

      else:

          new_mean_vectors.append(new_mean_vector)

  if np.array_equal(mean_vectors,new_mean_vectors):

      break

  else:

      mean_vectors = new_mean_vectors

      print(mean_vectors)

      print(new_mean_vectors)

  pass

先把中心點變成一個有三個list的大list

clusters = list(map((lambda x : [x]) , mean_vectors))

對于每一個點,計算他和三個中心點的距離,然后取最小的作為分類,放進對應的list里面。

  for sample in data:

      distances = list(map((lambda m : dist(sample , m)) , mean_vectors))

      min_indexs = distances.index(min(distances))

      clusters[min_indexs].append(sample)

  new_mean_vectors = []

計算新的中心點,如果差距不大的話就作為新的中心點

  for c , v in zip(clusters , mean_vectors):

      new_mean_vector = sum(c)/len(c)

      if all(np.divide((new_mean_vector-v),v) < np.array([0.0001,0.0001]) ):

          new_mean_vectors.append(v)

      else:

          new_mean_vectors.append(new_mean_vector)

  if np.array_equal(mean_vectors,new_mean_vectors):

      break

  else:

      mean_vectors = new_mean_vectors

      print(mean_vectors)

接下來就是畫圖了。

total_colors = ['r','y','g','b','c','m','k']

shapes = ['p','o','v','^','s']

colors = random.sample(total_colors,k)

index = 0

x = list(map((lambda x : x[0]) , mean_vectors))

y = list(map((lambda x : x[1]) , mean_vectors))

for cluster,color in zip(clusters,colors):

  density = list(map(lambda arr:arr[0],cluster))

  sugar_content = list(map(lambda arr:arr[1],cluster))

  plt.scatter(density,sugar_content,c = color,marker=shapes[index])

  index += 1

plt.scatter(x , y , c = 'blue' , marker='x')

plt.show()
image
image

說實話效果還是不錯的。

這就是一個比較簡單python實現了。

Kmeans的公式化解釋:

image

改進:
1.Kmeans算法如果是遇到均值偏離嚴重的,可能會導致均值不準確,可以選擇中值點。
2.如果是初始的均值點選擇不好,可能達不到全局的收斂,只能達到局部收斂。而Kmeans就是一直改進方法:改進了選擇K初始值的方法,假設已經選取了n個初始聚類中心(0<n<K),則在選取第n+1個聚類中心時:距離當前n個聚類中心越遠的點會有更高的概率被選為第n+1個聚類中心。在選取第一個聚類中心(n=1)時同樣通過隨機的方法??梢哉f這也符合我們的直覺:聚類中心當然是互相離得越遠越好。這個改進雖然直觀簡單,但是卻非常得有效。
Kmeans選擇的時候注意不要選擇最大距離的點做為下一個初始值,因為可以最大的這個點是噪音,所以只是要求遠的點有很多概率會被選擇到。

Kmeans方法總結:

優點:
1.簡單,快速,計算很方便。
2.處理大數據的時候,算法可以保持伸縮性和高效性
3.當簇近似于高斯發布時,效果最好。事實上如果涉及到減去均值然后平方都是有關于高斯發布的。因為這個就是高斯分布推出來的。
缺點:
1.在簇的平均值可被定義的情況下才有用,所以不適用于某種情況。
2.必須給出初始值的K值,對初始很敏感。
3.不適合發現非凸形狀或者是大小差別很大的形狀。
4.對噪聲點和孤立點敏感。

==================================================================================================================

層次聚類方法:

層次聚類分為兩種,一種是凝聚層次聚類,一種是分裂層次聚類。這里主要講凝聚的。

算法很簡單:一開始每一個點都是一個類別,然后計算每一個所有點里面兩個距離最小的,合并一個類,直到合并到K個類別為止,不阻止他會合并到1的。

python實現:

import numpy as np

import sklearn.datasets as datasets

import matplotlib.pyplot as plt

import pandas as pd

import seaborn as sns

import math

from sklearn.decomposition import PCA 

def get_data():

  df = datasets.load_iris()

  data = df.data

  label = df.target

  data_matrix = np.matrix(data)

  label_matrix = np.matrix(label)

  return data , label

def ou_distance(vec1 , vec2):

  distance = 0.0

  for a, b in zip(vec1, vec2):

      distance += math.pow(a - b, 2)

  return math.sqrt(distance)

  pass

導包,得到數據,計算歐氏距離,使用的數據集是sklearn的iris數據集。

class Node(object):

  def __init__(self ,

              vec=None ,

              left = None ,

              right = None ,

              distance = -1 ,

              id = None ,

              count = 1):

      self.vec = vec

      self.left = left

      self.right = right

      self.distance = distance

      self.id = id

      self.count = count

  pass

定義一個節點,這個節點包括了中心向量,做節點,右節點,id號(方便找到對應的點)

class Hierarchical(object):

  def __init__(self , k = 1):

      assert k > 0

      self.k = k

      self.labels = None

      self.nodesList = []

      pass

  def fit(self , x):

      #一開始一個點就是一個類別

      nodes = [Node(vec=v , id=i) for i ,v in enumerate(x)]

      self.nodesList.append(nodes.copy())

      distance = {}

      point_num , features_num = np.shape(x)

      self.labels = [-1] * point_num

      currentClusterid = -1

      while len(nodes) > self.k:

          if len(nodes) == 30:

              self.nodesList.append(nodes.copy())

          elif len(nodes) == 20:

              self.nodesList.append(nodes.copy())

          elif len(nodes) == 15:

              self.nodesList.append(nodes.copy())

          elif len(nodes) == 10:

              self.nodesList.append(nodes.copy())

          elif len(nodes) == 5:

              self.nodesList.append(nodes.copy())

          min_distance = math.inf

          nodes_lenght = len(nodes)

          closet_part = None

          for i in range(nodes_lenght - 1):

              for j in range(i + 1 , nodes_lenght):

                  d_key = (nodes[i].id , nodes[j].id)

                  if d_key not in distance:

                      distance[d_key] = ou_distance(nodes[i].vec , nodes[j].vec)

                  d = distance[d_key]

                  if d < min_distance:

                      min_distance = d

                      closet_part = (i , j)

          part1 , part2 = closet_part

          node1 , node2 = nodes[part1] , nodes[part2]

          new_vec = [(node1.vec[i]*node1.count + node2.vec[i]*node2.count)/

                    (node1.count + node2.count) for i in range(features_num)]

          new_node = Node(vec=new_vec ,

                          left=node1,

                          right=node2,

                        distance=min_distance,

                        id=currentClusterid,

                        count=node1.count + node2.count)

          currentClusterid -= 1

          del nodes[part2], nodes[part1]

          nodes.append(new_node)

      self.nodes = nodes

      self.nodesList.append(self.nodes.copy())

      self.calc_label()

      pass

      nodes = [Node(vec=v , id=i) for i ,v in enumerate(x)]

      self.nodesList.append(nodes.copy())

      distance = {}

      point_num , features_num = np.shape(x)

      self.labels = [-1] * point_num

      currentClusterid = -1

這里開始解釋。首先一開始都是一個類別,每一個類別沒有做節點右節點,那么他們自己就是一個中心了。nodeList是為了畫圖的,不用管,point_num,features_num得到點的數量和特征數量。label一開始都是-1。currentClusterid就是集合的id,因為他不是數據,只是一個中間值。反正畫圖是用不到的。不要也行,這里加了有點難理解,但是我樂意。

      while len(nodes) > self.k:

          if len(nodes) == 30:

              self.nodesList.append(nodes.copy())

          elif len(nodes) == 20:

              self.nodesList.append(nodes.copy())

          elif len(nodes) == 15:

              self.nodesList.append(nodes.copy())

          elif len(nodes) == 10:

              self.nodesList.append(nodes.copy())

          elif len(nodes) == 5:

              self.nodesList.append(nodes.copy())

while()里面這段都是畫圖準備的。不用管。

          min_distance = math.inf

          nodes_lenght = len(nodes)

          closet_part = None

          for i in range(nodes_lenght - 1):

              for j in range(i + 1 , nodes_lenght):

                  d_key = (nodes[i].id , nodes[j].id)

                  if d_key not in distance:

                      distance[d_key] = ou_distance(nodes[i].vec , nodes[j].vec)

                  d = distance[d_key]

                  if d < min_distance:

                      min_distance = d

                      closet_part = (i , j)

這里是計算這個數據里面最小距離的點。整個類別里面距離最小最小的點。先設置min_ditance距離為無限大。代碼很簡單,應該能看懂。

最后得到的closet_part就是距離最小的兩個編號了。

          part1 , part2 = closet_part

          node1 , node2 = nodes[part1] , nodes[part2]

          new_vec = [(node1.vec[i]*node1.count + node2.vec[i]*node2.count)/

                    (node1.count + node2.count) for i in range(features_num)]

          new_node = Node(vec=new_vec ,

                          left=node1,

                          right=node2,

                        distance=min_distance,

                        id=currentClusterid,

                        count=node1.count + node2.count)

          currentClusterid -= 1

          print(currentClusterid)

          del nodes[part2], nodes[part1]

          nodes.append(new_node)

計算出新的節點,vec為兩個點的中心,然后放進數據點中,再刪掉原來的。

      self.nodes = nodes

      self.nodesList.append(self.nodes.copy())

      self.calc_label()

      pass

最后這些是為了返回的,calclabel()是得到分類的函數,后面講到。

  def calc_label(self):

      for i, node in enumerate(self.nodes):

          self.leaf_traversal(node, i)

  def leaf_traversal(self, node: Node, label):

      if node.left == None and node.right == None:

          self.labels[node.id] = label

      if node.left:

          self.leaf_traversal(node.left, label)

      if node.right:

          self.leaf_traversal(node.right, label)

這里是遞歸遍歷出來所有的葉子給label值。

最后還有一個畫圖函數:

然而畫圖前要進行PCA的姜維:

pca = PCA(n_components=2)

pca.fit(data)

PCA(copy=True, n_components=2, whiten=False) 

data = pca.transform(data)

  def leaf_print(node , j):

      if node.left == None or node.right == None:

          plt.scatter(data[node.id][0] , data[node.id][1] , color = colors[j] , marker=markers[j])

      if node.left:

          leaf_print(node.left , j)

      if node.right:

          leaf_print(node.right , j)

def draw(nodes):

  for i , j in zip(nodes , range(len(nodes))):

      leaf_print(i,(j+1)%len(markers))

  plt.title(len(nodes))

  plt.show()

應該很好理解的。

另外還有一些顏色啊,,形狀啊等等的,也給出來:

colors = {

'burlywood':            '#DEB887',

'cadetblue':            '#5F9EA0',

'chartreuse':          '#7FFF00',

'chocolate':            '#D2691E',

'cornflowerblue':      '#6495ED',

'cornsilk':            '#FFF8DC',

'crimson':              '#DC143C',

'cyan':                '#00FFFF',

'darkblue':            '#00008B',

'darkcyan':            '#008B8B',

'darkgoldenrod':        '#B8860B',

'darkgray':            '#A9A9A9',

'darkgreen':            '#006400',

'darkkhaki':            '#BDB76B',

'darkmagenta':          '#8B008B',

'darkolivegreen':      '#556B2F',

'darkorange':          '#FF8C00',

'darkorchid':          '#9932CC',

'darkred':              '#8B0000',

'darksalmon':          '#E9967A',

'darkseagreen':        '#8FBC8F',

'darkslateblue':        '#483D8B',

'darkslategray':        '#2F4F4F',

'darkturquoise':        '#00CED1',

'darkviolet':          '#9400D3',

'deeppink':            '#FF1493',

'deepskyblue':          '#00BFFF',

'dimgray':              '#696969',

'dodgerblue':          '#1E90FF',

'firebrick':            '#B22222',

'floralwhite':          '#FFFAF0',

'forestgreen':          '#228B22',

'fuchsia':              '#FF00FF',

'gainsboro':            '#DCDCDC',

'ghostwhite':          '#F8F8FF',

'gold':                '#FFD700',

'goldenrod':            '#DAA520',

'gray':                '#808080',

'green':                '#008000',

'greenyellow':          '#ADFF2F',

'honeydew':            '#F0FFF0',

'hotpink':              '#FF69B4',

'indianred':            '#CD5C5C',

'indigo':              '#4B0082',

'ivory':                '#FFFFF0',

'khaki':                '#F0E68C',

'lavender':            '#E6E6FA',

'lavenderblush':        '#FFF0F5',

'lawngreen':            '#7CFC00',

'lemonchiffon':        '#FFFACD',

'mediumpurple':        '#9370DB',

'mediumseagreen':      '#3CB371',

'mediumslateblue':      '#7B68EE',

'mediumspringgreen':    '#00FA9A',

'mediumturquoise':      '#48D1CC',

'mediumvioletred':      '#C71585',

'midnightblue':        '#191970',

'mintcream':            '#F5FFFA',

'mistyrose':            '#FFE4E1',

'moccasin':            '#FFE4B5',

'navajowhite':          '#FFDEAD',

'navy':                '#000080',

'oldlace':              '#FDF5E6',

'olive':                '#808000',

'olivedrab':            '#6B8E23',

'orange':              '#FFA500',

'orangered':            '#FF4500',

'orchid':              '#DA70D6',

'palegoldenrod':        '#EEE8AA',

'palegreen':            '#98FB98',

'paleturquoise':        '#AFEEEE',

'palevioletred':        '#DB7093',

'papayawhip':          '#FFEFD5',

'peachpuff':            '#FFDAB9',

'peru':                '#CD853F',

'pink':                '#FFC0CB',

'plum':                '#DDA0DD',

'powderblue':          '#B0E0E6',

'purple':              '#800080',

'red':                  '#FF0000',

'rosybrown':            '#BC8F8F',

'royalblue':            '#4169E1',

'saddlebrown':          '#8B4513',

'salmon':              '#FA8072',

'sandybrown':          '#FAA460',

'seagreen':            '#2E8B57',

'seashell':            '#FFF5EE',

'sienna':              '#A0522D',

'silver':              '#C0C0C0',

'skyblue':              '#87CEEB',

'slateblue':            '#6A5ACD',

'slategray':            '#708090',

'snow':                '#FFFAFA',

'springgreen':          '#00FF7F',

'steelblue':            '#4682B4',

'tan':                  '#D2B48C',

}

colors = list(colors.values())

不要標簽只要值。

markers = ['.' , ',' , 'o' , 'v' , '^', '<' , '>' , '1','2','3','4','s' , 'p' , '*' , 'h' , 'H' , 'd' , '|'  , '+' , 'x']

這個是形狀。

運行:

my = Hierarchical(4)

data , label = get_data()

my.fit(data)

上面的fit數據,喂給它姜維之后或者是不姜維都可以的。

剛剛的self.nodelist就是保存過程的,分別保存了最開始的150個類別的,30,20,15,10,5個類別的過程。

for nodes in my.nodesList:

  draw(nodes)

  pass

效果:

image
image
image
image
image
image

最后分出來的類別:

image

可以看到效果其實很好的,和原分類對比其實差不了多少。隨著整個過程下來可以看到分類效果是越來越明顯了。其實距離的選擇有很多種:

image

==================================================================================================================================

DBSCAN密度聚類算法:

這種算法的指導思想是只要密度大于某個閾值就把他加入到附近的簇中。不必要知道要多少個分類,可以發現任意形狀的簇,包括非凸的,而且都噪音數據不敏感。

密度聚類概念:

image
image

算法流程:
1.如果一個點的領域包括了多于m個點的對象,那么就把他作為一個核心對象。
2.尋找直接密度可達的對象
3.沒有更新時結束
包含過少對象的會被認為是噪聲。

python實現:

還是使用iris數據集:

import numpy as np

import matplotlib.pyplot as plt

import pandas as pd

import seaborn as sns

import sklearn.datasets as datasets

import math

def get_data():

  data = datasets.load_iris().data

  dataset = []

  for d in data:

      d1 = (d[0] , d[1] , d[2] , d[3])

      dataset.append(d1)

  return dataset

得到數據集。

#計算歐氏距離

def dist(vec1 , vec2):

  distance = 0.0

  for a, b in zip(vec1, vec2):

      distance += math.pow(a - b, 2)

  return math.sqrt(distance)

  pass

計算歐氏距離

def DBSCAN(D, e, Minpts):

  #初始化核心對象集合T,聚類個數k,聚類集合C, 未訪問集合P,

  T = set()

  k = 0

  C = []

  P = set(D)

  for d in D:

      if len([ i for i in D if dist(d, i) <= e]) >= Minpts:

          T.add(d)

  #開始聚類

  while len(T):

      P_old = P

      #隨機選擇一個核心對象

      o = list(T)[np.random.randint(0, len(T))]

      Q = []

      #加入集合

      Q.append(o)

      while len(Q):

          q = Q[0]

          Nq = [i for i in D if dist(q, i) <= e]

          if len(Nq) >= Minpts:

              S = P & set(Nq)

              Q += (list(S))

              P = P - S

          Q.remove(q)

      k += 1

      Ck = list(P_old - P)

      T = T - set(Ck)

      C.append(Ck)

  return C , P

聚類算法的實現,解釋一下主要步驟:

  for d in D:

      if len([ i for i in D if dist(d, i) <= e]) >= Minpts:

          T.add(d)

選擇出所有的核心對象。

  while len(T):

      P_old = P

      #隨機選擇一個核心對象

      o = list(T)[np.random.randint(0, len(T))]

      Q = []

      #加入集合 Q集合是待選擇的密度可達核心點

      Q.append(o)

      while len(Q):

          q = Q[0]

          Nq = [i for i in D if dist(q, i) <= e]要計算里面的點是不是核心點,因為里面存的不僅僅是核心點,而是核心點周圍的點

          if len(Nq) >= Minpts:是核心點

              S = P & set(Nq)p是沒有被選擇的點 set(Nq是核心對象周圍的點) 那么S就是類別了。

              Q += (list(S))重復上訴步驟,看看周圍的點哪些是核心對象點,把他周圍的點拉進來,在不斷擴張

              P = P - S選出去了,可以不要了

          Q.remove(q)用了  不要了

      k += 1

      Ck = list(P_old - P)剩下的就是被選取的

      T = T - set(Ck)這些核心點已經被用過了,可以丟棄,要不永遠都不會結束的

      C.append(Ck)分出來的一個類別

上面的注釋已經解釋的很清楚了。。。。。。

C , P= DBSCAN(data, 0.6, 4)

C是分類,P是噪音點,沒有被選擇的

接下來就是畫圖了:

from sklearn.decomposition import PCA

pca = PCA(n_components=2)

pca.fit(data)

data2 = pca.transform(data)

def Draw(C):

  for c , i in zip(C , range(len(C))):

      for s in c:

          s = data.index(s)

          s = data2[s]

          plt.scatter(s[0] , s[1] , color = colors[i])

      pass

  for i in P:

      i = data.index(i)

      i = data2[i]

      plt.scatter(i[0] , i[1] , color = 'black')

      pass

  plt.show()

  pass

使用的colors顏色是剛剛層次聚類的那個。

Draw(C)

效果:

image

效果其實不夠剛剛的好。其實在實現的過程中發現一個很重要的問題,參數選擇不好做什么都是假的。一開始不知道怎么選半徑和個數,每次出來都是1,最后是上網看了別人用的這個數據才知道選0.6和5的。試一個晚上了,還以為是代碼錯誤。

image

==================================================================================================================================

譜聚類

譜聚類是一種基于拉普拉斯矩陣的特征向量的聚類算法。

image
image
image
image

計算過程:

image

注意在選取特征的時候,要選擇前k小的特征,而不是最大的。

原因:

image

python實現:

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

from sklearn.cluster import KMeans

from sklearn.decomposition import PCA

import sklearn.datasets as dataset

import seaborn as sns

import math

def pca(data):

  pca = PCA(n_components=2)

  pca.fit(data)

  return pca.transform(data)

def get_data():

  data = dataset.load_iris().data

  data = pca(data)

  return data

data = get_data()

def dist(vec1 , vec2):

  distance = 0.0

  for a, b in zip(vec1, vec2):

      distance += math.pow(a - b, 2)

  return math.sqrt(distance)

降維,得到數據,歐氏距離。

def getWbyKNN(data , K):

  point_num = len(data)

  dis_num = np.zeros((point_num , point_num))

  W = np.zeros((point_num , point_num))

  for i in range(point_num):

      for j in range(i+1 , point_num):

          dis_num[i][j] = dis_num[j][i] = dist(data[i] , data[j])

  for idx , each in enumerate(dis_num):

      index_distance = np.argsort(each)

      W[idx][index_distance[1 : K+1]] = 1

  tmp_W = np.transpose(W)

  W = (tmp_W + W)/2

  return W

  pass

得到W相似矩陣。首先計算出一個距離矩陣,包含了所以的距離。然后排序,第一個小的點肯定是自己,所以1開始,前k小的設為1,其他的設為0。這時候得到的這個矩陣并一定是對稱的,所以加上轉置除2來對稱化。

#得到度矩陣

def getD(W):

  point_num = len(W)

  D = np.diag(np.zeros(point_num))

  for i in range(point_num):

      D[i][i] = sum(W[i])

  return D

  pass

通過W相似矩陣得到D。

#得到游走拉普拉斯矩陣 I - D-1W

def getLPLSmatrix(W , D):

  D = np.linalg.inv(D)

  I = np.eye(len(W[0]) , 1)

  return (I - D.dot(W))

  pass

得到拉普拉斯矩陣

W = getWbyKNN(data , 5)

D = getD(W)

L = getLPLSmatrix(W , D)

之后就是獲得特征值特征向量了。

def getEigVec(L,cluster_num):  #從拉普拉斯矩陣獲得特征矩陣

  eigval,eigvec = np.linalg.eig(L)

  dim = len(eigval)

  dictEigval = dict(zip(eigval,range(0,dim)))

  kEig = np.sort(eigval)[0:cluster_num]

  ix = [dictEigval[k] for k in kEig]

  return eigval[ix],eigvec[:,ix]

eigval , eigvec = getEigVec(L , 5)

得到前5個

最后用Kmeans來計算

clk = KMeans(4)

clk.fit(eigvec)

C = clk.labels_

這是最后得到的標簽:

image

效果差不多吧。

colors = ['r' , 'b' , 'g' , 'y']

markers = ['x' , '^' , '+' , 's']

def draw(data , label):

  for i , j in zip(data , label):

      plt.scatter(i[0] , i[1] , color = colors[j] , marker=markers[j])

  plt.show()

  pass

畫圖:

image

這就是最后的效果了。

總體來說還是凝聚層次聚類好些。還有一些聚類判斷指標沒有寫,等看書了再不全吧,現在還是理論階段。

還有其他的距離模型,比如som神經網絡,GMM高斯混合模型等等,學到在說吧。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1 為什么要對特征做歸一化 特征歸一化是將所有特征都統一到一個大致相同的數值區間內,通常為[0,1]。常用的特征歸...
    顧子豪閱讀 6,556評論 2 22
  • 1 為什么要對特征做歸一化 特征歸一化是將所有特征都統一到一個大致相同的數值區間內,通常為[0,1]。常用的特征歸...
    顧子豪閱讀 1,423評論 0 1
  • 偏統計理論知識 1. 撲克牌54張,平均分成2份,求這2份都有2張A的概率。 答案一:M表示兩個牌堆各有2個A的情...
    美琦miki視覺筆記閱讀 4,497評論 0 10
  • 一、什么是用戶畫像? 男,31歲,已婚,收入1萬以上,愛美食,團購達人,喜歡紅酒配香煙。 這樣一串描述即為用戶畫像...
    T_129e閱讀 566評論 2 0
  • 在某些聚類任務中,可以以成對約束的形式獲得有限的監督,即標記為屬于相同或不同簇的實例對。由此產生的問題稱為半監督聚...
    AW_5365閱讀 2,268評論 0 3