空间co-location模式挖掘基于全连接Join-Base原理与实现
简单来说该文章就是将apriori算法应用到空间模式的挖掘,将事务篮子换为co-location模式,将事务等价为行实例和表实例。引入参与率和参与度来等价支持度。频繁项的挖掘和关联规则的生成还是遵循apriori算法的步骤和核心思想,即先验原理(频繁模式的子集一定是频繁的,非频繁模式的超集一定是不频繁的)。
基本理论知识
空间特征
空间特征(或称空间对象、属性),代表了空间中不同种类的事物。空间特征代表了空间中不同种类的事物的集合。记为F = {f1, f2, f3, …, fn}。把一个具体空间位置上的对象称为空间实例。将实例的集合称为实例集,记为 S = S1 U S2 U …Sn,其中Si(1<=i<=n)是对应空间特征fi的实例集合。
![](https://i-blog.csdnimg.cn/blog_migrate/c29e18a5f0433c9fc96f3b28f567b562.png)
邻近关系
空间邻近关系:描述了空间实例之间的空间关系。可以是拓扑、距离、混合关系。空间邻近关系需要满足自反性和对称性。
以距离关系为例,空间邻近关系R为欧式距离小于等于阈值d,表示为:
![](https://i-blog.csdnimg.cn/blog_migrate/4ee1f90ae45903c5a95e307eaf4b3c09.png)
团
分布图中一个完全联通子图就是一个团。如{A3,B3,C1,D1}就是一个团
![](https://i-blog.csdnimg.cn/blog_migrate/bc1c40c5c069235d0807fbe0b2907eea.png)
空间co-location模式
一组空间特征集合c,其中c⊆F。如图中{A,B,C}就是一个co-location模式。
行实例和表实例
行实例表示团包含了co-location模式c中的所有特征,并且它的子集不包含c中的所有特征。co-location模式c中的所有行实例集合为表实例。
co-location模式c的长度称为co-location模式的阶。如co-location{A,B,C}的阶为3。
如:
例如:假设{A3,C1,C3}都满足两两邻近,但是不是co-location{A,C}的行实例
co-location{A,B,C}的行实例为{A2,B4,C5}和{A3,B3,C1}。所以表实例为{{A2,B4,C5},{A3,B3,C1}}
参与率与参与度
简单来说就是数据挖掘里面的支持度,在空间数据挖掘中引入参与率
参与率表示为PR(c,fi),它是fi的实例在空间co-location模式c的所有实例中不重复出现的个数与fi总实例个数的比率。
![](https://i-blog.csdnimg.cn/blog_migrate/f7899a92a743a2ad6762a97abaf33b00.png)
参与度表示为PI(c),它是空间co-location模式c的所有空间特征的PR值中的最小值。
![](https://i-blog.csdnimg.cn/blog_migrate/0e86e642029e9a79359c34bd9ed43c8c.png)
min_prev是用户给定的最小参与度(最小频繁性)阈值,当PI©>=min_prev 时,称为co-location模式c是频繁的。
co-location规则
c1 => c2(p,cp)称为co-location规则,其中c1和c2是co-location模式,c1∩c2不等于空集,p是规则参与度,cp是规则的条件概率。
条件概率cp是从co-location模式c1推出co-location模式c2的可信度
![](https://i-blog.csdnimg.cn/blog_migrate/8fef02ed9660ff1deffe5b87bd85af53.png)
主要步骤
类似于关联规则挖掘,大多数co-location挖掘算法通常将挖掘任务分解为如下两个子任务:
- 频繁co-location产生:其目标是发现满足最小参与度阈值min_prev的所有co-location模式。
- co-location规则产生:其目标是从上一步发现的频繁co-location模式中提取所有高条件概率的规则。
全连接算法Join-Base:
- 候选co-location的生成:由频繁k阶模式,生成k+1阶候选模式,在判断是否频繁,过程类比apriori算法
- 表实例的生成:k阶模式c1和k阶模式c2连接得到k+1阶候选模式c3,则候选模式c3的表实例是由模式c1的表实例和模式c2的表实例按前k-1个特征相同进行链接,同时要求最后两个实例满足邻近关系R。
![](https://i-blog.csdnimg.cn/blog_migrate/97871498dcfeec25446616868098dcd4.png)
书中给出的算法步骤
![](https://i-blog.csdnimg.cn/blog_migrate/50873a4d9630ba162178a058d721aafa.png)
代码实现
我是基于python实现的,算法步骤与书中给出的步骤有一点出入
说明:
P是频繁项,C是候选项,T_cu是未判断是否满足参与率的表实例集合,T是满足参与率的表实例集合。
首先导入需要用到的包
import itertools
import copy
import math
import numpy as np
import matplotlib.pyplot as plt
准备好需要用到的数据
min_prev = 0.3 #最小参与率
min_conf = 0.3 #最小置信度
ET = ["A","B","C","D"]
E = [["A",1,[24,14]]
,["A",2,[64,44]]
,["A",3,[46,24]]
,["A",4,[63,7]]
,["B",1,[13,3]]
,["B",2,[19,45]]
,["B",3,[47.5,10.5]]
,["B",4,[62,52]]
,["B",5,[13,50]]
,["C",1,[39,11]]
,["C",2,[52,50]]
,["C",3,[40,36]]
,["D",1,[40,20]]
,["D",2,[6,10]]]
R = 16 #设最小邻近关系的距离为16
将数据做可视化,看一下数据的基本关系
#定义可视化函数,方便查看数据之间的关系
def drawData(E,R):
values=[x[2] for x in E]
x = np.array(values)[:,0]
y = np.array(values)[:,1]
n = [x[0]+str(x[1]) for x in E]
fig,ax=plt.subplots(figsize=(12, 7))
ax.scatter(x,y)
for i,txt in enumerate(n):
ax.annotate(txt,(x[i],y[i]))
for i in range(len(values)-1):
for j in range(i+1,len(values)):
if math.sqrt((values[j][0]-values[i][0])**2 + (values[j][1]-values[i][1])**2) < R:
ax.plot([values[i][0],values[j][0]],[values[i][1],values[j][1]])
执行一下,展示
drawData(E,R)
展示图像如下:
这是我自己参考书中图像构造的数据集,方便与书中结果比对
下面定义几个基本函数和类
获取空间实例E中每个实例出现的次数,方便后面求参与率
def get_count_ET(E,ET):
count = {}
for i in ET:
count[i] = 0
for j in E:
if j[0] == i:
count[i] += 1
return count
测试一下
get_count_ET(E,ET)
输出为:{‘A’: 4, ‘B’: 5, ‘C’: 3, ‘D’: 2}
判断两个实例之间是否相邻
```python
#判断两个实例之间是否相邻
def isNiber(instance1,instance2,R):
distance = ((instance1[2][0] - instance2[2][0]) ** 2 + (instance1[2][1] - instance2[2][1]) ** 2) ** 0.5
if distance <= R:
return 1
else:
return 0
计算该模式下各个实例的参与度
def get_canyudu(P,count_ET):
canyudu = 1 #设置一个最大参与率
for key in P.keys():
canyulv = P[key]/count_ET[key]
if canyulv < canyudu: #这里判断用于返回最下参与率
canyudu = canyulv
return canyudu
直接根据空间实例E和空间邻近关系R生成2阶表实例
def createT2(E,R):
T2 = []
E_len = len(E)
for i in range(E_len-1):
for j in range(i,E_len):
if E[i][0]!=E[j][0] and isNiber(E[i],E[j],R):
instance = []
instance.append(E[i][0]+','+str(E[i][1]))
instance.append(E[j][0]+','+str(E[j][1]))
T2.append(instance)
T_dic = Table_2_Tdic(T2)
return T_dic
将表实例如[A1,B2]转换为表实例类{ A,B : [A1,B2] }
def Table_2_Tdic(T):
table = {}
for l in T:
co = ""
row_instance = []
l_len = len(l)
for i in range(l_len):
if i != l_len-1:
co += str(l[i]).split(',')[0] + ','
else:
co += str(l[i]).split(',')[0]
row_instance.append(str(l[i]))
if str(co) not in table.keys():
table[str(co)] = [row_instance]
else:
table[str(co)].append(row_instance)
# print(table)
return table
由k-1阶满足参与率的表实例集生成k阶粗表实例集
def T_2_Tk(T,k):
T_list = []
keys = list(T.keys())
keys.sort()
keys_len = len(keys)
for i in range(keys_len-1):
if keys[i].split(',')[:-1] != keys[i+1].split(',')[:-1]:
continue
for j in range(i+1,keys_len):
if keys[j].split(',')[:-1] == keys[i].split(',')[:-1]:
for instance_i in T[keys[i]]:
for instance_j in T[keys[j]]:
if instance_i[:-1] == instance_j[:-1]:
tem = []
tem.extend(instance_i)
tem.append(instance_j[-1])
T_list.append(tem)
else:
break
Tk = T_list.copy()
for C_Tlist in T_list:
for c in itertools.combinations(C_Tlist, k-1):
c = list(c)
c_len = len(c)
co = ""
row_list = []
for i in range(c_len):
if i != c_len-1:
co += c[i].split(",")[0]+','
else:
co += c[i].split(",")[0]
row_list.append(c[i])
if co not in T.keys() or row_list not in T[co]:
Tk.remove(C_Tlist)
break
T_dic = Table_2_Tdic(Tk)
return T_dic
由k阶粗表实例集和k阶候选集以及最小参与率生成k阶频繁项集和满足参与率的表实例集
def Tk_2_Pk(T_dic, count_ET, min_prev):
Pk = []
T = {}
keys = list(T_dic.keys())
keys.sort()
for key in keys:
key_list = key.split(",")
p = {}
key_len = len(key_list)
for i in range(key_len):
p[key_list[i]] = len(set([wai[i] for wai in T_dic[key]]))
canyudu = get_canyudu(p, count_ET)
if canyudu >= min_prev:
T[key] = T_dic[key]
Pk.append(key_list)
return T, Pk
由k阶频繁模式P,生成k+1阶候选模式C
def P_2_Ck(P):
C = []
p_len = len(P)
for i in range(p_len):
for j in range(i+1,p_len):
if P[j][:-1] == P[i][:-1]:
temp = []
temp.extend(P[i])
temp.append(P[j][-1])
C.append(temp)
return C
整合运行一下
if __name__ == '__main__':
min_prev = 0.3 # 最小参与率
ET = ["A", "B", "C", "D"]
E = [["A", 1, [24, 14]]
, ["A", 2, [64, 44]]
, ["A", 3, [46, 24]]
, ["A", 4, [63, 7]]
, ["B", 1, [13, 3]]
, ["B", 2, [19, 45]]
, ["B", 3, [47.5, 10.5]]
, ["B", 4, [62, 52]]
, ["B", 5, [13, 50]]
, ["C", 1, [39, 11]]
, ["C", 2, [52, 50]]
, ["C", 3, [40, 36]]
, ["D", 1, [40, 20]]
, ["D", 2, [6, 10]]]
R = 16 # 设最小邻近关系的距离为16
# drawData(E, R)
count_ET = get_count_ET(E, ET)
k = 2
T_C = createT2(E, R)
C = list(T_C.keys())
C.sort()
print("C2")
print(C)
T, P = Tk_2_Pk(T_C, count_ET, min_prev)
print("T2")
for i in T.keys():
print(i, T[i])
print("P2")
print(P)
while (1):
k += 1
C = P_2_Ck(P)
if len(C) == 0:
break
print("C{}".format(k))
print(C)
T_C = T_2_Tk(T, k)
T, P = Tk_2_Pk(T_C, count_ET, min_prev)
if bool(T):
print("T{}".format(k))
for i in T:
print(i, T[i])
if bool(P):
print("P{}".format(k))
print(P)
运行结果:
注:我没有写生成co-location规则的函数,所以这里没有产生规则,产生规则只需要从频繁项集中取子集,然后到表实例集中查找出现的次数,最后求出其概率就可以了
以上就是基于全连接的co-location模式挖掘,希望对你有帮助。