学习笔记:【案例】中医证型关联规则挖掘

案例来源:《Python数据分析与挖掘实战》第8章

案例背景与挖掘目标

输入数据:

挖掘目标:

  1. 借助三阴乳腺癌患者的病理信息,挖掘患者的症状与中医证型之间的关联关系
  2. 对截断治疗提供依据,挖掘潜性证素

分析方法与过程(选择的原则)

子任务规划

  1. 问卷形式收集原始数据
  2. 数据预处理
  3. 运用关联规则算法建模
  4. 分析结果,应用到实际业务中

实验
实现Apriori关联规则算法

  1. 读取数据 demo/data/apriori.txt
  2. 离散化操作,将事务集转换为 0, 1 矩阵
  3. 根据支持度找出频繁集,直至找到最大频繁集后停止
  4. 根据置信度得到大于等于置信度的规则,即为Apriori算法所求的关联规则
  5. 对Apriori算法输出的规则,编写过滤函数
  6. (拓展)以上实验使用聚类进行数据离散化,可尝试其他离散化方法,如等距、等频、决策树、基于卡方检验等,比较各个方法的优缺点

代码存档:

实验

import pandas as pd
import os
from __future__ import print_function
from sklearn.cluster import KMeans
import time
dpath = './demo/data/data.xls'
input_data = pd.read_excel(dpath)
input_data.describe()
肝气郁结证型系数 热毒蕴结证型系数 冲任失调证型系数 气血两虚证型系数 脾胃虚弱证型系数 肝肾阴虚证型系数
count 930.000000 930.000000 930.000000 930.000000 930.000000 930.000000
mean 0.232154 0.214438 0.247039 0.217702 0.227043 0.271739
std 0.078292 0.131887 0.087779 0.079210 0.108064 0.099186
min 0.026000 0.000000 0.067000 0.059000 0.003000 0.016000
25% 0.176250 0.127000 0.185000 0.160000 0.140000 0.188250
50% 0.231000 0.186000 0.236500 0.208500 0.200000 0.273000
75% 0.281750 0.274000 0.291000 0.264000 0.318000 0.352000
max 0.504000 0.780000 0.610000 0.552000 0.526000 0.607000
processedfile = './demo/tmp/data_processed2.xls'
typelabel = {u'肝气郁结证型系数':'A', u'热毒蕴结证型系数':'B', u'冲任失调证型系数':'C', u'气血两虚证型系数':'D', u'脾胃虚弱证型系数':'E', u'肝肾阴虚证型系数':'F'}
k = 4

keys = list(typelabel.keys())
result = pd.DataFrame()
for i in range(len(keys)):
    print(u'executing "%s" clustering' % keys[i])
    kmodel = KMeans(n_clusters=k, n_jobs=4)
    kmodel.fit(input_data[[keys[i]]].as_matrix())
    
    r1 = pd.DataFrame(kmodel.cluster_centers_, columns=[typelabel[keys[i]]])
    r2 = pd.Series(kmodel.labels_).value_counts()
    r2 = pd.DataFrame(r2, columns=[typelabel[keys[i]] + 'n'])
    r  = pd.concat([r1, r2], axis=1).sort_values(typelabel[keys[i]])
    r.index = [1,2,3,4]
    
    #r[typelabel[keys[i]]] = pd.rolling_mean(r[typelabel[keys[i]]], 2)
    r[typelabel[keys[i]]] = r2.rolling(window = 2, center = False).mean()
    r[typelabel[keys[i]]][1] = 0.0
    result = result.append(r.T)
    
result = result.sort_index()
result.to_excel(processedfile)
executing "肝气郁结证型系数" clustering
executing "热毒蕴结证型系数" clustering


/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/ipykernel_launcher.py:14: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  


executing "冲任失调证型系数" clustering
executing "气血两虚证型系数" clustering
executing "脾胃虚弱证型系数" clustering
executing "肝肾阴虚证型系数" clustering
def connect_string(x, ms):
    x = list(map(lambda i: sorted(i.split(ms)), x))
    l = len(x[0])
    r = []
    for i in range(len(x)):
        for j in range(i, len(x)):
            if x[i][:l - 1] == x[j][:l - 1] and x[i][l - 1] != x[j][l - 1]:
                r.append(x[i][:l - 1] + sorted([x[j][l - 1], x[i][l - 1]]))
    return r
def find_rule(d, support, confidence, ms=u'--'):
    result = pd.DataFrame(index=['support', 'confidence'])  # 定义输出结果

    support_series = 1.0 * d.sum() / len(d)  # 支持度序列
    column = list(support_series[support_series > support].index)  # 初步根据支持度筛选
    k = 0

    while len(column) > 1:
        k = k + 1
        print(u'\n正在进行第%s次搜索...' % k)
        column = connect_string(column, ms)
        print(u'数目:%s...' % len(column))
        sf = lambda i: d[i].prod(axis=1, numeric_only=True)  # 新一批支持度的计算函数

        # 创建连接数据,这一步耗时、耗内存最严重。当数据集较大时,可以考虑并行运算优化。
        d_2 = pd.DataFrame(list(map(sf, column)), index=[ms.join(i) for i in column]).T

        support_series_2 = 1.0 * d_2[[ms.join(i) for i in column]].sum() / len(d)  # 计算连接后的支持度
        column = list(support_series_2[support_series_2 > support].index)  # 新一轮支持度筛选
        support_series = support_series.append(support_series_2)
        column2 = []

        for i in column:  # 遍历可能的推理,如{A,B,C}究竟是A+B-->C还是B+C-->A还是C+A-->B?
            i = i.split(ms)
            for j in range(len(i)):
                column2.append(i[:j] + i[j + 1:] + i[j:j + 1])

        cofidence_series = pd.Series(index=[ms.join(i) for i in column2])  # 定义置信度序列

        for i in column2:  # 计算置信度序列
            cofidence_series[ms.join(i)] = support_series[ms.join(sorted(i))] / support_series[ms.join(i[:len(i) - 1])]

        for i in cofidence_series[cofidence_series > confidence].index:  # 置信度筛选
            result[i] = 0.0
            result[i]['confidence'] = cofidence_series[i]
            result[i]['support'] = support_series[ms.join(sorted(i.split(ms)))]

    result = result.T.sort_values(['confidence', 'support'], ascending=False)  # 结果整理,输出
    print(u'\n结果为:')
    print(result)

    return result
inputfile = './demo/data/apriori.txt' #输入事务集文件
data = pd.read_csv(inputfile, header=None, dtype = object)

start = time.clock() #计时开始
print(u'\n转换原始数据至0-1矩阵...')
ct = lambda x : pd.Series(1, index = x[pd.notnull(x)]) #转换0-1矩阵的过渡函数
b = map(ct, data.as_matrix()) #用map方式执行
c = list(b)
data = pd.DataFrame(c).fillna(0) #实现矩阵转换,空值用0填充
end = time.clock() #计时结束
print(u'\n转换完毕,用时:%0.2f秒' %(end-start))
del b #删除中间变量b,节省内存

support = 0.06 #最小支持度
confidence = 0.75 #最小置信度
ms = '---' #连接符,默认'--',用来区分不同元素,如A--B。需要保证原始表格中不含有该字符

start = time.clock() #计时开始
print(u'\n开始搜索关联规则...')
find_rule(data, support, confidence, ms)
end = time.clock() #计时结束
print(u'\n搜索完成,用时:%0.2f秒' %(end-start))
转换原始数据至0-1矩阵...

转换完毕,用时:0.33秒

开始搜索关联规则...

正在进行第1次搜索...
数目:276...

正在进行第2次搜索...
数目:947...

正在进行第3次搜索...
数目:41...

结果为:
                    support  confidence
A3---F4---H4       0.078495    0.879518
C3---F4---H4       0.075269    0.875000
B2---F4---H4       0.062366    0.794521
C2---E3---D2       0.092473    0.754386
D2---F3---H4---A2  0.062366    0.753247

搜索完成,用时:2.34秒
posted @ 2018-08-07 18:17  极客W先森  阅读(3059)  评论(0编辑  收藏  举报