机器学习----05

8 篇文章 0 订阅

案例: 事件预测

加载event.txt, 预测某个时间段是否会出现特殊时间.


import numpy as np
import sklearn.preprocessing as sp
from sklearn import svm
import sklearn.model_selection as ms


class DigitEncoder ():

    def fit_transform(self, x):
        return x.astype(int)

    def transform(self, x):
        return x.astype(int)

    def inverse_transform(self, x):
        return x.astype(str)

data = []
with open('event.txt', 'r') as f:
    for line in f.readlines():
        data.append(line[:-1].split(','))
data = np.delete(np.array(data).T, 1, 0)
print(data)
encoders, x = [], []
for row in range(len(data)):
    if data[row, 0].isdigit():
        encoder = DigitEncoder()
    else:
        encoder = sp.LabelEncoder()
    if row < len(data) - 1:
        x.append(encoder.fit_transform(data[row]))
    else:
        y = encoder.fit_transform(data[row])
    encoders.append(encoder)
x = np.array(x).T
train_x, test_x, train_y, test_y = ms.train_test_split(
    x, y, test_size=0.25, random_state=5)
model = svm.SVC(kernel='rbf', class_weight='balanced')
model.fit(train_x, train_y)
pred_test_y = model.predict(test_x)
print((pred_test_y == test_y).sum() / test_y.size)

data = [['Tuesday', '14:00:00', '13', '11']]
data = np.array(data).T
x = []
for row in range(len(data)):
    encoder = encoders[row]
    x.append(encoder.transform(data[row]))
x = np.array(x).T
pred_y = model.predict(x)
print(encoders[-1].inverse_transform(pred_y))

案例交通流量预测

加载traffic.txt, 预测某个时间段某个路口的车流量.


import numpy as np
import sklearn.preprocessing as sp
import sklearn.model_selection as ms
import sklearn.svm as svm
import sklearn.metrics as sm

class DigitEncoder:

    def fit_transform(self, x):
        return x.astype(int)

    def transform(self, x):
        return x.astype(int)

    def inverse_transform(self, x):
        return x.astype(str)

data = []
data = np.loadtxt('traffic.txt', delimiter=',', dtype='U16')
data = data.T
encoders, x, y = [], [], []
for row in range(len(data)):
    if data[row][0].isdigit():
        encoder = DigitEncoder()
    else:
        encoder = sp.LabelEncoder()
    if row < len(data) - 1:
        x.append(encoder.fit_transform(data[row]))
    else:
        y = encoder.fit_transform(data[row])
    encoders.append(encoder)

x = np.array(x).T
# 划分测试集训练集
train_x, test_x, train_y, test_y = ms.train_test_split(
    x, y, test_size=0.25, random_state=7
)
# 使用SVM回归器训练模型
model = svm.SVR(kernel='rbf', C=10)
model.fit(train_x, train_y)
pred_test_y = model.predict(test_x)
print(sm.r2_score(test_y, pred_test_y))

# 执行业务预测
data = [['Tuesday', '13:35', 'San Francisco', 'yes']]
data = np.array(data).T
x = []
for row in range(len(data)):
    encoder = encoders[row]
    x.append(encoder.transform(data[row]))
x = np.array(x).T
pred_y = model.predict(x)
print(pred_y)

聚类

分类(classification)与聚类(cluster)不同, 分类是有监督学习模型, 聚类属于无监督学习模型. 聚类讲究使用一些算法把样本划分称为n个群落. 一般情况下, 这种算法都需要计算欧氏距离.

欧几里得距离

P ( x 1 ) − Q ( x 2 ) : ∣ x 1 − x 2 ∣ = ( x 1 − x 2 ) 2 P ( x 1 , y 1 ) − Q ( x 2 , y 2 ) : ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 P ( x 1 , y 1 , z 1 ) − Q ( x 2 , y 2 , z 2 ) : ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 + ( z 1 − z 2 ) 2 P(x_1) - Q(x_2):|x_1 - x_2| = \sqrt{(x_1-x_2)^2} \\ P(x_1, y_1) - Q(x_2, y_2): \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2} \\ P(x_1, y_1, z_1) - Q(x_2, y_2, z_2): \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2 + (z_1 - z_2)^2} \\ P(x1)Q(x2):x1x2=(x1x2)2 P(x1,y1)Q(x2,y2):(x1x2)2+(y1y2)2 P(x1,y1,z1)Q(x2,y2,z2):(x1x2)2+(y1y2)2+(z1z2)2
用两个样本对应特征值之差的平方和的平方根, 即欧式距离, 用来表示两个样本的相似性.

K均值算法

第一步: 随机选择K个样本作为K个聚类中心, 计算每个样本到各个聚类中的欧氏距离, 将该样本分配到与之最近的聚类中心所在的类别中.

第二步: 根据第一步得到的聚类划分, 分别计算每个聚类的几何中心, 将几何中心作为新的聚类中心, 重复第一步, 直到计算所得几何中心与聚类中心重合或相近.

注意:

  1. 聚类数必须事先已知, 借助某些评估指标, 优选最好的聚类数量.
  2. 聚类中心的初始选择会影响到最终聚类划分的结果, 初始中心尽量选择距离较远的样本.

K举止相关API:

import sklearn.cluster as sc
# n_clusters: 聚类的类别数量.
model = sc.KMeans(n_clusters=4)
# 给出训练样本
model.fit(x)
# 预测样本类别
c = model.predict(x)
# 获取训练结果的聚类中心
centers = model.cluster_centers_

案例: 加载multiple3.txt, 完成KMeans聚类

import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp

x = np.loadtxt('multiple3.txt', delimiter=',')
# KMeans聚类模型
model = sc.KMeans(n_clusters=20)
model.fit(x)
pre_dict_c = model.predict(x)
centers = model.cluster_centers_
print(pre_dict_c)

# 计算分类边界
n = 500
l, r = x[:, 0].min() - 1, x[:, 0].max() + 1
b, t = x[:, 1].min() - 1, x[:, 1].max() + 1
grid_x, grid_y = np.meshgrid(
    np.linspace(l, r, n),
    np.linspace(b, t, n)
)
samples = np.column_stack(
    (grid_x.ravel(), grid_y.ravel())
)
grid_z = model.predict(samples)
grid_z = grid_z.reshape(grid_x.shape)

# 画图
mp.figure('K-Means Cluster', facecolor='lightgray')
mp.title('K-Means Cluster', fontsize=14)
mp.xlabel('x', fontsize=12)
mp.ylabel('y', fontsize=13)
mp.tick_params(labelsize=10)

# 绘制分类边界
mp.pcolormesh(grid_x, grid_y, grid_z, cmap='gray')

mp.scatter(x[:, 0], x[:, 1], c=pre_dict_c, cmap='brg', s=60, alpha=0.6, label='samples')
mp.scatter(centers[:, 0], centers[:, 1], color='orangered', marker='+', s=300, label='Centers')
mp.legend()
mp.show()

图像量化

KMeans聚类算法可以应用于图像量化领域. 通过KMeans算法把一张图像所包含的颜色值进行聚类划分, 求每一类别的平均值后, 再重新生成新的图像. 可以达到图像降维的目的, 更有利于图像识别. 这个过程称为图像量化.

案例:

import numpy as np
import scipy.misc as sm
import scipy.ndimage as sn
import sklearn.cluster as sc
import matplotlib.pyplot as mp

img = sm.imread('lily.jpg', True)
x = img.reshape(-1, 1)  # n行1列
model = sc.KMeans(n_clusters=4)
model.fit(x)
y = model.labels_
centers = model.cluster_centers_.ravel()
# 把y数组中相应元素的值改为centers的值
# 生成新图片, 处理后, 图片中只包含centers范围内的值
img2 = centers[y].reshape(img.shape)    # 利用掩码进行reshape
mp.figure('Image')
mp.subplot(121)
mp.axis('off')
mp.imshow(img, cmap='gray')
mp.subplot(122)
mp.axis('off')
mp.imshow(img2, cmap='gray')
mp.tight_layout()
mp.show()

均值漂移算法

首先假定样本空间的每个聚类均服从某个已知的概率分布规则, 然后用不同的概率密度函数拟合样本中的统计直方图, 不断移动密度函数的中心位置, 直到获得最佳的拟合效果为止. 这些概率密度函数曲线的峰值点就是聚类的中心, 再根据每个样本与各个中心的距离, 选择最近的聚类中心所属类别作为该样本的类别.
均值漂移算法的特点:

  1. 聚类数不必事先已知, 算法会自动识别出统计直方图的中心数量.
  2. 聚类中心不依据于最初假定, 聚类划分的结果相对稳定.
  3. 样本空间应该服从某种概率分布规则, 否则算法的准确性将会大打折扣.

均值漂移相关API:

# 获取量化带宽对象
bw = sc.estimate_bandwidth(
    x,  # 输入集
    n_samples=len(x),    #样本数量
    quantile=0.1    # 量化带宽(统计直方图的宽度)
)
sc.Meanshift(bandwidth=bw, bin_seeding=True)
model.fit(x)
model.predict(x)

案例: multiple3.txt, 使用均值漂移做聚类划分.

import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp

x = np.loadtxt('multiple3.txt', delimiter=',')
# KMeans聚类模型
model = sc.KMeans(n_clusters=4)
model.fit(x)
pre_dict_c = model.predict(x)
centers = model.cluster_centers_
print(pre_dict_c)
...

凝聚层级算法

首先假定每个样本都是一个独立的聚类, 如果统计出来的聚类数大于期望的聚类数, 则从每个样本出发, 寻找离自己最近的另一个样本, 与之狙击, 形成更大的聚类. 同时令总聚类数减少, 不断重复以上过程, 直到统计出来的聚类数达到期望值为止.

凝聚层次算法的特点:

  1. 聚类数k必须事先已知. 借助某些评估指标, 优选最好的聚类数.
  2. 没有聚类中心概念, 因此只能在训练集中心划分聚类, 不能对训练集以外的未知样本确定其归属
  3. 在确定被凝聚的样本时, 出了以距离作为条件外, 还可以根据连续性来确定被凝聚的样本.

凝聚层次算法相关API:

# 构建凝聚层次聚类模型
model = sc.AgglometativeClustering(n_cluster=4)
# 训练 + 预测
pred_y = model.fit_predict(x)

案例:

import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp

x = np.loadtxt('multiple3.txt', delimiter=',')
# KMeans聚类模型
model = sc.KMeans(n_clusters=4)
model.fit(x)
pre_dict_c = model.predict(x)
centers = model.cluster_centers_
print(pre_dict_c)

# 计算分类边界
n = 500
l, r = x[:, 0].min() - 1, x[:, 0].max() + 1
b, t = x[:, 1].min() - 1, x[:, 1].max() + 1
grid_x, grid_y = np.meshgrid(
    np.linspace(l, r, n),
    np.linspace(b, t, n)
)
samples = np.column_stack(
    (grid_x.ravel(), grid_y.ravel())
)
grid_z = model.predict(samples)
grid_z = grid_z.reshape(grid_x.shape)

# 画图
mp.figure('K-Means Cluster', facecolor='lightgray')
mp.title('K-Means Cluster', fontsize=14)
mp.xlabel('x', fontsize=12)
mp.ylabel('y', fontsize=13)
mp.tick_params(labelsize=10)

# 绘制分类边界
mp.pcolormesh(grid_x, grid_y, grid_z, cmap='gray')

mp.scatter(x[:, 0], x[:, 1], c=pre_dict_c, cmap='brg', s=60, alpha=0.6, label='samples')
mp.scatter(centers[:, 0], centers[:, 1], color='orangered', marker='+', s=300, label='Centers')
mp.legend()
mp.show()

使用凝聚层次算法, 根据连续性来确定被聚集的样本类别划分相关API:

# linkage='average', 无连续性的凝聚层次聚类器
model = sc.AgglomerativeClustering(
    linkage='average', n_clusters=4)
# 基于连续性的凝聚层次聚类器
# 近邻筛选器
conn = nb.kneighbors_graph(x, 10, include_self=False)
model = sc.AgglomerativeClustering(
    linkage='average', n_clusters=4,
    conntivity=conn)

案例:

import numpy as np
import sklearn.cluster as sc
import sklearn.neighbors as nb
import matplotlib.pyplot as mp

x = np.loadtxt('multiple3.txt', delimiter=',')
# 连续性的凝聚层次聚类器
# conn = nb.kneighbors_graph(x, 1, include_self=False)
# model = sc.AgglomerativeClustering(
#     linkage='average', n_clusters=4,
#     connectivity=conn)

model = sc.AgglomerativeClustering(
    linkage='average', n_clusters=4
)

pre_dict_c = model.fit_predict(x)
print(pre_dict_c)

# 画图
mp.figure('Agglo Cluster', facecolor='lightgray')
mp.title('Agglo Cluster', fontsize=14)
mp.xlabel('x', fontsize=12)
mp.ylabel('y', fontsize=13)
mp.tick_params(labelsize=10)


mp.scatter(x[:, 0], x[:, 1], c=pre_dict_c, cmap='brg', s=60, alpha=0.6, label='samples')
mp.legend()

mp.show()

轮廓系数

轮廓系数用于评估聚类器的好坏. 好的聚类: 内密外疏, 同一个聚类内部的样本要足够密集, 不同的聚类之间样本要足够疏远.

轮廓系数的计算规则: 针对样本空间中的一个特定样本, 计算它与所在聚类其他样本的平均距离a, 以及该样本与距离最近的另一个聚类中所有样本的平均距离b, 该样本的轮廓系数为(b - a) / max(a, b). 将整个样本空间中所有样本的轮廓系数取算数平均值, 作为菌类划分的性能指标.

轮廓系数的取值区间: [-1, 1]. -1代表分类效果差, 1代表分类效果好. 0代表聚类重叠, 没有很好的划分.

轮廓系数相关API:

import sklearn.metrics as sm
# v: 返回样本空间所有样本的平均轮廓系数
# metric: euclidean 使用欧几里得距离算法
v = sm.silhouette_score(
    输入集, 输出集,
    sample_size=样本数,
    metric=距离算法
)

案例:

# 输出轮廓系数指标
v = sm.silhouette_score(
    x, pre_dict_c,
    sample_size=len(x),
    metric='euclidean'
)
print(v)

DBSCAN算法

从样本空间中任意选择一个样本, 以事先给定的半径做圆, 凡被该圆圈中的样本都视为与该样本处于相同的聚类, 以这些被圈中的样本为圆心继续画圆, 重复以上过程, 不断扩大被权重样本的规模, 直到再也没有新的样本加入为止, 至此得到一个聚类. 在剩余样本中, 重复以上过程, 直到耗尽样本空间中所有样本为止.

DBSCAN算法的特点:

  1. 事先给定的半径会影响最后的聚类效果, 可以借助轮廓系数选择较优方案.
  2. 根据聚类的形成过程, 把样本细分成为三类:
    1. 外周样本: 被其他样本聚集到某个聚类中, 但无法再引入新样本的样本
    2. 孤立样本: 聚类中的样本数低于所设定的下限, 则不称其为聚类, 称其为孤立样本.
    3. 核心样本: 除了外周样本和孤立样本以外的样本.
      DBSCAN算法相关API:
# 构建DBSCAN聚类模型
# eps: 圆的半径
# min_samples: 聚类样本数量的下限, 低于该数值则为孤立yang'b
model = sc.DBSCAN(eps=0.5, min_samples=3)
pre_dict_c = model.fit_predict(x)
# 获取核心样本的下标
model.core_sample_indices_

案例: 读取perf.txt, 实现聚类划分.

import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp
import sklearn.metrics as sm

x = np.loadtxt('perf.txt', delimiter=',')

# 基于轮廓系数优选eps超参数
eps, scores, models = np.linspace(0.3, 1.2, 10), [], []
for epsilon in eps:
    model = sc.DBSCAN(eps=epsilon, min_samples=5)
    model.fit(x)

    # 输出轮廓系数指标
    score = sm.silhouette_score(
        x, model.labels_,
        sample_size=len(x),
        metric='euclidean'
    )
    scores.append(score)
    models.append(model)

scores = np.array(scores)
best_index = scores.argmax()
print(eps[best_index])
print(scores[best_index])

# 获取到最优模型
model = models[best_index]
pre_dict_c = model.fit_predict(x)

# 获取核心样本掩码
core_mask = np.zeros(len(x), dtype=bool)
core_mask[model.core_sample_indices_] = True

# 获取孤立样本的掩码
offset_mask = model.labels_ == -1

# 外周样本的掩码
p_mask = ~(core_mask | offset_mask)

# 画图
mp.figure('Agglo Cluster', facecolor='lightgray')
mp.title('Agglo Cluster', fontsize=14)
mp.xlabel('x', fontsize=12)
mp.ylabel('y', fontsize=13)
mp.tick_params(labelsize=10)
labels = model.labels_
mp.scatter(x[core_mask][:, 0],
           x[core_mask][:, 1],
           c=labels[core_mask], 
           cmap='brg',
           s=80, label='core')
mp.scatter(x[p_mask][:, 0],
           x[p_mask][:, 1],
           c=labels[p_mask],
           cmap='brg',
           alpha=0.5,
           label='p', s=80)
mp.scatter(
    x[offset_mask][:, 0],
    x[offset_mask][:, 1],
    c='gold', alpha=0.5,
    label='offset', s=80
           )
mp.legend()
mp.show()

推荐引擎

推荐引擎意在把最需要的推荐给用户.

在不同的机器学习场景中通常需要分析相似的样本, 而统计相似样本的方式可以基于欧氏距离分数, 也可以基于皮氏距离分数.

简单推荐引擎的过程:

  1. 当A登录后, 系统检索A看过(评过分)的电影, 发现A喜欢什么电影.
  2. 数据库中有哪些人与A的习惯相似. 找到相似用户.
  3. 检索相似用户看过的电影, 寻求评分较高的推荐给A.
    欧氏距离分数
    欧 式 距 离 分 数 = 1 1 + 欧 氏 距 离 欧式距离分数 = \frac{1}{1+欧氏距离} =1+1
    计算所得欧氏距离分数区间处于(0, 1], 越趋向于0, 样本件的距离越远, 样本越不相似. 趋向于1, 代表越相似.

为了更方便的找到相似用户, 需要构建样本之间的欧式距离分数矩阵.

案例: 分析ratings.json

import json
import numpy as np

with open('ratings.json', 'r') as f:
    ratings = json.loads(f.read())
# 所有用户
users = list(ratings.keys())
# scmat用于存储每个人之间的欧氏距离得分矩阵
scmat = []

for user1 in users:
    scrow = []
    for user2 in users:
        # movies存储两个用户共同看过的电影
        movies = set()
        for movie in ratings[user1]:
            if movie in ratings[user2]:
                movies.add(movie)
        if len(movies) == 0:
            score = 0   # 两人没有共同语言, 得分为0
        else:
            # 计算两人相似度得分
            # x, y保存两人同时看过的多部电影的评分
            x, y = [], []
            for movie in movies:
                x.append(ratings[user1][movie])
                y.append(ratings[user2][movie])
            x = np.array(x)
            y = np.array(y)
            score = 1 / (1 + np.sqrt((x - y)**2).sum())
        scrow.append(score)
    scmat.append(scrow)

users = np.array(users)
scmat = np.array(scmat)

for scrow in scmat:
    print(' '.join('{:.2f}'.format(score) for score in scrow))

皮尔逊相关系数

A = [2, 3, 4]   # A用户打分列表
B = [3, 3, 3]   # B用户打分列表
C = [3, 4, 5]   # C用户打分列表
np.corrcoef(A, B)
np.corrcoef(A, C)

皮尔逊相关系数 = 协方差 / 标准差之积

相关系数处于[-1, 1]区间, 接近于-1, 代表两组样本负相关; 接近于1, 代表两组正相关.

案例:

import json
import numpy as np

with open('ratings.json', 'r') as f:
    ratings = json.loads(f.read())
# 所有用户
users = list(ratings.keys())
# scmat用于存储每个人之间的欧氏距离得分矩阵
scmat = []

for user1 in users:
    scrow = []
    for user2 in users:
        # movies存储两个用户共同看过的电影
        movies = set()
        for movie in ratings[user1]:
            if movie in ratings[user2]:
                movies.add(movie)
        if len(movies) == 0:
            score = 0   # 两人没有共同语言, 得分为0
        else:
            # 计算两人相似度得分
            # x, y保存两人同时看过的多部电影的评分
            x, y = [], []
            for movie in movies:
                x.append(ratings[user1][movie])
                y.append(ratings[user2][movie])
            x = np.array(x)
            y = np.array(y)
            score = np.corrcoef(x, y)[0, 1]
        scrow.append(score)
    scmat.append(scrow)

users = np.array(users)
scmat = np.array(scmat)

# 按照相似度从高到低排序每个用户的相似用户
for i, user in enumerate(users):
    # 获取当前用户与所有人的相似度得分并排序
    sorted_indices = scmat[i].argsort()[::-1]
    # 不和自己比
    sorted_indices = sorted_indices[sorted_indices != i]
    # 与当前用户的所有相似用户及相似度得分
    similar_users = users[sorted_indices]
    similar_scores = scmat[i][sorted_indices]

    # 生成推荐清单
    # 1. 找到所有皮尔逊系数正相关的用户
    # 2. 遍历每个相似用户, 找到相似看过的当前用户没看过的电影
    # 3. 对于多个相似用户可能推荐同一部电影
    #       取它们对该电影评分的均值作为推荐程度
    positive_mask = similar_scores > 0
    similar_users = similar_users[positive_mask]
    similar_scores = similar_scores[positive_mask]
    # 存储对于当前用户所推荐的电影, 以及电影推荐度(对电影的评分)
    recomm_movies = {}
    for i, similar_user in enumerate(similar_users):
        for movie, score in ratings[similar_user].items():
            if movie not in ratings[user].keys():
                if movie not in recomm_movies:
                    recomm_movies[movie] = []
                else:
                    recomm_movies[movie].append(score)
    print(user)
    recomm_movies = sorted(recomm_movies.items(), key=lambda x: np.average(np.array(x[1])), reverse=True)
    print(recomm_movies)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值