K-means演算法(將表中的點分為n類)
阿新 • • 發佈:2018-12-12
客戶分類:
1、將客戶分為三類:超級VIP、vip、普通使用者
2、需要你將不同的類的資料,在圖上顯示出來,用不同的顏色
3、返回三個類中,各包含哪些點
資料在下面的的表中,因為無法上傳表格所以截了個圖!
import matplotlib.pyplot as plt import numpy as np import pandas as pd import random def decimal_clean(arr): ''' 將輸入序列進行小數定標標準化 :param arr:輸入的待優化的序列 :return:標準化後的序列 ''' k = np.ceil(np.log10(np.max(np.abs(arr)))) return arr / 10 ** k def iter_self(xy_line, n_type): ''' 自我迭代函式, 自我生成n_type個隨機參考點進行迴圈迭代, 每次迭代的最後利用本次分割槽結果求新的參考點 迭代退出條件, 新的參考點跟上一次的參考點位置一致 :param xy_line: 輸入的x_y序列 :param n_type: 分類數目 :return: 劃分完成的區域 ''' # 進入函式, 初始化舊參考點位置序列與新參考點位置序列 old_pos = [[random.random(), random.random()] for i in range(n_type)] new_pos = [[] for i in range(n_type)] # 進入迴圈迭代 while True: # 每一次的迴圈都重新整理一次分割槽列表 area = [[] for i in range(n_type)] # 對每一個點遍歷 for pos in range(len(xy_line)): # 獲得這個點的座標 this_pos = [xy_line.iloc[pos, 0], xy_line.iloc[pos, 1]] # 建立空列表,用於存放該點與各個參考點的歐式距離 distance = [] # 針對每一個點的座標對所有中心點求歐式距離 for i in range(n_type): distance.append(Oup_distance(this_pos, old_pos[i])) # 找到所有距離中最小點的索引, 即該點屬於第幾區 min_index = distance.index(min(distance)) # 根據該點的區號, 進行分割槽 area[min_index].append(this_pos) # 判斷是否有空區域, 如果有, 重新呼叫本函式, 得到返回結果之後直接break if [] in area: area = iter_self(xy_line, n_type) break # 來到此步, 證明各個分割槽都是有值的, 用均值法求出各區對應的新的參考點座標 new_pos = reflush_pos(area, n_type, new_pos) # 判斷新參考點與就參考點是否一致, 一致即可退出迴圈 if new_pos == old_pos: break else: # 否則將新的點序列深拷貝給舊的點序列, 新的點序列置空 old_pos = new_pos.copy() new_pos = [[] for i in range(n_type)] return area def reflush_pos(area, n_type, pos): ''' 重新整理參考點位置 :param area: 分割槽序列 :param n_type: 種類數目 :param pos: 用於存放新參考點的序列 :return: 新的參考點序列 ''' # 對area進行遍歷 for i in range(n_type): # 將area[i]深拷貝賦值給this, 在進行numpy陣列轉換 this = area[i].copy() # 如果不進行深拷貝, 此步會將整個area轉換成numpy陣列 this_area = np.array(this) # 求x序列和y序列的均值, 並賦值給pos x_mean = np.mean(this_area[:, 0]) y_mean = np.mean(this_area[:, 1]) pos[i] = [x_mean, y_mean].copy() return pos def Oup_distance(pos1, pos2): ''' 計算兩點之間的歐式距離 :param pos1:點1的(x, y)座標 :param pos2:點2的(x, y)座標 :return:兩點之間的歐式距離值 ''' Oup = np.sqrt((pos1[1] - pos2[1]) ** 2 + (pos1[0] - pos2[0]) ** 2) return Oup company = pd.read_csv(r"C:\Users\Administrator\Desktop\company.csv", encoding="gbk") # 這裡用的是iloc的提取方法, 也可以根據個人習慣使用其他提取方法 # 此處特意將時間和消費金額兩列作為x和y使用concat函式合併到一個dataframe, 方便後面的處理 x_y = pd.concat([decimal_clean(company.iloc[:, 2]), decimal_clean(company.iloc[:, 1])], axis=1, join="outer") # 得到三維的列表AREA AREA = iter_self(x_y, 3) # 畫圖 plt.figure() for area in AREA: # area是二維列表,將其變為二維陣列 area_np = np.array(area) x = area_np[:, 0] y = area_np[:, 1] # 將x,y聯絡起來 plt.scatter(x, y) # 顯示畫圖 plt.show()