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)

 

測試結果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章