# III.无监督学习编码实现(聚类和关联)
# 1.数据集的设定
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as ss
# 引入sklearn包中的datasets接口模拟一些点
from sklearn.datasets import make_circles,make_moons,make_blobs
n_samples = 1000
circles = make_circles(n_samples=n_samples,factor=0.5,noise=0.05)
moons = make_moons(n_samples=n_samples,noise=0.05)
blobs = make_blobs(n_samples=n_samples,random_state=8,center_box=(-1,1),cluster_std=0.1)
random_data = np.random.rand(n_samples,2),None # 二维是为了方便可视化
# random_data2 = np.random.randint(10,size=n_samples)
# print(type(random_data2))
# print(random_data2)
colors = "bgrcmyk"
data = [circles,moons,blobs,random_data]
f = plt.figure()
# 2.模型建立,引入一个列表,一会儿装模型用
models = [("None",None)]
# Clustering-i.基于切割的K-means
# 原则:所有的类都有一个中心,属于一个类的点到它的中心的距离比到其他类中心点的距离更近
# 算法:
# A.从n个样本中随机选取K个作为初始化的质心,K的个数为分类的数
# B.对每个样本测量其到各个质心的距离,并把它归到最近的质心的类中
# C.重新计算已经得到的各类的质心
# D.迭代B和C过程,直到新的质心不变或小于指定的阈值
# 注意点:
# 1.初始质心的位置可能会影响最终聚类的结果(多试几次找出稳定点)
# 2.离群点会影响整体的聚类效果(将质心换成取重点的K-Medoids算法)
# 3.必须要指定K(借助其他衡量因子确定K的个数)
from sklearn.cluster import KMeans
models.append(("K-means",KMeans(n_clusters=3)))
# Clustering-ii.基于密度的DBSCAN(找到密度相连的最大集合)
# 原则:一定区域内,密度到达一定程度才叫一个类,否则叫离群点
# 概念:
# 1.E邻域:给定对象半径为E内的区域为该对象的E邻域
# 2.核心对象:如果给定对象E邻域内的样本点个数大于等于MinPts,则称该对象为核心对象
# 3.直接密度可达:对于样本集合D,如果样本点q在p的E邻域内,且p为核心对象,那么对象q从对象p直接密度可达
# 4.密度可达:对于样本集合D,给定一串样本点p1,p2…pn,p=p1,q=pn,假设对象pi从pi-1直接密度可达,则对象q从对象p密度可达
# 5.密度相连:存在样本集合D中的一点o,如果对象o到对象p和对象q都是密度可达,那么p和q密度相连
# 注意点:
# 优:对离群点不敏感
# 劣:需要KD-Tree等数据结构的辅助,且参数问题较难解决
from sklearn.cluster import DBSCAN
# min_samples:最小分类数,eps:E邻域
models.append(("DBSCAN",DBSCAN(min_samples=3,eps=0.2)))
# Clustering-iii.基于层次的聚类算法
# 原则:依次聚类最近的集合
# 距离衡量的方法:最短距离,最长距离,平均距离,Ward
# 注意点:
# 优:聚类灵活
# 劣:计算复杂度比较高,离群点影响比较大
from sklearn.cluster import AgglomerativeClustering
# n_cluster:分类数,linkage:距离计算方式
models.append(("AgglomerativeClustering",AgglomerativeClustering(n_clusters=3,linkage="ward")))
# Clustering-iv.基于图的Split算法
# 原则:与基本层次聚类思路相反,为从顶至下
# 注意点:
# 优:图建立方式及分裂方式灵活
# 3.聚类结果对比,画图
# enumerate()函数用于将一个可遍历的数据对象(如列表,元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在for循环当中
# 遍历下标inx,实体部分clt
# 以models中的第1项为例inx为0,clt为("None",None)
for inx,clt in enumerate(models):
# clt分为2部分,可以用这个形式指定clt名字和clt实体
# clt_name对应"None",clt_entity对应"None"的实体部分
clt_name,clt_entity = clt
# 同样的,遍历data的下标i和实体dataset
for i,dataset in enumerate(data):
# X对应数组,Y对应标注
X,Y = dataset
# 如果data实体是空的话,分类结果为0,分类的项目与数组长度一致
if not clt_entity:
clt_res = [0 for item in range(len(X))]
# 如果data实体不为空的,分类结果为fit结果
else:
clt_entity.fit(X)
clt_res = clt_entity.labels_.astype(np.int)
f.add_subplot(len(models),len(data),inx*len(data)+i+1)
plt.title(clt_name)
for p in range(len(X)):
plt.scatter(X[p,0],X[p,1],color=colors[clt_res[p]])
plt.show()
# Association-i.关联规则(反映一个事物与其他事物之间的相互依存性和关联性,目的:找到频繁项集)
# 1.概念:
# 1)项目:一个字段,对交易来说一般指一次交易中的一个物品,如尿布
# 2)事物:一个集合,对交易来说一般指发生的所有项目集合,如{啤酒,尿布}
# 3)项集:一个集合,包含若干项目的集合(一次事务中的)
# 4)频繁项集:某个项集的支持度大于设定阈值,则称这个项集为频繁项集
# 5)支持度:项集{X,Y}在总项集中出现的概率(Support)
# 6)置信度:在先决条件X发生的条件下,由关联规则{X->Y}推出Y的概率(Confidence),条件概率的概念
# 7)提升度:表示含有X的条件下同时含有Y的概率,与无论含不含X含有Y的概率之比,(Confidence({X->Y})/Support({Y}))
# * 频繁项集的组合可能是频繁的也可能是非频繁的,非频繁项集的组合一定是非频繁的
# 2.算法:Apriori:用低阶频繁项集和设定的阈值找到高阶频繁项集
# A.指定支持度的阈值
# B.判断项集的支持度与阈值的大小关系
#
# Association-i.序列规则(在关联规则的前提下将时间因素考虑进来,剔除关联规则中时间点靠后的项对时间点靠前的项的支持)
# 1.应用:预测用户在本次购物之后,下次购物会购买其他什么用作搭配
# 2.算法:Apriori-All
# A.Forward:Apriori
# B.Backward:去掉时间序列之后的项对之前的项的支持
from itertools import combinations
def comb(lst):
ret=[]
for i in range(1,len(lst)+1):
ret+=list(combinations(lst,i))
return ret
class AprLayer(object):
d=dict()
def __init__(self):
self.d=dict()
class AprNode(object):
def __init__(self,node):
self.s=set(node)
self.size=len(self.s)
self.lnk_nodes=dict()
self.num=0
def __hash__(self):
return hash("__".join(sorted([str(itm) for itm in list(self.s)])))
def __eq__(self, other):
if "__".join(sorted([str(itm) for itm in list(self.s)]))=="__".join(sorted([str(itm) for itm in list(other.s)])):
return True
return False
def isSubnode(self,node):
return self.s.issubset(node.s)
def incNum(self,num=1):
self.num+=num
def addLnk(self,node):
self.lnk_nodes[node]=node.s
class AprBlk():
def __init__(self,data):
cnt=0
self.apr_layers = dict()
self.data_num=len(data)
for datum in data:
cnt+=1
datum=comb(datum)
nodes=[AprNode(da) for da in datum]
for node in nodes:
if not node.size in self.apr_layers:
self.apr_layers[node.size]=AprLayer()
if not node in self.apr_layers[node.size].d:
self.apr_layers[node.size].d[node]=node
self.apr_layers[node.size].d[node].incNum()
for node in nodes:
if node.size==1:
continue
for sn in node.s:
sub_n=AprNode(node.s-set([sn]))
self.apr_layers[node.size-1].d[sub_n].addLnk(node)
def getFreqItems(self,thd=1,hd=1):
freq_items=[]
for layer in self.apr_layers:
for node in self.apr_layers[layer].d:
if self.apr_layers[layer].d[node].num