機器學習(一)--分類,K-Means算法(NBA球星實例、超市用戶實例)

離散與連續

數據–數據對象、樣本、實例

離散屬性–類別屬性

  1. 用名稱標註
  2. 用類別/類別號來標註

連續屬性–連續的小數

  • 在一個區間內連續,用浮點型數值表示

數據集

多個數據組合在一起–數據集合–數據集

  1. 行:代表樣本
  2. 列:代表屬性

一、機器學習

(一)概念

在歷史數據中發現規律,然後利用規律,對新的數據進行預測與指導。
在這裏插入圖片描述

(二)數據分析與數據挖掘

人工智能的基礎

想要一個好的機器學習結果,就必須有一個好的數據處理。

數據分析與數據挖掘的區別

數據分析主要偏向於業務。

數據挖掘主要偏向於對數據價值的挖掘。

在這裏插入圖片描述

(三)按照學習方式分類

1.監督學習

數據:既有特徵值,又有目標值

研究:研究的是特徵與目標之間的關係

數據集

訓練集與測試集的劃分
在這裏插入圖片描述

算法代表

1.分類算法:目標值是離散的

(1)KNN算法

特點

  1. k值不同,分類的結果不同
  2. 需要將所有的數據,加載到內存,不斷計算每一個測試樣本與訓練樣本的距離。時間、空間消耗比較大。
  3. 惰性學習算法

優化
在這裏插入圖片描述

(2)貝葉斯算法

2.迴歸算法:目標值是連續的

2.無監督學習

數據:只有特徵值,無目標值數據

研究:研究的是樣本和樣本之間的關係

數據集

不需要劃分
在這裏插入圖片描述

算法代表

1.聚類算法–K-Means算法

利用樣本的特徵,使最終的結果,同一類別內的樣本具有較高的相似性,不同類別的樣本具有較高的相異性。
在這裏插入圖片描述

3.半監督學習

隱馬爾可夫模型

二、K-Means

應用場景

用於用戶羣體的劃分。

(一)k-means原理自實現

# 科學計算庫
import numpy as np
# 數據可視化庫
import matplotlib.pyplot as plt
# 數據處理庫
import pandas as pd

def bulid_data():
    '''
    構建數據
    :return:數據
    '''
    # 加載數據
    # 1.open
    # 2.np.loadtxt/np.genfromtxt -- 文本類型的數組
    # 3.pd.read_table
    # sep和delimiter都可以指定分隔符
    # header=None -- 不讓它將第一行設爲行標
    data = pd.read_table('test.txt',sep='\t',header=None)
    # 轉化爲矩陣(矩陣--特殊的數組)
    # mat = asmatrix
    # matrix -- 比mat多了一個拷貝內存的過程
    # bmat -- 組合矩陣
    data = np.mat(data.values)
    return data

def center_init(data,k):
    '''
    聚類中心初始化
    :param data: 數據
    :param k: 聚類的類別數目
    :return: center
    '''
    # 確定數據的行下標範圍
    index_num = data.shape[0]
    # 確定數據的列數
    column_num = data.shape[1]
    # 使用全零數組爲聚類中心佔位
    center = np.zeros((k,column_num))

    # 隨機選擇所有樣本中的k個樣本作爲最開始的聚類中心
    # 計數器
    i = 0
    # 避免重複
    r_list = []
    while True:
        r = np.random.randint(0,index_num-1)
        if r in r_list:
            continue
        else:
            r_list.append(r)
            center[i,:] = data[r,:]
            i+=1
        if len(r_list) == k:
            break
    return center

def distance(v1,v2):
    '''
    距離計算
    :param v1: 點1
    :param v2: 點2
    :return: 距離
    '''
    # # 方法1
    # sum_ = 0
    # # v1.shape -- 二維
    # # v2.shape -- 一維
    # # 將v1由2維降爲1維
    # # 將矩陣轉換爲數組:使用矩陣視圖
    # # 矩陣.A --> 數組
    # v1 = v1.A[0]
    # if v1.shape == v2.shape:
    #     for i in range(len(v1)):
    #         sum_ += (v1[i] - v2[i])**2
    # return np.sqrt(sum_)

    # 方法2
    diff = v1 - v2
    d = np.sqrt(np.sum(np.power(diff,2)))
    return d

def k_means_owns(data,k):
    '''
    自實現k-means原理
    :param data: 數據
    :param k: 聚類的類別數目
    :return: 各個樣本最終的類別,最終的聚類中心
    '''
    # 初始化聚類中心--隨機初始化
    # 隨機在所有樣本中選取k個聚類中心
    center = center_init(data,k)

    # 數據行數
    index_num = data.shape[0]
    # 定義數組,保存距離樣本最近的聚類中心及距離
    new_data = np.zeros((index_num,2))
    flag = True
    while flag:
        flag = False
        # 計算每一個訓練樣本與聚類中心的距離
        # 雙層循環----外層 -- 訓練樣本
        #             內層 -- 聚類中心
        for i in range(index_num):
            min_dist = 10000000000000000000
            min_index = -1
            for j in range(k):
                # 計算距離
                # 高緯度的數組使用下標,會進行降維度
                # 矩陣是二維的特殊數組,使用索引不會降維度
                d = distance(data[i, :], center[j, :])
                # print(d)
                if d < min_dist:
                    min_dist = d
                    min_index = j
            # 如果當前的樣本屬於的簇與上一次的不一致
            if new_data[i,0] != min_index:
                new_data[i:] = min_index, min_dist
                flag = True

        if flag:
            # 計算新的聚類中心
            # 計算每一簇的均值 -- 每一簇的中心
            # 使用bool數組索引
            for p in range(k):
                bool_index = new_data[:, 0] == p
                # 選定簇
                p_cluster = data[bool_index, :]
                # 新的聚類中心
                center[p, :] = p_cluster[:, 0].mean(), p_cluster[:, 1].mean()
        # 如果新的聚類中心,與上一次的聚類中心重合--結束
        # 改變思路:如果所有樣本所屬的聚類中心,與上一次所屬的聚類中心相同--結束
    return new_data,center

def show_res_owns(data,new_data,center):
    '''
    結果展示
    :param data: 原始數據
    :param new_data: 保存着各個樣本最終的類別
    :param center: 最終的聚類中心
    :return: None
    '''
    # 1.創建畫布
    plt.figure()
    # 顯示中文,支持負號
    plt.rcParams['font.sans-serif'] = 'SimHei'
    plt.rcParams['axes.unicode_minus'] = False
    # 2.繪圖
    # 設置顏色列表
    c_list = ['b','g','y','pink']
    # 設置點形狀列表
    marker_list = ['*','o','^','D']
    # 繪製散點圖
    for i in range(data.shape[0]):
        plt.scatter(data[i,0],data[i,1],c=c_list[int(new_data[i,0])],marker=marker_list[int(new_data[i,0])])
    # 繪製聚類中心
    plt.plot(center[:,0],center[:,1],'bx',markersize=12)
    # 增加名稱
    plt.title('聚類結果展示')
    # 保存圖片
    plt.savefig('聚類結果展示')
    # 3.繪圖展示
    plt.show()

def main():
    # 1.構建數據
    data = bulid_data()
    # print(data)
    # print(type(data))
    # print(data.dtype)
    # 2.自實現k-means算法原理
    # 確定聚類的類別數目
    k = 4
    new_data,center = k_means_owns(data,k)

    # 3.結果展示
    show_res_owns(data,new_data,center)

if __name__ == '__main__':
    main()

(二)使用sklearn

# 科學計算庫
import numpy as np
# 數據可視化庫
import matplotlib.pyplot as plt
# 數據處理庫
import pandas as pd
from sklearn.cluster import KMeans

def bulid_data():
    '''
    構建數據
    :return:數據
    '''
    # 加載數據
    # 1.open
    # 2.np.loadtxt/np.genfromtxt -- 文本類型的數組
    # 3.pd.read_table
    # sep和delimiter都可以指定分隔符
    # header=None -- 不讓它將第一行設爲行標
    data = pd.read_table('test.txt',sep='\t',header=None)
    # 轉化爲矩陣(矩陣--特殊的數組)
    # mat = asmatrix
    # matrix -- 比mat多了一個拷貝內存的過程
    # bmat -- 組合矩陣
    data = np.mat(data.values)
    return data

def show_res(data,y_predict,center):
    '''
    結果展示
    :param data: 原始數據
    :param y_predict:預測類別
    :param center: 聚類中心
    :return: None
    '''
    # 1.創建畫布
    plt.figure()
    # 顯示中文,支持負號
    plt.rcParams['font.sans-serif'] = 'SimHei'
    plt.rcParams['axes.unicode_minus'] = False
    # 2.繪圖
    # 設置顏色列表
    c_list = ['b','g','y','pink']
    # 設置點形狀列表
    marker_list = ['*','o','^','D']
    # 繪製散點圖
    for i in range(data.shape[0]):
        plt.scatter(data[i,0],data[i,1],c=c_list[y_predict[i]],marker=marker_list[y_predict[i]])
    # 繪製聚類中心
    plt.plot(center[:,0],center[:,1],'bx',markersize=12)
    # 增加名稱
    plt.title('聚類結果展示')
    # 保存圖片
    plt.savefig('聚類結果展示')
    # 3.繪圖展示
    plt.show()

def main():
    # 1.構建數據
    data = bulid_data()
    # 2.使用sklearn中的KMeans進行聚類分析
    # 確定聚類的類別數目
    k = 4
    # (1)構建算法實力
    # n_clusters--指定聚類的類別
    km = KMeans(n_clusters=k)
    # init='k-means++'--以一種更優的方式選取初始聚類中心
    # (2)進行訓練數據
    km.fit(data)
    # (3)驗證模型的好壞,即得到預測值
    y_predict = km.predict(data)
    # k-means算法--得到聚類中心
    center = km.cluster_centers_
    print('預測類別:\n',y_predict)
    print('聚類中心:\n',center)
    # 3.結果可視化
    show_res(data,y_predict,center)

if __name__ == '__main__':
    main()

(三)實例–NBA球星(sklearn)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

def show_res(data,y_predict,center):
    '''
    結果展示
    :param data: 原始數據
    :param y_predict:預測類別
    :param center: 聚類中心
    :return: None
    '''
    # 1.創建畫布
    plt.figure()
    # 顯示中文,支持負號
    plt.rcParams['font.sans-serif'] = 'SimHei'
    plt.rcParams['axes.unicode_minus'] = False
    # 2.繪圖
    # 設置顏色列表
    c_list = ['b','g','y','pink','red']
    # 設置點形狀列表
    marker_list = ['*','o','^','D','8']
    # 繪製散點圖
    for i in range(data.shape[0]):
        plt.scatter(data[i,0],data[i,1],c=c_list[y_predict[i]],marker=marker_list[y_predict[i]])
    # 繪製聚類中心
    plt.plot(center[:,0],center[:,1],'bx',markersize=12)
    # 增加名稱
    plt.title('NBA球星聚類結果展示')
    # 保存圖片
    plt.savefig('NBA球星聚類結果展示')
    # 3.繪圖展示
    plt.show()

def build_data(data):
    '''
    數據預處理
    :return:預處理後的數據
    '''
    # 2.數據合併
    # 只有一個表

    # 3.數據清洗
    #   (1)檢測與處理缺失值
    #       檢測:pd.inull().sum()
    #       處理:刪除值、填充法、插值法
    #           處理非NaN類型缺失值,先將這種數據轉化爲np.NaN類型,再進行處理
    # res_null = pd.isnull(data).sum()
    # print(res_null)    # 無缺失值

    #   (2)處理異常值
    #       3sigma原理、箱線圖分析法
    # 無異常值

    # 4.篩選有用的特徵
    data = data.loc[:, ['時間', '助攻', '得分']]
    # print(data.dtypes)
    # 時間     object
    # 助攻    float64
    # 得分    float64
    # 將時間這一列的空格缺失值,轉換成np.NaN類型
    data.loc[:, '時間'].replace(' ', np.NaN, inplace=True)
    # res_null = pd.isnull(data).sum()
    # print(res_null)    # 時間列有393個空值

    # 處理缺失值
    # 使用上一個鄰居來填充缺失值
    data.loc[:'時間'].fillna(method='pad', inplace=True)
    # res_null = pd.isnull(data).sum()
    # print(res_null)    # 無空值

    # 將時間的數據類型轉化爲float類型
    data.loc[:, '時間'] = data.loc[:, '時間'].astype(np.float64)
    # print(data.dtypes)

    # 構建最終的得分/分鐘  助攻/分鐘
    data.loc[:, '得分/分鐘'] = data.loc[:, '得分'] / data.loc[:, '時間']
    data.loc[:, '助攻/分鐘'] = data.loc[:, '助攻'] / data.loc[:, '時間']
    data = data.loc[:, ['得分/分鐘', '助攻/分鐘']]
    return data

def main():
    # 1.加載、構建數據
    data = pd.read_excel('nba_data.xlsx')
    # print(data)
    # print(data.columns)

    data = build_data(data)
    # [5].標準化?
    #   做數據分析時,暫時不要做;要進行機器學習算法構建模型的時候,必須要做
    # 無需消除量綱

    # [6].構建模型--算法模型--進行訓練數據--進行預測
    # 確定聚類類別數量
    k = 5
    # 創建算法實例
    km = KMeans(n_clusters=k)
    # 訓練數據
    km.fit(data.values)
    # 進行預測
    y_predict = km.predict(data.values)
    # 預測中心
    center = km.cluster_centers_
    print('預測值:\n',y_predict)
    print('聚類中心:\n',center)

    # 7.數據可視化--折線圖、散點圖、直方圖、柱狀圖、餅圖、箱線圖
    show_res(data.values,y_predict,center)

    # 8.結論

if __name__ == '__main__':
    main()

三、補充

(一)3sigma

在這裏插入圖片描述

異常值處理之3sigma

import pandas as pd

# 3sigma原則
# [mean-3*std,mean+s*std]
# 99.73%的數據

def three_sigma(data):
    '''
    進行3sigma異常值處理
    :param data: 需要進行處理的數據--series
    :return: bool數組
    '''
    # 下限
    low = data.mean() - 3*data.std()
    up = data.mean() + 3*data.std()

    # 正常--True,異常--False
    bool_index = (low <= data) & (data <= up)

    return bool_index

# 驗證異常值處理
detail = pd.read_excel('meal_order_detail.xlsx')
# print(detail)
# print(detail.columns)
print(detail.shape[0])

# 對菜品的單價數據進行異常值剔除
bool_index = three_sigma(detail.loc[:, "amounts"])

detail = detail.loc[bool_index,:]
# print('按照菜品單價剔除異常值之後的結果\n',detail)
print(detail.shape[0])

(二)標準化

量級相差過大,就需要進行標準化

1.離差標準化

x = (x-min)/(max-min)

2.標準差標準化(推薦)

x = (x-mean)/std

3.小數定標標準化

通過移動數據的小數點位置來進行標準化。

k --> int(np.ceil(np.log10(|x|.max())))

x = x/10^k

(三)維度

行的方向是行增大的方向,即向下

列的方向是列增大的方向,即向右

1.一維

shape:(9,)

一維的數組只有列維度

axis=0,axis=-1 – 代表列維度

2.二維(多個一維組成)

shape:(2,3)

行列維度

axis=0,axis=-2 – 代表行維度

axis=1,axis=-1 – 代表列維度

3.三維(多個二維組成)

shape:(1,2,3)

塊行列維度

axis=0 – 代表塊維度

axis=1 – 代表行維度

axis=2 – 代表列維度

4.四維(多個三維組成)

shape:(1,2,3,4)

堆塊行列維度

……

……

mean()默認維度測試

import numpy as np
import pandas as pd

df = pd.DataFrame(data=np.array([[1,2,5],[1,3,4],[4,4,5]]))

print(df)
print(df.mean())

#    0  1  2
# 0  1  2  5
# 1  1  3  4
# 2  4  4  5
# 0    2.000000
# 1    3.000000
# 2    4.666667
# dtype: float64

發現最終的結果,求的是一列的平均值,即行增大的方向,也就是按行的方向求的。

即mean()默認的axis=0。

四、作業

  1. 將NBA實例的sklearn實現改爲自實現
  2. 超市用戶聚類案例

(一)NBA–自實現

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def bulid_data(data):
    data = data.loc[:,['時間','助攻','得分']]
    # res_null = pd.isnull(data).sum()
    # print(res_null)
    data.loc[:,'時間'].replace(' ',np.NaN,inplace=True)
    data.loc[:,'時間'].fillna(method='pad',inplace=True)
    data.loc[:'時間'] = data.loc[:'時間'].astype(np.float64)
    data.loc[:,'助攻/時間'] = data.loc[:,'助攻']/data.loc[:,'時間']
    data.loc[:,'得分/時間'] = data.loc[:,'得分']/data.loc[:,'時間']
    data = data.loc[:,['得分/時間','助攻/時間']]
    return np.mat(data.values)

def center_init(data,k):
    index_num = data.shape[0]
    column_num = data.shape[1]
    # print(index_num)
    center = np.zeros((k,column_num))
    r_list = []
    i = 0
    while True:
        r = np.random.randint(0,index_num-1)
        if r in r_list:
            continue
        else:
            r_list.append(r)
            center[i,:] = data[r,:]
            i += 1
        if len(r_list) == k:
            break
    return center

def distance(v1,v2):
    diff = v1-v2
    return np.sqrt(np.sum(np.power(diff,2)))

def k_means_owns(data,k):
    # 隨機選取k個聚類中心
    center = center_init(data,k)

    index_num = data.shape[0]
    new_data = np.zeros((index_num,2))
    flag = True
    while flag:
        flag = False
        for i in range(index_num):
            min_distence = 1000000000000000
            min_index = -1
            for j in range(k):
                # 計算距離聚類中心距離
                d = distance(data[i,:],center[j,:])
                if d < min_distence:
                    min_distence = d
                    min_index = j
            if new_data[i,0] != min_index:
                flag = True
                new_data[i,:] = min_index,min_distence

        if flag:
            # 計算新的聚類中心
            for p in range(k):
                bool_index = new_data[:,0] == p
                p_cluster = data[bool_index,:]
                center[p,:] = p_cluster[:,0].mean(),p_cluster[:,1].mean()
    return new_data,center

def show_res(data,new_data,center):
    plt.figure()
    plt.rcParams['font.sans-serif'] = 'SimHei'
    plt.rcParams['axes.unicode_minus'] = False
    c_list = ['c','g','y','pink','red']
    marker_list = ['*','o','^','D','8']
    # 繪製樣本數據
    for i in range(data.shape[0]):
        plt.scatter(data[i,0],data[i,1],c=c_list[int(new_data[i,0])],marker=marker_list[int(new_data[i,0])])
    # 繪製聚類中心
    plt.plot(center[:, 0], center[:, 1], 'bx', markersize=12)
    plt.title('NBA球星聚類分析結果')
    plt.savefig('NBA球星聚類分析結果')
    plt.show()

def main():
    # 讀取數據
    data = pd.read_excel('../03.實例:基於k_means算法實現NBA球員聚類分析/nba_data.xlsx')
    # print(data)
    # 構建數據
    data = bulid_data(data)
    # k-means自實現
    # 確定聚類中心個數
    k = 5
    new_data,center = k_means_owns(data, k)
    show_res(data,new_data,center)

if __name__ == '__main__':
    main()

(二)超市用戶–sklearn

import numpy as np
import pandas as pd
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt

def stand_sca(data):
    '''
    標準差標準化
    :param data:需要標準化的數據
    :return:標準化後的數據
    '''
    data = (data-data.mean())/data.std()
    return data

def min_max_sca(data):
    '''
    離差標準化
    :param data: 需要標準化的數據
    :return: 標準化後的數據
    '''
    data = (data-data.min(axis=0))/(data.max(axis=0)-data.min(axis=0))
    return data

def desc_sca(data):
    '''
    小數定標標準化
    :param data: 需要標準化的數據
    :return: 標準化之後的數據
    '''
    k = int(np.ceil(np.log10(data.abs().max())))
    data = data / (10**k)
    return data

def build_data():
    # 1.構建數據
    data = pd.read_table('company.csv', sep=',', encoding='gbk')

    # 2.篩選特徵值
    data = data.loc[:,['平均每次消費金額','平均消費週期(天)']]

    # 3.缺失值檢測
    # res_null = pd.isnull(data).sum()
    # print(res_null)

    # 4.處理異常值
    # 無異常值

    # 5.標準化
    # (1)標準差標準化
    # data = stand_sca(data)
    # (2)離差標準化
    data = min_max_sca(data)
    return np.mat(data.values)

def k_means(data):
    # 確定聚類中心個數
    k = 3
    # 1.創建算法實例
    km = KMeans(n_clusters=k)
    # 2.訓練數據
    km.fit(data)
    # 3.進行預測
    y_predict = km.predict(data)
    # 獲取聚類中心
    center = km.cluster_centers_
    # print('預測值:\n',y_predict)
    # print('聚類中心:\n',center)
    return y_predict,center

def show(data,y_predict,center):
    plt.figure()
    plt.rcParams['font.sans-serif'] = 'SimHei'
    plt.rcParams['axes.unicode_minus'] = False
    c_list = ['pink','yellow','green','blue']
    marker_list = ['*','>','^','o']
    for i in range(data.shape[0]):
        plt.scatter(data[i,0],data[i,1],c=c_list[y_predict[i]],marker=marker_list[y_predict[i]])
    plt.plot(center[:,0],center[:,1],'bx',markersize=12)
    plt.title('超市用戶聚類結果')
    plt.savefig('超市用戶聚類結果')
    plt.show()

def main():
    data = build_data()
    # print(data)
    y_predict,center = k_means(data)
    show(data,y_predict,center)

if __name__ == '__main__':
    main()

(三)超市用戶–自實現

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def stand_sca(data):
    '''
    標準差標準化
    '''
    data = (data - data.mean())/data.std()
    return data

def min_max_sca(data):
    '''
    離差標準化
    '''
    data = (data - data.min())/(data.max()-data.min())
    return data

def build_data():
    # 獲取數據
    data = pd.read_table('company.csv', sep=',', encoding='gbk')

    # 獲取有效數據
    data = data.loc[:,['平均每次消費金額','平均消費週期(天)']]

    # 檢測缺失值
    # res_null = pd.isnull(data).sum()
    # print(res_null)

    # 檢測異常值
    # 無異常值

    # 標準化
    data = min_max_sca(data)

    return np.mat(data.values)

def center_init(data,k):
    index_num = data.shape[0]
    center = np.zeros((k,data.shape[1]))
    r_list = []
    i = 0
    while True:
        r = np.random.randint(0,index_num-1)
        if r in r_list:
            continue
        else:
            center[i,:] = data[r,:]
            r_list.append(r)
            i += 1
        if len(r_list) == k:
            break
    return center

def distance(v1,v2):
    diff = v1-v2
    d = np.sqrt(np.sum(np.power(diff,2)))
    return d

def k_means_owns(data,k):
    center = center_init(data,k)
    # print(center)

    index_num = data.shape[0]
    column_num = data.shape[1]
    new_data = np.zeros((index_num,column_num))
    for i in range(index_num):
        min_dis = 1000000000000
        min_index = -1
        for j in range(k):
            d = distance(data[i,:],center[j,:])
            if d < min_dis:
                min_dis = d
                min_index = j
        new_data[i,:] = min_index,min_dis

    for p in range(k):
        bool_index = new_data[:,0] == p
        p_cluster = data[bool_index,:]
        center[p,:] = p_cluster[:,0].mean(),p_cluster[:,1].mean()
    return new_data,center

def show(data,new_data,center):
    plt.figure()
    plt.rcParams['font.sans-serif'] = 'SimHei'
    plt.rcParams['axes.unicode_minus'] = False
    c_list = ['pink','yellow','green','blue']
    marker_list = ['*','>','^','o']
    for i in range(data.shape[0]):
        plt.scatter(data[i,0],data[i,1],c=c_list[int(new_data[i,0])],marker=marker_list[int(new_data[i,0])])
    plt.plot(center[:,0],center[:,1],'bx',markersize=12)
    plt.title('超市用戶聚類結果')
    plt.savefig('超市用戶聚類結果')
    plt.show()

def main():
    data = build_data()
    print(data)
    k = 3
    new_data,center = k_means_owns(data,k)
    show(data,new_data,center)

if __name__ == '__main__':
    main()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章