zoukankan      html  css  js  c++  java
  • 《机器学习实战》 in python3.x

    机器学习实战这本书是在python2.x的环境下写的,而python3.x中好多函数和2.x中的名称或使用方法都不一样了,因此对原书中的内容需要校正,下面简单的记录一下学习过程中fix的部分

    1、print 函数后面需要加括号(程序清单2-4开始出现print函数)

    2、raw_input改为input函数,在3.x中python使用input替代了raw_input函数(程序清单2-5)

    3、reload(KNN)->import importlib

                                 importlib.reload(KNN)

    4、程序清单3-6中

        

    在python2.7中,找到key所对应的第一个元素为:firstStr = myTree.keys()[0],这在python3.4中运行会报错:‘dict_keys‘ object does not support indexing,这是因为python3改变了dict.keys,返回的是dict_keys对象,支持iterable 但不支持indexable,我们可以将其明确的转化成list,则此项功能在python3中应这样实现:

    firstSides = list(myTree.keys()) 
    firstStr = firstSides[0]#找到输入的第一个元素

    5、程序清单3-9

    pickle对数据进行持久化的时候是采用二进制的方式进行存储和读取的,所以写入文件的时候将

    fw=open(filename,'w')---->fw=open(filename,'wb')

    将文件以二进制的形式打开,方便pickle的写入

    从文件中读取数据的时候也要用二进制的方式读取做以下修改

    fr=open(filename)---->fr=open(filename,'rb')

    6、程序清单4-5中

    wordList=textParse(open('ch04/email/ham/%d.txt' % i).read())

    这一句在运行的时候老是报编码错误,结果是读取的文件中有乱码,删除乱码后问题解决

    错误代码如下:

    UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 199: illegal multibyte sequence

    trainingSet=range(50);

    del(trainingSet[randIndex])

    由于range不能返回List,不支持del操作,所以运行时出现以下错误:

    TypeError: 'range' object doesn't support item deletion

    可以将代码修改为:

    trainingSet = list(range(50));  

    7.代码清单8-5

    由于程序运行在python3.x 环境下,而python3.x中用urllib代替了 urllib2函数库

    所以 import urllib2--->import urllib.request

    之所以用urllib.request是因为urllib2.open()方法在python3.x中已经升级成为了urllib.request.open(),所以做此改动,可保无失

    另外,由于原文提及的Google购物API服务已经关闭,所以只能从作者下载的相关页面中提取乐高积木的价格了,需要增加以下函数用于分析页面获取价格数据:

    from BeautifulSoup import BeautifulSoup
    # 从页面读取数据,生成retX和retY列表
    def scrapePage(retX, retY, inFile, yr, numPce, origPrc):
        # 打开并读取HTML文件
        fr = open(inFile,encoding='utf-8')#规定读取文件时编码的格式
        soup = BeautifulSoup(fr.read())
        i=1
        # 根据HTML页面结构进行解析
        currentRow = soup.findAll('table', r="%d" % i)
        while(len(currentRow)!=0):
            currentRow = soup.findAll('table', r="%d" % i)
            title = currentRow[0].findAll('a')[1].text
            lwrTitle = title.lower()
            # 查找是否有全新标签
            if (lwrTitle.find('new') > -1) or (lwrTitle.find('nisb') > -1):
                newFlag = 1.0
            else:
                newFlag = 0.0
            # 查找是否已经标志出售,我们只收集已出售的数据
            soldUnicde = currentRow[0].findAll('td')[3].findAll('span')
            if len(soldUnicde)==0:
                print "item #%d did not sell" % i
            else:
                # 解析页面获取当前价格
                soldPrice = currentRow[0].findAll('td')[4]
                priceStr = soldPrice.text
                priceStr = priceStr.replace('$','') #strips out $
                priceStr = priceStr.replace(',','') #strips out ,
                if len(soldPrice)>1:
                    priceStr = priceStr.replace('Free shipping', '')
                sellingPrice = float(priceStr)
                # 去掉不完整的套装价格
                if  sellingPrice > origPrc * 0.5:
                        print "%d	%d	%d	%f	%f" % (yr,numPce,newFlag,origPrc, sellingPrice)
                        retX.append([yr, numPce, newFlag, origPrc])
                        retY.append(sellingPrice)
            i += 1
            currentRow = soup.findAll('table', r="%d" % i)
    

    同时,SetDATaCollect函数也要做相应的修改:

    # 依次读取六种乐高套装的数据,并生成数据矩阵        
    def setDataCollect(retX, retY):
        scrapePage(retX, retY, '/setHtml/lego8288.html', 2006, 800, 49.99)
        scrapePage(retX, retY, '/setHtml/lego10030.html', 2002, 3096, 269.99)
        scrapePage(retX, retY, '/setHtml/lego10179.html', 2007, 5195, 499.99)
        scrapePage(retX, retY, '/setHtml/lego10181.html', 2007, 3428, 199.99)
        scrapePage(retX, retY, '/setHtml/lego10189.html', 2008, 5922, 299.99)
        scrapePage(retX, retY, '/setHtml/lego10196.html', 2009, 3263, 249.99)

    8、代码清单9-1

    在函数loadDataSet中

    fltLine = list(map(float, curLine))#将每行映射成浮点数,python3 map返回值改变,所以需要添加list()函数

     在函数binSplitDataSet

        #mat0 = dataSet[nonzero(dataSet[:, feature] > value)[0], :][0]
        #mat1 = dataSet[nonzero(dataSet[:, feature] <= value)[0], :][0]

    改为:

    mat0 = dataSet[nonzero(dataSet[:, feature] > value)[0], :]
    mat1 = dataSet[nonzero(dataSet[:, feature] <= value)[0], :]

    逻辑上mat0,mat1返回的是划分后的新矩阵,而不是矩阵的第一行

    9、程序清单9-2

    在chooseBestSplit函数中,由于Matrxi类型不能被Hash(featIndex是随机数)

    将代码

    for splitVal in set(dataSet[:,featIndex]): 

    改为:

    for splitVal in set((dataSet[:,featIndex].T.A.tolist())[0]): 
     

     10、9.7.1节用Tkinter创建GUI

    #windows下python3.2版本之后是自动安装tkinter的,python3.3的引入方式为:
    >>> import _tkinter
    >>> import tkinter
    >>> tkinter._test() #弹出测试窗口
    >>>

    #第一个小测试
    >>> root=Tk() #创建一个空的tk窗口,注意弹出后不要关闭,然后继续输入下一行 >>> myLabel=Label(root,text="hello,Tkinter!") >>> myLabel=grid()#输入以上两行,框内显示文字 >>> #使程序完整: >>> root.mainloop()

     11、treeExplorer.py代码修改如下:(标红的地方为修改的地方)

    from numpy import *
    from tkinter import *
    import regTrees
    import matplotlib
    matplotlib.use('TkAgg')
    from matplotlib.figure import Figure
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    
    
    def reDraw(tolS,tolN):
        reDraw.f.clf()#清空画布
        reDraw.a=reDraw.f.add_subplot(111)#添加新的子图
        if chkBtnVar.get():
            #检查复选框是否被选中
            if tolN<2:tolN=2
            myTree=regTrees.createTree(reDraw.rawdata, regTrees.modelLeaf, regTrees.modelErr,(tolS,tolN))
            yHat=regTrees.createForeCast(myTree,reDraw.testdata,regTrees.modelTreeEval)
        else:
            myTree=regTrees.createTree(reDraw.rawdata,ops=(tolS,tolN))
            yHat=regTrees.createForeCast(myTree,reDraw.testdata)
        reDraw.a.scatter(reDraw.rawdata[:,0].tolist(),reDraw.rawdata[:,1].tolist(),s=5)#绘出真实值,散点图
        reDraw.a.plot(reDraw.testdata,yHat,linewidth=2.0)#绘出测试值,曲线图
        reDraw.canvas.show()
        
    def getInputs():
        try:tolN=int(tolNentry.get())
        except:
            tolN=10
            print("enter Integer for tolN")
            #❷(以下两行) 清除错误的输入并用默认值替换
            tolNentry.delete(0, END)
            tolNentry.insert(0,'10')
        try:tolS=float(tolSentry.get())
        except:
            tolS=1.0
            print("enter Float for tolS")
            tolSentry.delete(0,END)
            tolSentry.insert(0,'1.0')
        return tolN,tolS
        
    
    def drawNewTree():
        tolN,tolS=getInputs()
        reDraw(tolS, tolN)
    
    root=Tk()
    #Label(root,text="plot place Holder").grid(row=0,columnspan=3)
    #利用TkAgg创建画布
    reDraw.f=Figure(figsize=(5,4),dpi=100)
    reDraw.canvas=FigureCanvasTkAgg(reDraw.f,master=root)
    reDraw.canvas.show()
    reDraw.canvas.get_tk_widget().grid(row=0,columnspan=3)#widget:部件
    
    Label(root,text="tolN").grid(row=1,column=0)
    tolNentry=Entry(root)#Entry:文本输入框
    tolNentry.grid(row=1,column=1)
    tolNentry.insert(0,'10')
    Label(root,text="tolS").grid(row=2,column=0)
    tolSentry=Entry(root)#文本输入框
    tolSentry.grid(row=2,column=1)
    tolSentry.insert(0,'1.0')
    Button(root,text="ReDraw",command=drawNewTree).grid(row=1,column=2,rowspan=3)
    chkBtnVar=IntVar()#按钮整数值ֵ
    chkBtn=Checkbutton(root,text="Model Tree",variable=chkBtnVar)#复选框
    chkBtn.grid(row=3,column=0,columnspan=2)
    reDraw.rawdata=mat(regTrees.loadDataSet('sine.txt'))
    reDraw.testdata=arange(min(reDraw.rawdata[:,0]),max(reDraw.rawdata[:,0]),0.01)
    reDraw(1.0,10)
    root.mainloop()

     12、使用K均值聚类,并使用该算法计算波兰的酒吧聚集地及可以到各个酒吧的最佳位置。由于国内使用YahooAPi的地图功能,故使用百度地图提供的API代替,整个代码现改如下:

    from numpy import *
    from matplotlib.markers import MarkerStyle
    def loadDataSet(filename):
        dataMat=[]
        fr=open(filename)
        for line in fr.readlines():
            curLine=line.strip().split('	')
            fltLine=list(map(float,curLine))
            dataMat.append(fltLine)
        return dataMat
    
    #计算欧几里德距离
    def distEclud(vecA,vecB):
        return sqrt(sum(power(vecA-vecB,2)))
    
    #生成随机中心质点
    def randCent(dataSet,k):
        n=shape(dataSet)[1]
        centroids=mat(zeros((k,n)))
        #构建簇质心
        for j in range(n):
            minJ=min(dataSet[:,j])
            rangeJ=float(max(dataSet[:,j])-minJ)
            centroids[:,j]=minJ+rangeJ*random.rand(k,1)#random.rand生成k行1列的数组,其中元素值均分布在(0,1)范围内,实际上是每列对应向量的计算
        return centroids
    
    #k-均值聚类算法
    def kMeans(dataSet,k,distMeas=distEclud,createCent=randCent):
        m=shape(dataSet)[0]
        clusterAssment=mat(zeros((m,2)))#簇分配结果矩阵(该表是质心变化记录表,m代表元素个数,第一列存放的是距离该点最近的质心,第二列出存放的距该质心的距离的平方)
        centroids=createCent(dataSet,k)
        clusterChanged=True
        while clusterChanged:
            clusterChanged=False
            for i in range(m):
                minDist=inf;minIndex=-1
                for j in range(k):
                    #❶(以下三行) 寻找最近的质心
                    distJI=distMeas(centroids[j,:],dataSet[i,:])#寻找距离i点最近的质心
                    if distJI<minDist:
                        minDist=distJI;minIndex=j
                if clusterAssment[i,0]!=minIndex:clusterChanged=True
                clusterAssment[i,:]=minIndex,minDist**2
            #❷(以下四行) 更新质心的位置
            print(centroids)
            #获取新的K个点作为新的质心
            for cent in range(k):
                ptsInClust=dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]#返回该质点对应的所有DataSet中的点(所有距离该质心距离最短的点)
                centroids[cent,:]=mean(ptsInClust,axis=0)#按列(压缩行)返回均值(返回每列的平均值),产生新的质心
        return centroids,clusterAssment
    
    #二分K-均值聚类算法
    def biKmeans(dataSet,k,distMeas=distEclud):
        m=shape(dataSet)[0]
        clusterAssment=mat(zeros((m,2)))
        #❶(以下两行) 创建一个初始簇
        centroid0=mean(dataSet,axis=0).tolist()[0]#所有点的平均值:绝对中心位置
        centList=[centroid0]
        for j in range(m):
            clusterAssment[j,1]=distMeas(mat(centroid0),dataSet[j,:])**2#计算所有点距离中心点的距离平方
        while(len(centList)<k):#质点不足K个
            lowestSSE=Inf#SSE:距离质点的距离平方和
            for i in range(len(centList)):
                #❷(以下两行) 尝试划分每一簇
                ptsInCurrCluster=dataSet[nonzero(clusterAssment[:,0].A==i)[0],:]
                centroidMat,splitClusAss=kMeans(ptsInCurrCluster,2,distMeas)
                sseSplit=sum(splitClusAss[:,1])#新划分的簇质点距离平方和
                sseNotSplit=sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1])#老簇除了第i个质点外距离平方和
                print("sseSplit,and notSplit",sseSplit,sseNotSplit)
                if(sseSplit+sseNotSplit)<lowestSSE:#新的总和<老的总和
                    bestCentToSplit=i#最佳划分质点
                    bestNewCents=centroidMat#最佳新质点集
                    bestClustAss=splitClusAss.copy()#最佳簇分配矩阵
                    lowestSSE=sseSplit+sseNotSplit#刷新最小SSE
            bestClustAss[nonzero(bestClustAss[:,0].A==1)[0],0]=len(centList)#更新质点序号
            bestClustAss[nonzero(bestClustAss[:,0].A==0)[0],0]=bestCentToSplit#以方便并入总质点集
            print('the bestCentToSplit is:',bestCentToSplit)
            print('the len of bestClusAss is:',len(bestClustAss))
            #(以下两行)将老的一个质点用两个最佳的新质点替换
            centList[bestCentToSplit] = bestNewCents[0,:].tolist()[0]
            centList.append(bestNewCents[1,:].tolist()[0])
            clusterAssment[nonzero(clusterAssment[:,0].A==bestCentToSplit)[0],:]=bestClustAss#更新簇分配矩阵(将最佳划分点相关的部分全部用新的划分点和距离替代)
        return mat(centList),clusterAssment
                    
    import urllib
    import urllib.request
    import json
    
    def geoGrab(stAddress,city):
        apiStem="http://api.map.baidu.com/geocoder/v2/?"
        params={}
        #❶ 将返回类型设为JSON
        params['address']='%s%s'%(stAddress,city)
        params['ak']='您自己申请的百度API的key'
        params['output']='json'
        url_params=urllib.parse.urlencode(params)
        baiduApi=apiStem+url_params
        print(baiduApi)
        #❷ 打印输出的的URL
        c=urllib.request.urlopen(baiduApi)
        return json.loads(c.read().decode('utf-8'))#指定编码,否则默认为字节不是字符串
    
    from time import sleep
    #批量获取经纬度并将“地址+经纬度”写入place.txt
    def massPlaceFind(fileName):
        fw=open('places.txt','w')
        for line in open(fileName).readlines():
            line=line.strip()
            lineArr=line.split('	')
            #print(lineArr)
            retDict=geoGrab(lineArr[1],lineArr[2])#1和2分别是详细地址(精确到门牌号)和城市名称
            if retDict['status']==0:#正常返回
                lat=float(retDict['result']['location']['lat'])#纬度
                lng=float(retDict['result']['location']['lng'])#经度
                print("%s	%f	%f"%(lineArr[0],lat,lng))
                fw.write('%s	%f	%f
    '%(line,lat,lng))#将经纬度添加到原来对应的行上
            else:
                print("error fetching")
            sleep(1)
        fw.close()
        
    #使用余弦定理计算两点之间距离
    def distSLC(vecA,vecB):
        a=sin(vecA[0,1]*pi/180)*sin(vecB[0,1]*pi/180)
        b=cos(vecA[0,1]*pi/180)*cos(vecB[0,1]*pi/180)*cos(pi*(vecB[0,0]-vecA[0,0])/180)
        return arccos(a+b)*6371.0
    
    import matplotlib
    import matplotlib.pyplot as plt
    def clusterClubs(numClust=5):
        datList=[]
        for line in open('places.txt').readlines():
            lineArr=line.split('	')
            datList.append([float(lineArr[4]),float(lineArr[3])])#基于进度和纬度创建矩阵
        datMat=mat(datList)
        myCentroids,clustAssing=biKmeans(datMat,numClust,distMeas=distSLC)
        fig=plt.figure()
        rect=[0.1,0.1,0.8,0.8]#决定绘制图的哪一部分的矩阵
        scatterMarkers=['s','o','^','8','p','d','v','h','>','<']#形状标记
        axprops=dict(xticks=[],yticks=[])
        ax0=fig.add_axes(rect,label='ax0',**axprops)
        imgP=plt.imread('Portland.png')
        #❶ 基于图像创建矩阵
        ax0.imshow(imgP)
        ax1=fig.add_axes(rect,label='ax1',frameon=False)#使用ax1在原图像上绘制新图
        for i in range(numClust):
            ptsInCurrCluster=datMat[nonzero(clustAssing[:,0]==i)[0],:]
            markerStyle=scatterMarkers[i%len(scatterMarkers)]#循环使用标记
            ax1.scatter(ptsInCurrCluster[:,0].flatten().A[0],ptsInCurrCluster[:,1].flatten().A[0],marker=markerStyle,s=90)
        ax1.scatter(myCentroids[:,0].flatten().A[0],myCentroids[:,1].flatten().A[0],marker='+',s=300)#使用+标记中心位置
        plt.show()
            
                    
        
    
            
        
        
                
        
        

     13、apriori算法修改如下

    def loadDataSet():
        return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]
    
    def createC1(dataSet):
        C1=[]#大小为1的所有候选项集合
        for transaction in dataSet:
            for item in transaction:
                if not [item] in C1:
                    C1.append([item])
        C1.sort()
        #对C1中每个项构建一个不变集合
        return list(map(frozenset,C1))#frozenset:用户不可改的集合
    
    #D:数据集 
    #Ck:候选项集列表
    #minSupport:最小支持度
    #生成频繁项集
    def scanD(D,Ck,minSupport):
        ssCnt={}#ssCnt:{key:value},key为项,value为其出现的次数
        for tid in D:
            for can in Ck:
                if can.issubset(tid):#can是tid的子集
                    if not can in ssCnt:ssCnt[can]=1
                    else:ssCnt[can]+=1
        numItems=float(len(D))
        retList=[]
        supportData={}
        for key in ssCnt:
            #计算所有项集的支持度
            support=ssCnt[key]/numItems
            if support>=minSupport:
                retList.insert(0,key)#在列表头部插入
            supportData[key]=support#最频繁项集及其支持度 key:value
        return retList,supportData

    变化的部分都用红色标出,以后也会采取类似的做法

    to be continued……

  • 相关阅读:
    简单明了的带你理解springboot原理和三大核心注解
    Spring Boot(一):入门篇
    【Mysql优化】聚簇索引与非聚簇索引概念
    Mysql索引原理与优化
    Mysql全文索引的使用
    索引的优缺点,如何创建索引
    184 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 04 例:字符串与byte(即:字节)数组间的相互转换
    183 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 03 String常用方法(下)
    182 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 02 String常用方法(上)
    181 01 Android 零基础入门 03 Java常用工具类03 Java字符串 02 String类 01 String常用方法简介
  • 原文地址:https://www.cnblogs.com/nerd/p/7079041.html
Copyright © 2011-2022 走看看