《python数据分析与挖掘实战》第八章详解

代码来自书上,进行了一定修改,确保运行没有error

挖掘的总体思路:

首先癌症有不同的发展期

不同发展期的癌症有不同的症型

这些症状都处于不同的严重程度。

因此收集病人样本930条。

数据挖掘流程:

一(对应代码1)、

每人的6种症型(症状名字的代号是A~F,分别对应data.xls中的各种症型)都处于不同的严重程度,

每种症型按照严重程度高低,聚类为四个区间,并分别得到各个区间的数量。每个区间取名字例如:A1~A4

由于每个病人都有六种症状的不同区间,因此每个病人都可以由一个6维矢量来表示

二(对应代码2)、6维矢量扩充成24维矢量,使用Apriori算法,找出不同严重程度的症状和乳腺癌发展时期之间的联系,也就是说,找出哪些症状(例如A3和B5)极有可能导致乳腺癌的某个特定的时期(例如H5),挖掘结束。

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆第一部分代码开始☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

# -*- coding: utf-8 -*-

'''

聚类离散化,最后的result的格式为:

  1 2 3 4

A 0 0.178698 0.257724 0.351843

An 240 356.000000 281.000000 53.000000

即(0, 0.178698]有240个,(0.178698, 0.257724]有356个,依此类推。

'''

from __future__ import print_function

import pandas as pd

from sklearn.cluster import KMeans # 导入K均值聚类算法

datafile = '../data/data.xls' #待聚类的数据文件

processedfile = '../tmp/data_processed.xls' # 数据处理后文件

typelabel = {u'肝气郁结证型系数': 'A', u'热毒蕴结证型系数': 'B', u'冲任失调证型系数': 'C', u'气血两虚证型系数': 'D', u'脾胃虚弱证型系数': 'E', u'肝肾阴虚证型系数': 'F'}

k = 4 # 需要进行的聚类类别数

# 读取数据并进行聚类分析

data = pd.read_excel(datafile) # 读取数据

keys = list(typelabel.keys())

result = pd.DataFrame()

if __name__ == '__main__': # 判断是否主窗口运行,如果是将代码保存为.py后运行,则需要这句,如果直接复制到命令窗口运行,则不需要这句。

  for i in range(len(keys)):#每轮循环处理一个症状的聚类和数量统计

  print("i=", i)

  # 调用k-means算法,进行聚类离散化

  print(u'正在进行“%s”的聚类...' % keys[i])

  kmodel = KMeans(n_clusters=k, n_jobs=4) # n_jobs是并行数,一般等于CPU数较好

  kmodel.fit(data[[keys[i]]].as_matrix()) # 训练模型

  r1 = pd.DataFrame(kmodel.cluster_centers_, columns=[typelabel[keys[i]]]) # 聚类中心

  print("r1=",r1)

  print("label=", typelabel[keys[i]])

  #

  #

  #

  r2 = pd.Series(kmodel.labels_).value_counts() # 分类统计

  print("r2=",r2)

  print("-------------------------------------")

  r2 = pd.DataFrame(r2, columns=[typelabel[keys[i]] + 'number']) # 转为DataFrame,记录各个类别的数目

  print("r2=", r2)#这一段用来统计聚类中各个类别的数量,并且写入一列中,并改改名字

  #

  #

  #

  #

  r=pd.concat([r1, r2], axis=1)

  print("排序前r=",r)

  r=r.sort_values(typelabel[keys[i]])

  print("排序后r=",r)

  r.index = [1, 2, 3, 4]#index指的是列标签,typelabel[keys[i]]指的是行标签

  #

  #

  #

  #

  print("----------------------------------------------------")

  print("计算均值前的表格r=",r)

  r[typelabel[keys[i]]] = pd.rolling_mean(r[typelabel[keys[i]]], 2) # rolling_mean()用来计算相邻2列的均值,以此作为边界点。

  r[typelabel[keys[i]]][1] = 0.0 # 这两句代码将原来的聚类中心改为边界点.这里的用法类似于C语言中的r[i][j]

  print("计算均值后的表格r=",r)

  result = result.append(r.T)#旋转

  print("----------------------------------------------------")

  #

  #

  #

  #

  print("result=",result)

  result = result.sort_index() # 以Index排序,即以A,B,C,D,E,F顺序排,A代表症状的名称,BCDE各自代表该症状的严重程度

  result.to_excel(processedfile)

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆第一部分代码结束☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

输出的结果是:

1 2 3 4

A 0 0.178697589 0.2577240643 0.3518431814

Anumber 240 356 281 53

B 0 0.1507662277 0.2966313131 0.4897045019

Bnumber 325 396 180 29

C 0 0.2021487293 0.2890611377 0.4235365546

Cnumber 297 394 204 35

D 0 0.1765046363 0.2571199525 0.3661899988

Dnumber 309 371 211 39

E 0 0.1526978022 0.2575413223 0.3748694473

Enumber 273 319 242 96

F 0 0.1791433755 0.2613863944 0.354642668

Fnumber 200 237 265 228

Dnumber表示D症状对应的病人样本数量

相关解释:

axis=0#表格纵轴

axis=1#表格横轴

每种症状都有四个量化区间

------------------------------------重点代码解释1-----------------------------------------

  r=pd.concat([r1, r2], axis=1).sort_values(typelabel[keys[i]])

这里首先是把r1代表的症状严重程度的量化参数(也就是聚类中心)和各个聚类中心对应的分类数量各自整合成一行,如下,

  A Anumber

0 0.220441 356

1 0.136954 240

2 0.408679 53

3 0.295007 281

然后按行排序(这里的行也就是最终结果中的列,因为后面的代码中存在转置)

  A Anumber

1 0.136954 240

0 0.220441 356

3 0.295007 281

2 0.408679 53

axis=1#表示按行的意思

------------------------重点代码解释1----------------------------------------------------

------------------------------------重点代码解释2---------------------------------------------------------------------------

 r[typelabel[keys[i]]] = pd.rolling_mean(r[typelabel[keys[i]]], 2) # rolling_mean()用来计算相邻2列的均值,以此作为边界点。

解释下这里的r1和r2如何组合成r

举例,输出的其中一段结果为:

计算均值前的表格r= C Cnumber

1 0.158734 297

2 0.245563 394

3 0.332559 204

4 0.514514 35

计算均值后的表格r= C Cnumber

1 0.000000 297

2 0.202149 394

3 0.289061 204

4 0.423537 35

(0.245563+0.332559)/2=0.289061 

自己评论:这种处理方式并不合理,因为数据是对应于聚类中心的,作者在这里随意利用聚类中心进行计算得到的区间,显然是和分类数量在意义和实际上都是不对应的。

-----------------------------重点代码解释2--------------------------------------------------------

--------------------------后续处理-------------------------------------------------

得到聚类处理后的文件为data_processed.xls

结合输入文件data.xls

由于得到了每种症状的各种严重程度的量化区间,所以把data.xls中的各个参数(例如A症状)转化为A1~A4

转化办法如下:

data.xls中,对每行的首单元进行按行排序,由于data.xls中第一列的各项数据处于data_processed.xls的四个区间中,

分别改为A1~A4,从而得到下一份代码需要的文件apriori.txt文件

-------------------------------后续处理结束--------------------------------------------

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆接下来是第二部分☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

被调用函数apriori.py如下

#-*- coding: utf-8 -*-

from __future__ import print_function

import pandas as pd

#自定义连接函数,用于实现L_{k-1}到C_k的连接

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(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

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆第2部分代码开始☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

#-*- coding: utf-8 -*-

from __future__ import print_function

import pandas as pd

from apriori import * #导入自行编写的apriori函数

import time #导入时间库用来计算用时

inputfile = '../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) #转换0-1矩阵的过渡函数

b = map(ct, data.as_matrix()) #用map方式执行

print("b=",b)

data = pd.DataFrame(b)#转化成数据框的时候,一些没有的症状就会被加进来

data=data.fillna(0) #实现矩阵转换,空值用0填充

print("data=",data)

end = time.clock() #计时结束

print(u'\n转换完毕,用时:%0.2f秒' %(end-start))

del b #删除中间变量b,节省内存

#以上的工作是把各种症状的组合转化成矢量

#

support = 0.06 #最小支持度

confidence = 0.87 #最小置信度

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))

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆第2部分代码结束☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

输出结果(也就是所得挖掘结果):

  support confidence

A3---F4---H4 0.078495 0.879518

C3---F4---H4 0.075269 0.875000

顺便解释下基本概念:

support指的是,或关系

Support(A=>B)=P(AUB)

置信度值得是:条件概率

Confidence(A=>B)=P(B|A)

那么以上第一行的结果可以解释为:当肝气郁结症型系数位于A3区间,并且 肝肾阴虚症型系数位于F4区间,在这两个前提的条件下,处于乳腺癌H4阶段的概率为0.879518

在总样本中,这种情况发生的概率是0.078495

上一篇:[ Spring Boot ] o.s.boot.web.support.ErrorPageFilter


下一篇:mac 安装pip2