本人是一名数学系研究生,于2017年底第一次接触python和机器学习,作为一名新手,欢迎与大家交流。
我主要给大家讲解代码,理论部分给大家推荐3本书:
《机器学习实战中文版》
《机器学习》周志华
《统计学习方法》李航
以上3本书,第一本是基于python2的代码实现;剩余两本主要作为第一本书理论省略部分的补充,理论大部分都讲得很细。
博客上关于机器学习实战理论解释都很多,参差不齐,好作品也大都借鉴了以上3本书,网上有很多电子版的书。
与其看看一些没用的博客,真心不如以上3本书有收获。
说实话,学习一定要静下心来,切忌浮躁。不懂可以每天看一点,每天你懂一点,天天积累就多了。
操作系统:windows8.1
python版本:python3.6
运行环境:spyder(anaconda)
# -*- coding: utf-8 -*-
"""
Created on Sun Mar 25 09:58:19 2018
@author: Lelouch_C.C
"""
from numpy import *
def loadDataSet():
return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
def createC1(dataSet):
"""
函数说明:C1 是大小为1的所有候选项集的集合,是不重复的frozenset集合.
"""
C1 = []
for transaction in dataSet:
for item in transaction:
if not [item] in C1:
C1.append([item]) #store all the item unrepeatly
C1.sort()
#return map(frozenset, C1)#frozen set, user can't change it.
return list(map(frozenset, C1))
#这里使用的格式就是Python中frozenset类型。frozenset是指被“冰冻”的集合,即用户不能修改它们。
#
def scanD(D,Ck,minSupport):
"""
函数说明:该函数用于从大小为1的所有候选项集的集合C1生成频繁项集列表L1,即retList。
数据集:D
候选项集列表:Ck
最小支持度:minSupport
返回值: 频繁项集列表:retList
包含支持度值的字典:supportData
"""
ssCnt={}
for tid in D: #遍历数据集
for can in Ck: #遍历候选项
if can.issubset(tid): #判断候选项中是否含数据集的各项
#if not ssCnt.has_key(can): # python3 can not support
if not can in ssCnt:
ssCnt[can]=1 #不含设为1
else: ssCnt[can]+=1 #有则计数加1
numItems=float(len(D)) #数据集大小
retList = [] #L1初始化
supportData = {} #记录候选项中各个数据的支持度
for key in ssCnt:
support = ssCnt[key]/numItems #计算支持度
if support >= minSupport:
retList.insert(0,key) #满足条件加入L1中
supportData[key] = support
return retList, supportData
"""
if __name__=='__main__':
dataSet=loadDataSet()
C1=createC1(dataSet)
print('C1=',C1)
D=list(map(set,dataSet))
print('D=',D)
L1,suppData0=scanD(D,C1,0.5)
print('L1=',L1)
print('suppData0=',suppData0)
#"""
"""
Apriori算法的伪代码:
当集合中项的个数大于0时:
构建一个k个项组成的候选项集的列表
检查数据以确认每个项集都是频繁的
保留频繁项集并构建k+1项组成的候选项集的列表
"""
def aprioriGen(Lk, k):
"""
函数说明:通过输入参数Lk、k, 输出候选项集Ck
频繁项集列表: Lk
项集元素个数: k
"""
retList = []
lenLk = len(Lk)
for i in range(lenLk):
for j in range(i+1, lenLk): #两两组合遍历
L1 = list(Lk[i])[:k-2]; L2 = list(Lk[j])[:k-2] #关于k-2的疑惑书上解释得很清楚,为了避免重复操作
#print('list(Lk[i]=',list(Lk[i]))
#print('list(Lk[i])[:k-2]=',list(Lk[i])[:k-2])
#print('list(Lk[j]=',list(Lk[j]))
#print('list(Lk[j])[:k-2]=',list(Lk[j])[:k-2])
L1.sort(); L2.sort()
if L1==L2: #若两个集合的前k-2个项相同时,则将两个集合合并
retList.append(Lk[i] | Lk[j]) #操作符‘|’是并
return retList
def apriori(dataSet, minSupport = 0.5):
C1 = createC1(dataSet)
#print('C1=',C1)
D = list(map(set, dataSet))
#print('D=',D)
L1, supportData = scanD(D, C1, minSupport) #单项最小支持度判断 0.5,生成L1
#print('L1=',L1)
#print('supportData=',supportData)
L = [L1] #列表L会逐渐包含频繁项集L1,L2,L3...
#print('L=',L)
k = 2
while (len(L[k-2]) > 0):
#寻找频繁项集L1,L2,L3...通过while循环来完成。创建包含更大项集的更大列表,直到下一个大的项集为空
Ck = aprioriGen(L[k-2], k)
#print('Ck=',Ck)
Lk, supK = scanD(D, Ck, minSupport)
#print('Lk=',Lk)
#print('supK=',supK)
supportData.update(supK)
L.append(Lk)
#print(L)
k += 1
return L, supportData
#"""
if __name__=='__main__':
dataSet=loadDataSet()
apriori(dataSet)
"""
输出:
C1= [frozenset({1}), frozenset({2}), frozenset({3}), frozenset({4}), frozenset({5})]
D= [{1, 3, 4}, {2, 3, 5}, {1, 2, 3, 5}, {2, 5}]
L1= [frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})]
supportData= {frozenset({1}): 0.5, frozenset({3}): 0.75, frozenset({4}): 0.25, \
frozenset({2}): 0.75, frozenset({5}): 0.75}
L= [[frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})]]
list(Lk[i]= [5]
list(Lk[i])[:k-2]= []
list(Lk[j]= [2]
list(Lk[j])[:k-2]= []
list(Lk[i]= [5]
list(Lk[i])[:k-2]= []
list(Lk[j]= [3]
list(Lk[j])[:k-2]= []
list(Lk[i]= [5]
list(Lk[i])[:k-2]= []
list(Lk[j]= [1]
list(Lk[j])[:k-2]= []
list(Lk[i]= [2]
list(Lk[i])[:k-2]= []
list(Lk[j]= [3]
list(Lk[j])[:k-2]= []
list(Lk[i]= [2]
list(Lk[i])[:k-2]= []
list(Lk[j]= [1]
list(Lk[j])[:k-2]= []
list(Lk[i]= [3]
list(Lk[i])[:k-2]= []
list(Lk[j]= [1]
list(Lk[j])[:k-2]= []
Ck= [frozenset({2, 5}), frozenset({3, 5}), frozenset({1, 5}), frozenset({2, 3}), \
frozenset({1, 2}), frozenset({1, 3})]
Lk= [frozenset({2, 3}), frozenset({3, 5}), frozenset({2, 5}), frozenset({1, 3})]
supK= {frozenset({1, 3}): 0.5, frozenset({2, 5}): 0.75, frozenset({3, 5}): 0.5,\
frozenset({2, 3}): 0.5, frozenset({1, 5}): 0.25, frozenset({1, 2}): 0.25}
[[frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})], \
[frozenset({2, 3}), frozenset({3, 5}), frozenset({2, 5}), frozenset({1, 3})]]
list(Lk[i]= [2, 3]
list(Lk[i])[:k-2]= [2]
list(Lk[j]= [3, 5]
list(Lk[j])[:k-2]= [3]
list(Lk[i]= [2, 3]
list(Lk[i])[:k-2]= [2]
list(Lk[j]= [2, 5]
list(Lk[j])[:k-2]= [2]
list(Lk[i]= [2, 3]
list(Lk[i])[:k-2]= [2]
list(Lk[j]= [1, 3]
list(Lk[j])[:k-2]= [1]
list(Lk[i]= [3, 5]
list(Lk[i])[:k-2]= [3]
list(Lk[j]= [2, 5]
list(Lk[j])[:k-2]= [2]
list(Lk[i]= [3, 5]
list(Lk[i])[:k-2]= [3]
list(Lk[j]= [1, 3]
list(Lk[j])[:k-2]= [1]
list(Lk[i]= [2, 5]
list(Lk[i])[:k-2]= [2]
list(Lk[j]= [1, 3]
list(Lk[j])[:k-2]= [1]
Ck= [frozenset({2, 3, 5})]
Lk= [frozenset({2, 3, 5})]
supK= {frozenset({2, 3, 5}): 0.5}
[[frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})], \
[frozenset({2, 3}), frozenset({3, 5}), frozenset({2, 5}), frozenset({1, 3})], \
[frozenset({2, 3, 5})]]
Ck= []
Lk= []
supK= {}
[[frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})],\
[frozenset({2, 3}), frozenset({3, 5}), frozenset({2, 5}), frozenset({1, 3})], \
[frozenset({2, 3, 5})], []]
#"""
#
def generateRules(L, supportData, minConf=0.7):
"""
函数说明:关联规则生成函数
频繁项集列表:L
包含那些频繁项集支持数据的字典:supportData
最小可信度阈值:minConf
"""
bigRuleList = [] #bigRuleList是包含可信度的规则列表,此处进行初始化
for i in range(1, len(L)):
#遍历(1, len(L))是要为L[i]提供索引值
#为什么要从(1, len(L))循环?
#注意到 L[0]是单元素项集,我们无法从单元素项集中构建关联规则;另外,L[len(L)]是空集
#所以,只获取有两个或者更多集合的项目
for freqSet in L[i]:
H1 = [frozenset([item]) for item in freqSet]
print(H1)
#该函数遍历L中的每一个频繁项集并对每个频繁项集创建只包含单个元素集合的列表H1
if (i > 1):
#如果频繁项集元素数目超过2,那么会考虑对它做进一步的合并
rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
else:
calcConf(freqSet, H1, supportData, bigRuleList, minConf)
return bigRuleList
#
def calcConf(freqSet, H, supportData, brl, minConf=0.7):
"""
函数说明:计算项集中只有两个元素的可信度。计算规则的可信度以及找到满足最小可信度要求的规则
频繁项集:freqSet
频繁项集中每个元素frozenset后组成的列表(可以出现在规则右部的元素列表,见234-236行):H
包含那些频繁项集支持数据的字典:supportData
包含可信度的规则列表bigRuleList:brl
最小可信度阈值:minConf
"""
prunedH = [] #建立一个满足最小可信度要求的规则列表
for conseq in H: #后件,遍历 H中的所有项集并计算它们的可信度值
conf = supportData[freqSet]/supportData[freqSet-conseq] #可信度计算
if conf >= minConf:
print (freqSet-conseq,'-->',conseq,'conf:',conf)
#如果某条规则满足最小可信度值,那么将这些规则输出到屏幕显示p
brl.append((freqSet-conseq, conseq, conf))
#添加到规则里,brl是前面通过检查的bigRuleList
prunedH.append(conseq) #同样需要放入列表到后面检查
return prunedH #返回一个满足最小可信度要求的规则列表
#合并
def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
"""
函数说明:从最初的项集中生成更多的关联规则
频繁项集:freqSet
频繁项集中每个元素frozenset后组成的列表(可以出现在规则右部的元素列表,见236-238行):H
包含那些频繁项集支持数据的字典:supportData
包含可信度的规则列表bigRuleList:brl
最小可信度阈值:minConf
"""
m = len(H[0]) #计算H中的频繁项集大小m
print('H=',H)
print('H[0]=',H[0])
if (len(freqSet) > (m + 1)):
print('len(freqSet)=',len(freqSet))
#查看频繁项集频繁项集freqSet是否大到可以移除大小为m的子集
Hmp1 = aprioriGen(H, m+1) #使用aprioriGen()来生成H中元素的无重复组合
print('Hmp1=',Hmp1)
Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf) #计算可信度
print('Hmp1=',Hmp1)
if (len(Hmp1) > 1):
print('len(Hmp1)=',len(Hmp1))
#满足最小可信度要求的规则列表多于1,则递归来判断是否可以进一步组合这些规则
rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)
"""
if __name__=='__main__':
L,suppData=apriori(dataSet,minSupport=0.5)
print('L=',L)
print('suppData=',suppData)
#rules=generateRules(L,suppData,minConf=0.7)
#print('rules=',rules)
print('##########################################################')
rules=generateRules(L,suppData,minConf=0.5)
print('rules=',rules)
#"""
#示例1:发现国会投票中的模式
#示例2:发现毒蘑菇的相似特征
if __name__=='__main__':
mushDatSet=[line.split() for line in open('mushroom.dat').readlines()]
#这里采用一种新的数据读取方式,;列表推导式
#print('mushDatSet=',mushDatSet)
L,suppData=apriori(mushDatSet,minSupport=0.3)
print('L=',L)
print('suppData=',suppData)
"""
for item in L[1]:
if item.intersection('2'):
print('item=',item)
for item in L[3]:
if item.intersection('2'):
print('item=',item)
"""
#bigRuleList=generateRules(L, suppData, minConf=0.7)
#print('bigRuleList=',bigRuleList)