Apriori算法(矩阵)

来源:互联网 发布:python一般用什么界面 编辑:程序博客网 时间:2024/06/06 06:29

陈老师Apriori算法整理(缺点:1.通用性不强,只解决3项集的问题未做推广2.算法程序为加上优化,封装、连接等操作3.置信度的计算不全,缺1->2 2->1等情况)

说明:支持度范围大于0小于1,因为分母是一样的,所以用支持度计数代表支持度

传统Apriori算法候选项集多(主要是二项集),且需要频繁扫描数据库。效率较低。现提出一种优化算法。通过一次扫描数据库生成上三角矩阵,通过此上三角矩阵直接生成频繁1项集、频繁2项集及候选3项集,避免了Apriori算法产生过多的候选2项集的问题,同时减少了频繁2项集自连接后进行剪枝的步骤;在第二次扫描数据库时,他只将数据库中对计算支持度产生作用且项数不小于3的项集形成链表,进而提高算法的执行效率。


具体步骤如下:

步骤一:扫描数据库,构造2项集的支持度矩阵M。

步骤二:根据最小支持度技术,遍历矩阵得到L1、L2与C3.

步骤一具体操作方法如下:在矩阵中,以集合I的项作为矩阵相应的行标和列标,矩阵中的某一元素Mij表示二项集{Ii,Ij}在事务数据库中出现的次数。扫描过程为:如果扫描到一条事务中包含有{Ii,Ij}二项集,则在矩阵中对应Mij位置的元素计数值加1,在扫描过程中依次对单项进行计数,将技术结果贴入主对角线对应的位置。

步骤二具体操作方法如下:读取矩阵M的主对角线数据并与支持度进行比较即可得到L1,遍历矩阵M的上三角数据并与支持度进行比较即可得到L2.从上到下逐行读取读取矩阵M的数据,首先找出第i行(i=1,2…,m)中不小于最小支持度计数的元素Mij;其次定位到第j行,如果Mij的值不小于最小支持度计数,那么寻找第j行中不小于最小支持度计数的元素Mij;最后再顺着第k列定位回到第i行,如果Mij的值也不小于最小支持度计数,那么则可以生成候选三项集{Ii,Ij,Ik}。根据上述步骤可知,只需扫描一次数据库就可以形成矩阵M,通过对矩阵遍历即可得到L1,L2和C3,避免了Apriori算法中产生大量候选2项集且不能剪枝的问题,也省略了L2自连接后的剪枝步骤。

然后根据以下两条性质确定最终的频繁3项集:

性质1:如果事务数据库中某事务的长度小于k,则由Lk-1生成Lk时,扫描该事务是对计算Ck中项集的计数不产生作用;

性质2:如果某项Ix属于I,但Ix不出现在Ck中,则在计算Lk时扫描Ix也是对计算候选项集的支持度不起作用。

根据以上两条性质,结合遍历矩阵找到的C3,寻找L3。

3.2举例说明

举例说明:最小支持度为2(>=2)

事务数据库D中的数据如下表所示:

ID

Product

1

L1

2

L2

3

L3

4

L4

5

L5

Trade_ID

Product_list(真正数据库中用商品的ID号也就是纯数字组成)

T001

L1,L2,L5

T002

L2,L4

T003

L2,L3

T004

L1,L2,L4

T005

L1,L3

T006

L2,L3

T007

L1,L3

T008

L1,L2,L3,L5

T009

L1,L2,L3

扫描数据库形成2项集支持度上三角矩阵M:

      

上三角矩阵M

扫描矩阵M并与最小支持度进行比较得L1,L2,C3

频繁1项集L1

项集

支持度计数

{L1}

6

{L2}

7

{L3}

6

{L4}

2

{L5}

2

频繁2项集L2

项集

支持度计数

{L1,L2}

4

{L1,L3}

4

{L1,L5}

2

{L2,L3}

4

{L2,L4}

2

{L2,L5}

2

生成候选3项集C3:步骤如下:首先找出第1行中不小于最小支持度计数的元素M12({L1,L2})=4>2(对应步骤二中的i=1,j=2);然后到第2行中找出不小于最小支持度计数的元素M23({L2,L3})=4>2(对应步骤二中的k=3);然后顺着第3列定位回第1行的元素M13({L1,L3})=4>2。则把{L1,L2,L3}放入候选3项集。然后依次对每一行进行上述操作,直至全部完成(严格按照步骤完成一行再进行下一行)。

最终生成候选3项集C3

项集

{L1,L2,L3}

{L1,L2,L5}

然后遍历数据库中所选商品种类大于等于3个的订单,确定候选3项集中的每一项的支持度并与最小支持度进行比较获得频繁3项集L3

频繁3项集L3

项集

支持度

{L1,L2,L3}

2

{L1,L2,L5}

2

最后计算每一项互推的可信度(置信度)

通过读取频繁3项集和频繁1、2项集的支持度进行计算置信度

L1=>L2,L3    2/6=33.3%

L2=>L1,L3    2/7=28.6%

L3=>L1,L3    2/6=33.3%

L1,L2=>L3   2/4=50%

L1,L3=>L2    2/4=50%

L2,L3=>L1    2/4=50%

根据最小置信度40%最终确定关联关系为: L1,L2=>L3.L1,L3=>L2.L2,L3=>L1

 

小结:1.支持度计数过于麻烦,可以使用连接,然后用count进行计数。这样这样更加优化。

            2.可以把下面的代码封装成函数进行运行

 

程序代码:

--------------------建表------------------------(1)产品名和产品名称对应表,产品ID用数字表示 CREATE TABLE PRODUCT_ID   ("P_ID" NUMBER, "PRODUCT" VARCHAR2(20 BYTE)   );(2)购物单号和所购物品ID对应表CREATE TABLE TRADE_LIST   ("TRADE_ID" NUMBER, "PRODUCT" NUMBER   );(3)候选3项集表 CREATE TABLE APRIORIC3   ("SET1" NUMBER, "SET2" NUMBER, "SET3" NUMBER, "SUPPORTCOUNT" NUMBER, "C_ID" NUMBER   );(4)频繁1项集表 CREATE TABLE APRIORISET1   ("SET1" NUMBER, "SUPPORTCOUNT" NUMBER   );(5)频繁2项集表  CREATE TABLE APRIORISET2    ("SET1" NUMBER, "SET2" NUMBER, "SUPPORTCOUNT" NUMBER   );(6)频繁3项集表  CREATE TABLE APRIORISET3    ("SET1" NUMBER, "SET2" NUMBER, "SET3" NUMBER, "SUPPORTCOUNT" NUMBER   );(7)置信度表 (共有4个位置,L1,L2=>L3则表中S4的位置为null. L1=>L2,L3则表中S2的位置为null。OP代表推到符号=>)CREATE TABLE CONFIDENCE    ("S1" VARCHAR2(10 BYTE), "S2" VARCHAR2(10 BYTE), "OP" VARCHAR2(10 BYTE), "S3" VARCHAR2(10 BYTE), "S4" VARCHAR2(10 BYTE), "CONFIDENCELEVEL" NUMBER   );


 

--------------------------(1)-------------------------------------生成频繁1项集频繁2项集和候选3项集----------------------在建表和插入数据之后更改代码中的支持度直接运行即可----------------------DECLARE  SUPPORT NUMBER;--支持度  TYPE T_NUM_TAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;  TYPE T_NUM_VAR IS TABLE OF T_NUM_TAB INDEX BY BINARY_INTEGER;  M T_NUM_VAR;--二维数组(矩阵)  TRADE_NO NUMBER;--每一次的交易号  X NUMBER;  Y NUMBER;  P_NO NUMBER;--产品的总数量  NUM NUMBER;--表中的辅助变量  CURSOR TRADE_CURSOR IS  SELECT DISTINCT(TRADE_ID) FROM TRADE_LIST ORDER BY TRADE_ID;  CURSOR X_CURSOR IS SELECT PRODUCT FROM TRADE_LIST WHERE TRADE_ID=TRADE_NO ORDER BY PRODUCT;   CURSOR Y_CURSOR IS SELECT PRODUCT FROM TRADE_LIST WHERE TRADE_ID=TRADE_NO ORDER BY PRODUCT;BEGIN  SUPPORT:=7;  NUM:=1;  /*矩阵初始化为全0*/  SELECT COUNT(P_ID) INTO P_NO FROM PRODUCT_ID;  FOR I IN 1..P_NO LOOP    FOR J IN 1..P_NO LOOP     M(I)(J):=0;    END LOOP;   END LOOP;   /*初始化矩阵结束*/  OPEN TRADE_CURSOR;  LOOP    FETCH TRADE_CURSOR INTO TRADE_NO;    EXIT WHEN TRADE_CURSOR%NOTFOUND;   /* DBMS_OUTPUT.PUT_LINE('Trade Number:'||TRADE_NO);    SELECT COUNT(PRODUCT) INTO LIST_COUNT FROM TRADE_LIST WHERE TRADE_ID=TRADE_NO;    DBMS_OUTPUT.PUT_LINE('COUNT:'||LIST_COUNT);    */    /*X的游标开始*/      OPEN X_CURSOR;       LOOP       FETCH X_CURSOR INTO X;         EXIT WHEN X_CURSOR%NOTFOUND;       --  DBMS_OUTPUT.PUT_LINE('TRADE_NO:'||TRADE_NO||'PRODUCT:'||X);         /*Y的游标开始*/            OPEN Y_CURSOR;            LOOP            FETCH Y_CURSOR INTO Y;            EXIT WHEN Y_CURSOR%NOTFOUND;            IF X<=Y THEN M(X)(Y):=M(X)(Y)+1;                        END IF;            END LOOP;            CLOSE Y_CURSOR;      /*Y的游标结束*/       END LOOP;       CLOSE X_CURSOR;       /*X的游标结束*/  END LOOP;  CLOSE TRADE_CURSOR;  /*循环输出开始*/  /*    FOR I IN 1..M.COUNT LOOP    FOR J IN 1..M(I).COUNT LOOP     DBMS_OUTPUT.PUT_LINE(M(I)(J));    END LOOP;   END LOOP;   */  /*循环输出结束*/  /*生成频繁1项集*/  DELETE FROM AprioriSet1;   FOR I IN 1..P_NO LOOP   IF M(I)(I)>=SUPPORT THEN   INSERT INTO AprioriSet1 VALUES(I,M(I)(I));   END IF;   END LOOP;     /*生成频繁1项集结束*/   /*生成频繁2项集*/  DELETE FROM AprioriSet2;   FOR I IN 1..P_NO LOOP   FOR J IN I+1..P_NO LOOP   IF M(I)(J)>=SUPPORT THEN   INSERT INTO AprioriSet2 VALUES(I,J,M(I)(J));   END IF;   END LOOP;   END LOOP;      /*生成频繁2项集结束*/   /*生成候选3项集*/   DELETE FROM APRIORIC3;   FOR I IN 1..P_NO LOOP   FOR J IN I+1..P_NO LOOP    IF M(I)(J)>=SUPPORT THEN    FOR K IN J+1..P_NO LOOP    IF M(J)(K)>=SUPPORT AND M(I)(K)>=SUPPORT  THEN    INSERT INTO APRIORIC3(SET1,SET2,SET3,SUPPORTCOUNT,C_ID) VALUES(I,J,K,0,NUM);    NUM:=NUM+1;    END IF;    END LOOP;    END IF;    END LOOP;    END LOOP;   /*生成候选3项集结束*/END;


 

----------------------------(2)--------------------------------------------------------由候选3项集生成频繁3项集---------------------------------------------修改支持度即可-----------------------------------DECLARE T_ID NUMBER;----选择购物种类大于等于3的交易号P_ID NUMBER;A1 NUMBER;--A1,A2,A3复制0,1,用于逻辑处理判断A2 NUMBER;A3 NUMBER;SUPPORT NUMBER;--支持度CURSOR T_CURSOR IS SELECT DISTINCT(TRADE_ID) FROM TRADE_LIST GROUP BY TRADE_ID HAVING COUNT(PRODUCT)>=3;CURSOR P_CURSOR  IS SELECT PRODUCT FROM TRADE_LIST WHERE TRADE_ID=T_ID;CURSOR C_CURSOR IS SELECT * FROM APRIORIC3;C3 C_CURSOR%ROWTYPE;--利用游标从候选3项集中选出来的一行BEGIN    SUPPORT:=7;    A1:=0;    A2:=0;    A3:=0;    UPDATE APRIORIC3 SET SUPPORTCOUNT=0;    OPEN C_CURSOR;    LOOP    FETCH C_CURSOR INTO C3;    EXIT WHEN C_CURSOR%NOTFOUND;        OPEN T_CURSOR;    LOOP    FETCH T_CURSOR INTO T_ID;     EXIT WHEN T_CURSOR%NOTFOUND;        OPEN P_CURSOR;        LOOP        FETCH P_CURSOR INTO P_ID;        EXIT WHEN P_CURSOR%NOTFOUND;       /*对每一条大于3项的记录都对候选3项集中的所有数据进行检索*/             DBMS_OUTPUT.PUT_LINE('L'||P_ID);             IF P_ID=C3.SET1 THEN A1:=1;  DBMS_OUTPUT.PUT_LINE('SET1-L'||P_ID); END IF;             IF P_ID=C3.SET2 THEN A2:=1;  DBMS_OUTPUT.PUT_LINE('SET2-L'||P_ID);END IF;             IF P_ID=C3.SET3 THEN A3:=1;  DBMS_OUTPUT.PUT_LINE('SET3-L'||P_ID);END IF;             IF A1=1 AND A2=1 AND A3=1 THEN          UPDATE APRIORIC3 SET SUPPORTCOUNT=SUPPORTCOUNT+1 WHERE C_ID=C3.C_ID;         A1:=0;         A2:=0;         A3:=0;         DBMS_OUTPUT.PUT_LINE('UPDATE');                  END IF;                    END LOOP;        CLOSE P_CURSOR;        A1:=0;        A2:=0;        A3:=0;     END LOOP;     CLOSE T_CURSOR;     END LOOP;     CLOSE C_CURSOR;     /*生成频繁3项集*/     DELETE FROM AprioriSet3;    OPEN C_CURSOR;    LOOP    FETCH C_CURSOR INTO C3;    EXIT WHEN C_CURSOR%NOTFOUND;    IF C3.SUPPORTCOUNT>=SUPPORT THEN    INSERT INTO APRIORISET3 VALUES(C3.SET1,C3.SET2,C3.SET3,C3.SUPPORTCOUNT);    END IF;    END LOOP;    CLOSE C_CURSOR;    /*生成频繁3项集结束*/END;
---------------------------------------------------------------------------------(3)--------------------------------------------------置信度计算-------------------------DECLARE  NUM1 NUMBER;  NUM2 NUMBER;  NUM3 NUMBER;  LEVEL1 NUMBER;  LEVEL2 NUMBER;  LEVEL3 NUMBER;  CURSOR CONFIDENCE_CURSOR IS SELECT * FROM APRIORISET3;  L3 CONFIDENCE_CURSOR%ROWTYPE;  CONFIDENCE_LEVEL NUMBER; --给定置信度BEGIN  DELETE  FROM CONFIDENCE;  CONFIDENCE_LEVEL:=0.8;  OPEN CONFIDENCE_CURSOR;  LOOP    FETCH CONFIDENCE_CURSOR INTO L3;    EXIT WHEN CONFIDENCE_CURSOR%NOTFOUND;    /*一项推二项开始L1=>L2,L3*/        SELECT SUPPORTCOUNT INTO NUM1 FROM APRIORISET1 WHERE SET1=L3.SET1;        SELECT SUPPORTCOUNT INTO NUM2 FROM APRIORISET1 WHERE SET1=L3.SET2;        SELECT SUPPORTCOUNT INTO NUM3 FROM APRIORISET1 WHERE SET1=L3.SET3;        LEVEL1:=L3.SUPPORTCOUNT/NUM1;        LEVEL2:=L3.SUPPORTCOUNT/NUM2;        LEVEL3:=L3.SUPPORTCOUNT/NUM3;        IF LEVEL1>=CONFIDENCE_LEVEL THEN        INSERT INTO CONFIDENCE(S1,S2,OP,S3,S4,CONFIDENCELEVEL) VALUES('L'||L3.SET1,'','=>','L'||L3.SET2,'L'||L3.SET3,LEVEL1);        END IF;         IF LEVEL2>=CONFIDENCE_LEVEL THEN        INSERT INTO CONFIDENCE(S1,S2,OP,S3,S4,CONFIDENCELEVEL) VALUES('L'||L3.SET2,'','=>','L'||L3.SET1,'L'||L3.SET3,LEVEL2);         END IF;         IF LEVEL3>=CONFIDENCE_LEVEL THEN        INSERT INTO CONFIDENCE(S1,S2,OP,S3,S4,CONFIDENCELEVEL) VALUES('L'||L3.SET3,'','=>','L'||L3.SET1,'L'||L3.SET2,LEVEL3);         END IF;         /*一项推二项结束L1=>L2,L3*/         /*二项推一项开始L1,L2=>L3*/        SELECT SUPPORTCOUNT INTO NUM1 FROM APRIORISET2 WHERE SET1=L3.SET1 AND SET2=L3.SET2;        SELECT SUPPORTCOUNT INTO NUM2 FROM APRIORISET2 WHERE SET1=L3.SET1 AND SET2=L3.SET3;        SELECT SUPPORTCOUNT INTO NUM3 FROM APRIORISET2 WHERE SET1=L3.SET2 AND SET2=L3.SET3;        LEVEL1:=L3.SUPPORTCOUNT/NUM1;        LEVEL2:=L3.SUPPORTCOUNT/NUM2;        LEVEL3:=L3.SUPPORTCOUNT/NUM3;        IF LEVEL1>=CONFIDENCE_LEVEL THEN        INSERT INTO CONFIDENCE(S1,S2,OP,S3,S4,CONFIDENCELEVEL) VALUES('L'||L3.SET1,'L'||L3.SET2,'=>','L'||L3.SET3,'',LEVEL1);        END IF;         IF LEVEL2>=CONFIDENCE_LEVEL THEN        INSERT INTO CONFIDENCE(S1,S2,OP,S3,S4,CONFIDENCELEVEL) VALUES('L'||L3.SET1,'L'||L3.SET3,'=>','L'||L3.SET2,'',LEVEL2);         END IF;         IF LEVEL3>=CONFIDENCE_LEVEL THEN        INSERT INTO CONFIDENCE(S1,S2,OP,S3,S4,CONFIDENCELEVEL) VALUES('L'||L3.SET2,'L'||L3.SET3,'=>','L'||L3.SET1,'',LEVEL3);         END IF;         /*二项推一项结束L1,L2=>L3*/  END LOOP;  CLOSE CONFIDENCE_CURSOR;END;



 

0 0