对apriori关联关系算法研究了一段时间,网上能搜到的例子,大部分是python写的,数据集长得像下面这样:

[[I1,I2,I5],[I2,I4],[I2,I3],[I1,I2,I4],[I1,I3],[I2,I3],[I1,I3],[I1,I2,I3,I5],[I1,I2,I3]]

而实际的交易数据,一般存储到关系型数据库中,数据是按下面的样子保存:

TRAN_SEQ_NO,ITEM
1,I1
1,I2
1,I5
2,I2
2,I4
.
.8,I5
9,I1
9,I2
9,I3

而且python的程序,写了好多循环,效率不高。

根据小票数据在数据库中存储的特点,并且apriori算法也不是特别复杂,因此想用plsql实现一下。

plsql实现的aprioir算法,对原算法做了裁剪,只计算2项集和两个商品之间的关联关系,3项集以上的忽略不计。

表结构创建

1.小票表(交易事物表)

create table CMX_APRIORI_TRANSACTION
(
  tran_seq_no NUMBER(20), --交易号
  item        VARCHAR2(25)  --商品编码
)

2.频繁项集C1

create table CMX_APRIORI_L1
(
  item    VARCHAR2(25),  --商品编码
  support NUMBER(9,6),          --支持度
  cnt     NUMBER(8)              --交易次数
)

2.关联关系L2(结果表)

create table CMX_APRIORI_L2
(
  item_a   VARCHAR2(25),    --前件商品编码
  item_b   VARCHAR2(25),    --后件商品编码
  cnt      NUMBER(8),                 --交易次数
  support  NUMBER(9,6),             --支持度
  conf_a_b NUMBER(9,6),  --置信度
  lift_a_b NUMBER(9,6)      --提升度
)

说明:

小票表插入的数据,必须提前进行处理。同一张小票商品要去重。

完整plsql代码:

CREATE OR REPLACE PACKAGE CMX_APRIORI_SQL IS

  /*-----------------------------------------------------------------------
* PROCEDURE NAME : CMX_APRIORI_SQL
* COMMENTS : 商品关联关系计算
* CODED BY : ONELANG 2019-1-27
* CHANGED HISTORY :
-----------------------------------------------------------------------*/
FUNCTION TEST(O_ERROR_MESSAGE IN OUT VARCHAR2) RETURN BOOLEAN;
END CMX_APRIORI_SQL;
/
CREATE OR REPLACE PACKAGE BODY CMX_APRIORI_SQL IS /*-----------------------------------------------------------------------
* PROCEDURE NAME : INIT_TEST_DATA
* COMMENTS : 初始化测试数据
* CODED BY : ONELANG 2019-1-27
* CHANGED HISTORY :
-----------------------------------------------------------------------*/ FUNCTION INIT_TEST_DATA(O_ERROR_MESSAGE IN OUT VARCHAR2) RETURN BOOLEAN IS
L_PROGRAM VARCHAR2(100) := 'CMX_APRIORI_SQL.INIT_TEST_DATA';
BEGIN EXECUTE IMMEDIATE 'TRUNCATE TABLE CMX_APRIORI_TRANSACTION'; INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (1,'I1');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (1,'I2');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (1,'I5');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (2,'I2');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (2,'I4');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (3,'I2');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (3,'I3');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (4,'I1');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (4,'I2');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (4,'I4');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (5,'I1');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (5,'I3');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (6,'I2');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (6,'I3');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (7,'I1');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (7,'I3');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (8,'I1');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (8,'I2');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (8,'I3');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (8,'I5');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (9,'I1');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (9,'I2');
INSERT INTO CMX_APRIORI_TRANSACTION (TRAN_SEQ_NO,ITEM)
VALUES (9,'I3');
COMMIT;
RETURN TRUE; EXCEPTION
WHEN OTHERS THEN
O_ERROR_MESSAGE := SQLERRM||TO_CHAR(SQLCODE);
RETURN FALSE;
END; /*-----------------------------------------------------------------------
* PROCEDURE NAME : GET_TEST_L1
* COMMENTS : 计算频繁项集L1
* CODED BY : ONELANG 2019-1-27
* CHANGED HISTORY :
-----------------------------------------------------------------------*/ FUNCTION GET_TEST_L1(O_ERROR_MESSAGE IN OUT VARCHAR2,I_SUPPORT IN NUMBER) RETURN BOOLEAN IS
L_PROGRAM VARCHAR2(100) := 'CMX_APRIORI_SQL.GET_TEST_L1';
L_TOTAL NUMBER(8);
BEGIN EXECUTE IMMEDIATE 'TRUNCATE TABLE CMX_APRIORI_L1'; SELECT COUNT(DISTINCT TRAN_SEQ_NO) INTO L_TOTAL
FROM CMX_APRIORI_TRANSACTION ; INSERT INTO CMX_APRIORI_L1
SELECT ITEM,ROUND(COUNT(1) / L_TOTAL,6) SUPPORT,COUNT(1) CNT
FROM CMX_APRIORI_TRANSACTION A
GROUP BY ITEM
HAVING COUNT(1) / L_TOTAL >= I_SUPPORT ; COMMIT; RETURN TRUE; EXCEPTION
WHEN OTHERS THEN
O_ERROR_MESSAGE := SQLERRM||TO_CHAR(SQLCODE); RETURN FALSE;
END; /*-----------------------------------------------------------------------
* PROCEDURE NAME : GET_L2
* COMMENTS : 获取关联关系L2
* CODED BY :
* CHANGED HISTORY :
-----------------------------------------------------------------------*/
FUNCTION GET_TEST_L2(O_ERROR_MESSAGE IN OUT VARCHAR2,I_SUPPORT IN NUMBER) RETURN BOOLEAN IS
L_PROGRAM VARCHAR2(100) := 'CMX_APRIORI_SQL.GET_L2';
L_TOTAL NUMBER(8);
BEGIN EXECUTE IMMEDIATE 'TRUNCATE TABLE CMX_APRIORI_L2'; SELECT COUNT(DISTINCT TRAN_SEQ_NO) INTO L_TOTAL
FROM CMX_APRIORI_TRANSACTION ; --2项集支持度
INSERT INTO CMX_APRIORI_L2(ITEM_A,ITEM_B,CNT,SUPPORT)
SELECT ITEM_A,ITEM_B,COUNT(DISTINCT TRAN_SEQ_NO) CNT, ROUND(COUNT(DISTINCT TRAN_SEQ_NO) / L_TOTAL,6) SUPPORT
FROM (SELECT A.TRAN_SEQ_NO,
A.ITEM ITEM_A,
B.ITEM ITEM_B
FROM CMX_APRIORI_TRANSACTION A,
CMX_APRIORI_TRANSACTION B
WHERE A.ITEM IN (SELECT ITEM FROM CMX_APRIORI_L1)
AND B.ITEM IN (SELECT ITEM FROM CMX_APRIORI_L1)
AND A.TRAN_SEQ_NO = B.TRAN_SEQ_NO
AND A.ITEM > B.ITEM
)
GROUP BY ITEM_A,ITEM_B
HAVING COUNT(DISTINCT TRAN_SEQ_NO) / L_TOTAL >= I_SUPPORT; --置信度
UPDATE CMX_APRIORI_L2 L2
SET CONF_A_B = (SELECT L2.SUPPORT / L1.SUPPORT FROM CMX_APRIORI_L1 L1 WHERE L2.ITEM_A = L1.ITEM); --提升度
UPDATE CMX_APRIORI_L2 L2
SET LIFT_A_B = (SELECT L2.CONF_A_B / L1.SUPPORT FROM CMX_APRIORI_L1 L1 WHERE L2.ITEM_B = L1.ITEM); COMMIT; RETURN TRUE; EXCEPTION
WHEN OTHERS THEN
O_ERROR_MESSAGE := SQLERRM||TO_CHAR(SQLCODE); RETURN FALSE;
END; FUNCTION TEST(O_ERROR_MESSAGE IN OUT VARCHAR2) RETURN BOOLEAN IS
L_PROGRAM VARCHAR2(100) := 'CMX_APRIORI_SQL.TEST';
L_MIN_SUPP NUMBER(9,5);
BEGIN L_MIN_SUPP := 0.1; IF INIT_TEST_DATA(O_ERROR_MESSAGE) = FALSE THEN
RETURN FALSE;
END IF; IF GET_TEST_L1(O_ERROR_MESSAGE,L_MIN_SUPP) = FALSE THEN
RETURN FALSE;
END IF; IF GET_TEST_L2(O_ERROR_MESSAGE,L_MIN_SUPP) = FALSE THEN
RETURN FALSE;
END IF; RETURN TRUE; EXCEPTION
WHEN OTHERS THEN
O_ERROR_MESSAGE := SQLERRM||TO_CHAR(SQLCODE);
RETURN FALSE;
END; END CMX_APRIORI_SQL;
/

运行:

declare
result boolean;
begin
-- Call the function
result := cmx_apriori_sql.test(o_error_message => :o_error_message);
-- Convert false/true/null to 0/1/null
:result := sys.diutil.bool_to_int(result);
end;

运行结果:

select * from cmx_apriori_l2

 ITEM_A  ITEM_B    CNT    SUPPORT    CONF_A_B    LIFT_A_B
1 I2 I1 4 0.444444 0.571428 0.857142
2 I4 I2 2 0.222222 1.000000 1.285714
3 I5 I3 1 0.111111 0.500000 0.750000
4 I3 I2 4 0.444444 0.666666 0.857142
5 I5 I1 2 0.222222 1.000000 1.499999
6 I3 I1 4 0.444444 0.666666 0.999999
7 I4 I1 1 0.111111 0.500000 0.750000
8 I5 I2 2 0.222222 1.000000 1.285714

用一家门店,一年的销售数据计算一下就会发现,尿布->啤酒根本没有关联关系。意外+惊喜。

oracle plsql 实现apriori算法的更多相关文章

  1. Oracle/PLSQL: ORA-06550

    参考: http://blog.csdn.net/haiross/article/details/20612135 Oracle/PLSQL: ORA-06550 Learn the cause an ...

  2. Apriori算法的原理与python 实现。

    前言:这是一个老故事, 但每次看总是能从中想到点什么.在一家超市里,有一个有趣的现象:尿布和啤酒赫然摆在一起出售.但是这个奇怪的举措却使尿布和啤酒的销量双双增加了.这不是一个笑话,而是发生在美国沃尔玛 ...

  3. #研发解决方案#基于Apriori算法的Nginx+Lua+ELK异常流量拦截方案

    郑昀 基于杨海波的设计文档 创建于2015/8/13 最后更新于2015/8/25 关键词:异常流量.rate limiting.Nginx.Apriori.频繁项集.先验算法.Lua.ELK 本文档 ...

  4. 数据挖掘算法(四)Apriori算法

    参考文献: 关联分析之Apriori算法

  5. 机器学习实战 - 读书笔记(11) - 使用Apriori算法进行关联分析

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第11章 - 使用Apriori算法进行关联分析. 基本概念 关联分析(associat ...

  6. 关联规则挖掘之apriori算法

    前言: 众所周知,关联规则挖掘是数据挖掘中重要的一部分,如著名的啤酒和尿布的问题.今天要学习的是经典的关联规则挖掘算法--Apriori算法 一.算法的基本原理 由k项频繁集去导出k+1项频繁集. 二 ...

  7. 利用Apriori算法对交通路况的研究

    首先简单描述一下Apriori算法:Apriori算法分为频繁项集的产生和规则的产生. Apriori算法频繁项集的产生: 令ck为候选k-项集的集合,而Fk为频繁k-项集的集合. 1.首先通过单遍扫 ...

  8. Apriori算法例子

    1 Apriori介绍 Apriori算法使用频繁项集的先验知识,使用一种称作逐层搜索的迭代方法,k项集用于探索(k+1)项集.首先,通过扫描事务(交易)记录,找出所有的频繁1项集,该集合记做L1,然 ...

  9. Apriori算法实例----Weka,R, Using Weka in my javacode

    学习数据挖掘工具中,下面使用4种工具来对同一个数据集进行研究. 数据描述:下面这些数据是15个同学选修课程情况,在课程大纲中共有10门课程供学生选择,下面给出具体的选课情况,以ARFF数据文件保存,名 ...

随机推荐

  1. Angular 修改路由策略,改为使用hash路由,即带#号URL

    修改app.module.ts如下  

  2. LInux因为缺失网关出现Name or service not known的解决方法

    笔者使用的VMware和CentOS 7.0.在安装完镜像包后,便开始配置静态ip.命令如下 vi /etc/sysconfig/network-scripts/ifcfg-ens33 将BOOTPR ...

  3. Migrate to AndroidX 遇到的坑

    Androidx 迁移方法: 首先把 gradle 版本改为3.2.0以上,以及 compileSdkVersion 为28以上 然后 Android Studio 菜单栏 Refactor -> ...

  4. 三伏天里小试牛刀andriod 开发 #华为云·寻找黑马程序员#【华为云技术分享】

    2019年07月,北京,三伏天,好热啊.越热自己还越懒得动换(肉身给的信号),但是做为产品经理/交互设计师的,总想着思考些什么(灵魂上给的信号),或者是学习些什么,更有利于将来的职业发展吧,哈哈哈.工 ...

  5. ZooKeeper学习笔记(二)——内部原理

    zookeeper学习笔记(二)--内部原理 1. zookeeper的节点的类型 总的来说可以分为持久型和短暂型,主要区别如下: 持久:客户端与服务器端断开连接的以后,创建的节点不会被删除: 持久化 ...

  6. Openstack Sahara组件和架构简介

    1.简介 Apache Hadoop是目前被广泛使用的主流大数据处理计算框架,Sahara项目旨在使用用户能够在Openstack平台上便于创建和管理Hadoop以及其他计算框架集群,实现类似AWS的 ...

  7. jQuery.Form.js使用方法

    一.jQuery.Form.js 插件的作用是实现Ajax提交表单. 方法: 1.formSerilize() 用于序列化表单中的数据,并将其自动整理成适合AJAX异步请求的URL地址格式. 2.cl ...

  8. Fiddler-在fiddlerscript中修改某个请求的请求头内容

    1.进入  OnBeforeRequest函数 在里面添加如下代码 if(oSession.fullUrl.Contains("url")){// //headers中添加测试参数 ...

  9. Python进阶----数据库引擎(InnoDB),表的创建,mysql的数据类型,mysql表的约束

    Python进阶----数据库引擎(InnoDB),表的创建,mysql的数据类型,mysql表的约束 一丶MySQL的存储引擎 什么是存储引擎:    MySQL中的数据用各种不同的技术存储在文件( ...

  10. 【JVM】记录一次线上SWAP偏高告警的故障分析过程

    近期遇到一个堆外内存导致swap飙高的问题,这类问题比较罕见,因此将整个排查过程记录下来了 现象描述 最近1周线上服务器时不时出现swap报警(swap超过内存10%时触发报警,内存是4G,因此swa ...