R-数据挖掘-关联规则(三)

海林老师《数据挖掘》课程作业系列

要求:自己写R/Python代码、函数实现一系列算法

其他参见:

R-数据挖掘-求混合型数据对象距离(一)

R-数据挖掘-主成分分析PCA(二)

R-数据挖掘-关联规则(三)

R-数据挖掘-决策树ID3(四)

R-数据挖掘-贝叶斯分类(五)

R-数据挖掘-聚类Kmeans(六)

R-数据挖掘-聚类DBSCAN(七)

全文逻辑:(读者可将所有代码按顺序复制到RStudio,全选ctrl+A,运行ctrl+enter,查看结果)

  1. 分析
  2. 算法/函数
  3. 测试数据
  4. 测试代码
  5. 测试结果(截图)

分析:这个比较难!!

#支持包:library(hash)
#输入数据集itemset,最小支持度min_sup,最小置信度min_conf。(均为小数)
#输出:频繁项集集合,及关联规则
#返回:关联规则数据框
#itemset包含:tid,items。
#如:itemset<-data.frame(tid=c("T1","T2","T3","T4","T5","T6","T7","T8","T9"),items=c("1,2,5","2,4","2,3","1,2,4","1,3","2,3","1,3","1,2,3,5","1,2,3"))

 

 

算法实现(编写函数):

#如下

myapriori<-function(itemset,min_sup,min_conf){
  library(hash)

  itemset$items<-as.character(itemset$items)
  items_num<-nrow(itemset)
  #字符串拼接。输入c("1","2","3")输出"1,2,3"
  p_c<-function(c){
    x=""
    for (i in 1:length(c)) {
      x=paste0(x,',',c[i])
    }
    return(substr(x,2,nchar(x)))
  }
  
  #返回CK_list,即若输入{1},{2},{3}k=2,则输出{1,2}{1,3},{2,3}
  #LK_1_list:待自连接的列表,K:连接后元素的长度(K>1)
  aprioriGen<-function(LK_1_list, k){
    #返回的项集元素个数(若元素的前 k-2 相同,就进行合并)
    CK_list = NULL
    lenLk = length(LK_1_list)
    for( i in 1:lenLk){
      if((i+1)<=lenLk){
        for (j in (i+1):lenLk){
          L1 = LK_1_list[[i]][0:(k-2)]
          L2 = LK_1_list[[j]][0:(k-2)]
          L1=sort( L1)
          L2=sort(L2)
          # 第一次 L1,L2 为空,元素直接进行合并,返回元素两两合并的数据集
          if (all(L1 == L2)){
            CK_list=c(CK_list,list(union(LK_1_list[[i]],LK_1_list[[j]])))#并集
          }
        }
      }
    }
    #剪枝降维
    if(k>2){
      CK_list_new=NULL
      for (i in 1:length(CK_list)) {
        if(all(combn(CK_list[[i]],k-1,simplify = F) %in% LK_1_list)){
          CK_list_new=c(CK_list_new,CK_list[i])
        }
      } 
      CK_list<-CK_list_new
    }
    return(CK_list)
  }
  
  #返回频繁k项集数据框形式LK
  #items_split原数据列表,CK_list为k项集列表形式,min_sup最小支持度
  #注释掉的为:先扫描模式再扫描数据库(此方法不好。。。用下面的)······················
 # pf<-function(items_split,CK_list,min_sup=0.5){
 #   CK<-data.frame(tid=NA,count=NA,supp=NA)
 #   for (i in 1:length(CK_list)) {
 #     count=0
#      for (j in 1:length(items_split)) {
 #       if(all(CK_list[[i]]%in%items_split[[j]])){
#          count=count+1
#        }
#      }
#      tid=p_c(CK_list[[i]])
#      supp=round(count/items_num,3)
#      CK<-rbind(CK,c(tid,count,supp))
#    }
#    CK<-na.omit(CK)
#    LK<-subset(CK,CK[,3]>=min_sup)     
#    return(LK)
#  }
 #先扫描数据库,再扫描模式!!!! 
  pf<-function(items_split,CK_list,min_sup=0.5){
      count=rep(0,length(CK_list))
      for (i in 1:length(items_split)) {
        for (j in 1:length(CK_list)) {
          if(all(CK_list[[j]]%in%items_split[[i]])){
            count[j]=count[j]+1
          }
        }
      }
      tid=c()
      for (x in 1:length(CK_list)) {
        tid=c(tid,p_c(CK_list[[x]]))
      }
      supp=round(count/items_num,3)
      CK<-data.frame(tid=tid,count=count,supp=supp,stringsAsFactors = F)
      LK<-subset(CK,CK[,3]>=min_sup)     
      return(LK)
  }
  
  #frequent输出频繁项集(输入项集要为字符),包括频次
  frequent<-function(itemset,min_sup=0.5){
    #原始项集列表
    item_list<-strsplit(itemset$items,',')
    #计数1项集C1
    C1<-as.data.frame(table(unlist(item_list)))
    names(C1)<-c("tid","count")
    C1$supp<-round((C1$count)/items_num,3)
    #找出频繁1项集L1
    L1<-subset(C1,C1$supp>=min_sup)
    #L1<-na.omit(C1)
    #L1<-L1[,1:2]
    print(".............L1如下................")
    print(L1)
    L1_list<-as.list(as.character(L1[,1]))
    L1_list_count<-as.list(L1[,2])
    k=2
    L=list(L1_list)
    L_count=list(L1_list_count)
    while(length(L[[k-1]])>0){
      #根据LK_1XLK_1,产生初始K项集CK_list
      CK_list<-aprioriGen(L[[k-1]],k)
      if(is.null(CK_list)){
        break
      }
      #扫描事务,对k项集计数CK和LK
      LK<-pf(item_list,CK_list,min_sup)
      print(paste0("...........L",k,"如下............."))
      print(LK)
      #将LK转换为LK_list
      LK_list<-strsplit(LK$tid,',')
      LK_list_count<-as.list(as.numeric(LK$count))
      L=c(L,list(LK_list))
      L_count=c(L_count,list(LK_list_count))
      k=k+1
    }
    frequent=list(L,L_count)
    return(frequent)
  }
  
  #利用frequent函数和数据集得到频繁模式
  frequent1<-frequent(itemset,min_sup)
  
  #将频次转换为键值对
  h=hash()
  for (i in 1:length(frequent1[[1]])) {
    for (j in 1:length(frequent1[[1]][[i]])) {
      keys=p_c(frequent1[[1]][[i]][[j]])#查找的时候可用h[[keys]]
      values=frequent1[[2]][[i]][j]
      .set(h, keys, values)
    }
  }
  #计算可信度,
  #如{1}{2}{1,2};求{1}=>{2};或者{1,2}{3}{1,2,3}求{1,2}=>{3}
  #字符:a为并集,b为要求的,保留三位有效数字
  conf<-function(a,b,h){
    return(round(as.numeric(h[[a]])/as.numeric(h[[b]]),3))
  }
  #计算支持度
  
  supp<-function(a,h,items_num){
    return(round(as.numeric(h[[a]])/items_num,3))
  }
  
  #将数据分割,左k个;f为待分割列表如:{1 2}{1 3}{2 3}将被分成{1}{2}...
  #返回数据框,包括原串,及两个分串和置信度
  confidence=data.frame(tid=NA,b1=NA,b2=NA)
  fg<-function(confidence,f,k){
    for (i in 1:length(f)) {
      tid=p_c(f[[i]])
      b=combn(f[[i]],k,simplify=F)
      for (j in 1:length(b)) {
        b1=as.character(b[[j]])
        b2=as.character(setdiff(f[[i]],b1))##求差集
        b1=p_c(b1)#拼接字符
        b2=p_c(b2)
        confidence=rbind(confidence,c(tid,b1,b2))
      }
    }
    confidence=na.omit(confidence)
    #求置信度,给confidence增加一列支持度和置信度
    for (i in 1:nrow(confidence)) {
      confidence[i,"supp"]<-supp(confidence[i,1],h,items_num)
      confidence[i,"conf"]<-conf(confidence[i,1],confidence[i,2],h)
    }
    return(confidence)
  }
  
  #输入频繁项集,及最小置信度;输出符合的关联规则
  glgz<-function(fre,min_conf){
    fre1=fre[[1]]
    for (i in 1:length(fre1)) {
      for (j in 1:length(fre1[[i]])) {
        m=length(fre1[[i]][[j]])
        while(m>1){
          confidence=fg(confidence,fre1[[i]][j],m-1)
          m=m-1
        }
      }
    }
    confidence=subset(confidence,confidence$conf>=min_conf)
    return(confidence)
  }
  
  result=glgz(frequent1,min_conf)
  
  print(paste("满足:最小支持度为:",min_sup,";  最小置信度为:",min_conf))
  print("----------------------------------------------------------")
  for(i in 1:nrow(result)){
    print(paste("{",result[i,2],"}","=>","{",result[i,3],"}","  ",result[i,4],"  ",result[i,5]))
  }
  return(result)
}

数据测试:

测试数据:书上的测试数据

itemset<-data.frame(tid=c("T1","T2","T3","T4","T5","T6","T7","T8","T9"),items=c("1,2,5","2,4","2,3","1,2,4","1,3","2,3","1,3","1,2,3,5","1,2,3"))
a=myapriori(itemset,0.2,0.5)

 

测试结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值