美文网首页
Python应用

Python应用

作者: 宙斯YY | 来源:发表于2019-01-14 11:21 被阅读6次

    一.Web服务器
    二.一些原理
    三.Redis
    四.爬虫
    五.数据分析
    六.机器学习
    七.深度学习

    一.Web服务器

    1.HTTP和TCP

    TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性。Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求。Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的。所以Http连接是一种短连接,是一种无状态的连接。所谓的无状态,是指浏览器每次向服务器发起请求的时候,不是通过一个连接,而是每次都建立一个新的连接。如果是一个连接的话,服务器进程中就能保持住这个连接并且在内存中记住一些信息状态。而每次请求结束后,连接就关闭,相关的内容就释放了,所以记不住任何状态,成为无状态连接。

    随着时间的推移,html页面变得复杂了,里面可能嵌入了很多图片,这时候每次访问图片都需要建立一次TCP连接就显得低效了。因此Keep-Alive被提出用来解决效率低的问题。从HTTP/1.1起,默认都开启了Keep-Alive,保持连接特性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。虽然这里使用TCP连接保持了一段时间,但是这个时间是有限范围的,到了时间点依然是会关闭的,所以我们还把其看做是每次连接完成后就会关闭。后来,通过Session, Cookie等相关技术,也能保持一些用户的状态。但是还是每次都使用一个连接,依然是无状态连接。

    以前有个概念很容忍搞不清楚。就是为什么HTTP是无状态的短连接,而TCP是有状态的长连接?HTTP不是建立在TCP的基础上吗,为什么还能是短连接?现在明白了,HTTP就是在每次请求完成后就把TCP连接关了,所以是短连接。而我们直接通过Socket编程使用TCP协议的时候,因为我们自己可以通过代码区控制什么时候打开连接什么时候关闭连接,只要我们不通过代码把连接关闭,这个连接就会在客户端和服务端的进程中一直存在,相关状态数据会一直保存着。

    2.TCP连接

    客户端和服务器端建立连接是端到端的管道,之前在网络编程中知道,每个客户端socket连接到服务器会产生一个socket为该客户端服务;
    一发一收确认一端连接。

    • 简单理解TCP连接三次握手和四次挥手的过程:
      三次握手:
      客户端发送给服务器端连接请求(tcpclient_socket.connect((127.0.0.1,9999))),(1);
      服务器端收到客户端请求之后,告诉客户端收到连接请求(2),此时客户端确认和服务器端建立连接;
      服务器端发送和客户端连接请求(3),客服端接收到服务器端消息发送反馈给服务器端(4),此时服务器确认和客户端建立连接。
      (2),(3)对于服务器端可以合并成一个请求,所以三次握手确保连接建立。
      四次挥手:
      客户端告诉服务器端关闭连接(tcpclient_socket.close()),(1);
      服务器端收到客户端请求关闭后,告诉客户端收到关闭请求,(2);
      服务器端告诉客户端关闭服务器端连接(tcpservice_socket.close()),(3);
      客户端收到关闭服务器端消息后,给服务器端发送收到请求(4),此时服务器确认和客户端断开连接。
      (2),(3)不能合并成一个请求是因为服务器端调用close是一个不确定是否会被调用的操作。
      服务器端发送关闭服务器连接请求后(3),如果没有收到客户端回应,会再次发送关闭请求。
      客户端最后一个发送请求之后(4),会等待2MSL(2倍最大报文生存时间)才真正关闭socket,因为这次消息很可能由于网络延迟或者意外而没有被服务器收到,如果马上关闭socket就无法再接收到服务器端发送的超时连接请求。
    3.TCP/IP

    TCP/IP 是供已连接因特网的计算机进行通信的通信协议。
    TCP/IP 指传输控制协议(传输层)/网际协议(网络层)
    TCP/IP 定义了电子设备(比如计算机)如何连入因特网,以及数据如何在它们之间传输的标准。
    TCP/IP传输数据相关概念:

    • 子网掩码:规定IP地址哪部分是网络地址和主机地址。
      https://baijiahao.baidu.com/s?id=1606474671793061553&wfr=spider&for=pc
    • 路由器(网关):是用于连接多个逻辑上分开的网络,当数据从一个子网传输到另一个子网时,可通过路由器的路由功能来完成。
    • ARP协议:是根据IP地址获取物理地址(网卡地址)的一个TCP/IP协议。
    • NAT协议:NAT网络地址转换(Network Address Translation)属接入广域网(WAN)技术,是一种将私有(保留)地址转化为合法IP地址的转换技术,它被广泛应用于各种类型Internet接入方式和各种类型的网络中。原因很简单,NAT不仅完美地解决了lP地址不足的问题,而且还能够有效地避免来自网络外部的攻击,隐藏并保护网络内部的计算机。
    • 交换机:局域网交换机指的是用在交换式局域网内进行数据交换的设备。

    eg:一台普通的内网主机浏览器输入www.baidu.com的过程:
    浏览器(客户端)发起请求,www.baidu.com通过DNS服务器解析出IP地址,加上浏览器的端口号8080,作为目的地址(服务器端)地址;
    发起请求的主机向局域网交换机请求数据,此时目的MAC地址是交换机的MAC地址,因为并不知道baidu服务器的MAC地址。
    (如果请求数据是局域网内部的主机,则此时通过交换机就可以找到目的主机的MAC地址)
    交换机再去公网网关路由器请求数据,此时的目的MAC地址被交换机修改为默认网关的MAC地址,通过路由算法,逐步交换找到baidu网关的MAC地址,然后通过交换机的MAC交换找到服务器主机MAC地址才真正建立起连接;
    (找到后会在客户端主机做该IP地址的MAC缓存)
    传输层建立TCP连接,三次握手;
    baidu发送HTTP协议规定的数据格式给客户端浏览器,浏览器按照HTTP规范解析数据展示;
    传输层TCP四次挥手断开连接。

    二.一些原理

    1.闭包

    1.闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)(想想Erlang的外层函数传入一个参数a, 内层函数
    依旧传入一个参数b, 内层函数使用a和b, 最后返回内层函数)
    2.函数嵌套并且函数的返回值为内部函数返回值函数时,可以成为闭包。

    #函数名其实就是一个指针变量,可以作为返回值和参数
    """
    函数作为返回值
    """
    def func():
        def innerfunc():
            print("innerfunc")
        return innerfunc
    f=func()
    f() #innerfunc
    
    """
    函数作为参数
    """
    def paramfunc():
        print("paramfunc")
    def func(f):
        f()
    func(paramfunc) #paramfunc
    
    """
    闭包的基本使用:
    内部函数使用外部函数的参数
    """
    def func(x):
        def innerfunc():
            print(x*10)
        return innerfunc
    f=func(10)
    f()  #20
    
    """
    闭包内部函数修改外部函数的值是需要使用nonlocal修饰,
    否则使用赋值运算相当于直接定义一个内部函数的同名变量
    """
    def func(x):
        def innerfunc():
            #nonlocal x
            x=2
            print("innerfunc-x=%d"%x)
        innerfunc()
        print("func-x=%d"%x)
        return innerfunc
    func(10)
    #innerfunc-x=2
    #func-x=10
    
    def func(list):
        def innerfunc():
            list.append(3)
            print("innerfunc-x=%s"%list)
        innerfunc()
        print("func-x=%s"%list)
        return innerfunc
    func([1,2]) 
    
    #innerfunc-x=[1, 2, 3]
    #func-x=[1, 2, 3]
    
    """
    还得注意一个点就是python的函数只有在执行时,才会去找函数体里的变量的值
    """
    flist = []
    for i in range(3):
        def foo(x):
            print(x+i)
        flist.append(foo)
    for f in flist:
        f(2) #4,4,4
    
    flist2 = []
    for j in range(3):
        def foo(x,y=j):
            print(x+y)
        flist2.append(foo)
    for f in flist2:
        f(2) #2,3,4
    

    闭包内部函数可以独享外部函数传递的数据,并做处理,这个地方比全局变量更有优势,全局变量可以被外部函数使用和修改

    2.装饰器

    装饰器是 Python 的一个重要部分。简单地说:他们是利用闭包特性修改其他函数的功能的函数。

    """
    装饰器原理:使用decf函数强行修改fc指向,给fc函数添加处理
    """
    def decf(f):
        def nn():
            print("decf")
            f()
        return nn
    
    def fc():
        print("fc")
    
    #修改fc的指向
    fc=decf(fc)
    fc()
    

    decf
    fc

    """
    装饰器基本使用
    """
    def decfunc(func):
        print("start dec")
        def noname():
            print("decfunc")
            func()
        return noname
    
    """
    1.相当于 orifunc=decfunc(orifunc),修改函数指向
    2.编译时装饰,而不是调用时装饰
    """
    @decfunc
    def orifunc():
        print("orifunc")
    
    orifunc()
    

    start dec
    decfunc
    orifunc

    """
    对有参函数加装饰器
    """
    def decfunc(func):
        def noname(n):
            print("decfunc")
            func(n)
        return noname
    
    @decfunc
    def orifunc(num):
        print("orifunc:%d"%num)
    
    orifunc(10)
    

    decfunc
    orifunc:10

    """
    对不定长有参函数加装饰器
    """
    def decfunc(func):
        def noname(*args,**kwargs):
            print("decfunc")
            func(*args,**kwargs)
        return noname
    
    @decfunc
    def orifunc(num,*args,**kwargs):
        print("num:%d"%num)
        print("args:",args)
        print("kwargs:",kwargs)
    
    orifunc(1)
    orifunc(1,2)
    orifunc(1,2,key=3)
    

    decfunc
    num:1
    args: ()
    kwargs: {}
    decfunc
    num:1
    args: (2,)
    kwargs: {}
    decfunc
    num:1
    args: (2,)
    kwargs: {'key': 3}

    """
    对有返回值函数加装饰器
    """
    def decfunc(func):
        def noname(*args,**kwargs):
            print("decfunc")
            return func(*args,**kwargs)
        return noname
    
    @decfunc
    def orifunc(*args,**kwargs):
        print("args:",args)
        print("kwargs:",kwargs)
        return "ZS"
    
    res=orifunc(1)
    print(res)
    

    decfunc
    args: (1,)
    kwargs: {}
    ZS

    """通用装饰器"""
    def decfunc(func):
        def noname(*args,**kwargs):
            return func(*args,**kwargs)
        return noname
    
    """带参数装饰器"""
    
    def decp(params):
        def call_func(func):
            def noname(*args,**kwargs):
                print("decp-%s"%params)
                return func(*args,**kwargs)
            return noname
        return call_func
    
    @decp("zs")
    def funcp():
        print("funcp--")
    
    funcp()
    

    decp-zs
    funcp--

    """多个装饰器"""
    def dec1(func):
        def noname(*args,**kwargs):
            print("dec1")
            return func(*args,**kwargs)
        return noname
    
    def dec2(func):
        def noname(*args,**kwargs):
            print("dec2")
            return func(*args,**kwargs)
        return noname
    
    #先装饰desc2,再装饰desc1,调用顺序就是先desc1,再desc2
    @dec1
    @dec2
    def func():
        print("function")
    
    func()
    

    dec1
    dec2
    function

    """类装饰器"""
    
    class decclass():
        def __init__(self,func):
            self.func=func
        def __call__(self, *args, **kwargs):
            print("decclass")
            return self.func()
    
    #相当于 funct=decclass(funct)  funct()->对象()调用call方法
    @decclass
    def funct():
        print("funct")
    
    funct()
    

    decclass
    funct

    3.元类

    1.类也是对象,元类就是用来创建这些类(对象)的,元类就是类的类。
    2.元类的主要目的就是为了当创建类时能够自动地改变类。
    3.元类应用在ORM框架中,给模型类添加处理方法和映射关系。

    """
    元类通过type进行创建
    a对象是A类创建的,A类是type类创建的,type类是type类创建的
    """
    class A():
        pass
    
    a=A()
    
    print(a.__class__)
    print(a.__class__.__class__)
    print(a.__class__.__class__.__class__)
    
    """
    通过type函数创建类
    """
    class Person():
        pass
    
    class Student(Person):
        count=0
        def show(self):
            print("student")
    
    stu=Student()
    stu.show()
    
    
    def show(self):
        print("student")
    
    Stu=type("Student",(Person,),{"count":0,"show":show})
    stu=Stu()
    stu.show()
    
    
    """
    通过MetaSporter类修改Sporter创建方式(不指定默认type创建)
    """
    class MetaSporter(type):
        def __new__(cls, class_name,class_parents,class_attr):
            attrs = ((name, value) for name, value in class_attr.items()
            #改变公有变量为大写
            if not name.startswith('__'))
            uppercase_attr = dict((name.upper(), value) for name, value in attrs)
            return type.__new__(cls,class_name,class_parents,uppercase_attr)
    
    
    class Sporter(metaclass=MetaSporter):
        name="MVP"
    
    sporter=Sporter()
    print(sporter.NAME)
    

    <class 'main.A'>
    <class 'type'>
    <class 'type'>
    student
    student
    MVP

    三.Redis

    1.Redis概述

    1.Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
    2.性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
    3.原子 – Redis的所有操作都是原子性的。
    4.用于服务器缓存,计数器等。

    2.安装配置

    http://www.runoob.com/redis/redis-install.html

    3.数据类型和操作

    1.Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(有序集合)。
    2.string 是 redis 最基本的类型,一个 key 对应一个 value。
    string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。
    string 类型的值最大能存储 512MB。

    基本操作:
    http://www.runoob.com/redis/redis-data-types.html

    4.Python使用Redis

    1.启动redis-server模块
    cd redis/src
    ./redis-server
    通过ps -x|grep redis 查看
    2.安装导入redis模块
    3.使用

    import redis
    
    def main():
        rs = redis.StrictRedis(host="127.0.0.1",port="6379",db=0)
        name = rs.get("name")
        print(name)
        res=rs.set("name","zsy")
        print(res)
        name=rs.get("name")
        print(name)
    
    if __name__ == '__main__':
        main()
    

    None
    True
    b'zsy'

    四.爬虫

    使用requests模块请求网络数

    import requests
    import json
    
    """
    基本使用requests模块获取请求头和响应头
    """
    # url="{}{}".format("http://","www.baidu.com") #格式化字符串
    # response=requests.get(url)
    # print("response:%s"%response.headers)
    # print("resquest:%s"%response.request.headers)
    # print(response.content.decode())
    
    """
    伪造请求头header
    """
    # header={"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"}
    # response=requests.get(url,headers=header)
    # print(response.content.decode())
    
    
    """
    post请求体添加
    """
    # url="{}".format("https://api.taotiangou.cn/api2_1/index/getIndexIcon")
    # headers={}
    # data={"userid":"189"}
    # response=requests.post(url,headers=headers,data=data)
    # #print(response.content.decode())
    #转成json打印
    # dict=json.loads(response.content.decode())
    # print(dict["data"][0]["a_name"])
    
    """
    使用代理:
    让服务器以为不是同一个客户端请求;防止真实地址泄漏
    """
    # proxies={"http":"http://27.42.173.133"}
    # response=requests.get(url,proxies=proxies)
    
    """
    cookie添加访问登录页面
    """
    
    url="{}".format("https://pan.baidu.com/disk/home?#/all?path=%2F&vmode=list")
    #第一种方法:直接header中写入cookie
    headers={"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
            "Cookie":"PSTM=1525329664; BIDUPSID=A33CF2B8C662B817DF7F62AE990D655C; PANWEB=1; MCITY=-%3A; BAIDUID=70FA8F8866B423880A1CA29BC1C68FCE:FG=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDCLND=x9MVHACLFgvF9IL7rIVTLM2OQhjVDfhmCW8C%2FihLVLw%3D; BDUSS=3Q3OX5VYUFUNkFNeC1wUnpwb21pSDh-MkFFd3JMU3h0SUZNZmlGfkl5dW9uM0JjQVFBQUFBJCQAAAAAAAAAAAEAAACj7KhNemhvdXNpeWFuZzE5OTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKgSSVyoEklcQ; pan_login_way=1; STOKEN=b8eccf9e1b192287d4486db9afd6a585a8022bdc2cc6586f57a938a8f9c28b6f; SCRC=d43dcdf89116b6b96ed8e3224a76acac; pgv_pvi=160503808; SE_LAUNCH=5%3A25806433_0%3A25806433; Hm_lvt_7a3960b6f067eb0085b7f96ff5e660b0=1548033802,1548034171,1548034218,1548394494; cflag=13%3A3; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; delPer=0; PSINO=1; locale=zh; pgv_si=s8925985792; H_PS_PSSID=1456_21091_20697_28328_28414_22072; BCLID=8267917567788901312; BDSFRCVID=oskOJeC62G-qlT69srwwuGzxamj5nTnTH6aoH36b11HYuz94DD82EG0PeM8g0Kub1eJMogKKyeOTHu8F_2uxOjjg8UtVJeC6EG0P3J; H_BDCLCKID_SF=tJIJoK_hfIK3fP36q4jqMJFtKh5yhnFXKKOLVb7b2h7keq8CDxtVKtA7jGrebJbfbmvEXnjE2D5_Sbr2y5jHhUvyjxKDJxvkb6L8_pbgfIopsIJMbfFWbT8U5fKDKxTuaKvia-THBMb1fDnDBT5h2M4qMxtOLR3pWDTm_q5TtUt5OCcnK4-Xj533DabP; Hm_lpvt_7a3960b6f067eb0085b7f96ff5e660b0=1548411429; PANPSC=16507912538981936925%3AMH68bVsDvKL4sE9jqMmgcqikII2LTYQX6iJWjf1IM76iE4uyuiKDw%2FFMne%2FXPWb6IL1H0PxEv92SQhzndJOhXsk9gyF%2FWtZZ82toIHXFJKL2daqLHTAOegPMsbEIX3KNyFMq753BNv%2Bev3JCgJ4cjzyDU9xFytyIxnT2tA7ZiDW928MbUB6%2BRw%3D%3D"}
    
    #第二种方法:把cookie值转成字典使用请求参数传递
    cookiestr="PSTM=1525329664; BIDUPSID=A33CF2B8C662B817DF7F62AE990D655C; PANWEB=1; MCITY=-%3A; BAIDUID=70FA8F8866B423880A1CA29BC1C68FCE:FG=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDCLND=x9MVHACLFgvF9IL7rIVTLM2OQhjVDfhmCW8C%2FihLVLw%3D; BDUSS=3Q3OX5VYUFUNkFNeC1wUnpwb21pSDh-MkFFd3JMU3h0SUZNZmlGfkl5dW9uM0JjQVFBQUFBJCQAAAAAAAAAAAEAAACj7KhNemhvdXNpeWFuZzE5OTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKgSSVyoEklcQ; pan_login_way=1; STOKEN=b8eccf9e1b192287d4486db9afd6a585a8022bdc2cc6586f57a938a8f9c28b6f; SCRC=d43dcdf89116b6b96ed8e3224a76acac; pgv_pvi=160503808; SE_LAUNCH=5%3A25806433_0%3A25806433; Hm_lvt_7a3960b6f067eb0085b7f96ff5e660b0=1548033802,1548034171,1548034218,1548394494; cflag=13%3A3; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; delPer=0; PSINO=1; locale=zh; pgv_si=s8925985792; H_PS_PSSID=1456_21091_20697_28328_28414_22072; BCLID=8267917567788901312; BDSFRCVID=oskOJeC62G-qlT69srwwuGzxamj5nTnTH6aoH36b11HYuz94DD82EG0PeM8g0Kub1eJMogKKyeOTHu8F_2uxOjjg8UtVJeC6EG0P3J; H_BDCLCKID_SF=tJIJoK_hfIK3fP36q4jqMJFtKh5yhnFXKKOLVb7b2h7keq8CDxtVKtA7jGrebJbfbmvEXnjE2D5_Sbr2y5jHhUvyjxKDJxvkb6L8_pbgfIopsIJMbfFWbT8U5fKDKxTuaKvia-THBMb1fDnDBT5h2M4qMxtOLR3pWDTm_q5TtUt5OCcnK4-Xj533DabP; Hm_lpvt_7a3960b6f067eb0085b7f96ff5e660b0=1548411429; PANPSC=16507912538981936925%3AMH68bVsDvKL4sE9jqMmgcqikII2LTYQX6iJWjf1IM76iE4uyuiKDw%2FFMne%2FXPWb6IL1H0PxEv92SQhzndJOhXsk9gyF%2FWtZZ82toIHXFJKL2daqLHTAOegPMsbEIX3KNyFMq753BNv%2Bev3JCgJ4cjzyDU9xFytyIxnT2tA7ZiDW928MbUB6%2BRw%3D%3D"
    
    #通过字符串截取获取把字符串转成字典
    cookies={kv.split("=")[0]:kv.split("=")[1] for kv in cookiestr.split(";")}
    response=requests.post(url,headers=headers,cookies=cookies)
    print(response.content.decode())
    
    """
    cookie转字典
    """
    def getcookie():
        url="{}".format("http://www.runoob.com/python/att-string-format.html")
        response=requests.get(url)
        print("cookie:%s"%response.cookies)
        dict=requests.utils.dict_from_cookiejar(response.cookies)
        print("dict:{}".format(dict))
    
    """
    访问HTTPS不安全网站,设置超时时间
    """
    def settime():
        url="{}".format("https://pan.baidu.com",verify=False,timeout=10)
        response=requests.get(url)
        print("status_code:{}".format(response.status_code))
    

    使用json模块处理json数据

    import requests
    import json
    #通过手机豆瓣找到电影列表json(去掉callback=json字段)
    url="{}".format("https://m.douban.com/rexxar/api/v2/subject_collection/movie_free_stream/items?os=ios&start=0&count=8&loc_id=108288&_=1548485894537") #格式化字符串
    header={"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"
            ,"Referer":"https://m.douban.com/movie/"
            }
    response=requests.get(url,headers=header)
    
    #json转对象(字典)
    dbjson=json.loads(response.content.decode())
    
    with open("douban.json","w",encoding="utf-8") as f:
        #json对象写入文件
        json.dump(dbjson,f,ensure_ascii=False,indent=4)
    

    使用re模块处理html标签
    正则表达式
    http://www.runoob.com/python3/python3-reg-expressions.html

    pattern = re.compile("<p>.*?</p>")  #预编译
    pattern.match() #从头查找
    pattern.findall() #找所有
    pattern.search() #找一个
    pattern.sub() #替换
    

    使用lxml模块提取html/xml数据
    1.xpath语法介绍

    • / 从根节点选取
    • // 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
    • . 选取当前节点
    • .. 选取当前节点的父节点
    • @ 选取属性
    """
    以 https://m.douban.com/movie/ 为例子
    """
    #1.获取文本
    /html/head/title/text()
    #2.获取属性
    /html/head/link/@rel
    #3.筛选
    //div[@class="down-app"]
    #4.获取热映电影名称列表
    //div[@class="card"]//span[@class="item-title"]/text()
    #5.可以使用通配符*,所有节点的所有属性
    //*[@*]
    

    2.lxml模块

    from lxml import etree
    
    htmlStr="""
    <div>
        <ul>
            <li><span>first</span><a href='first.cn'></a></li>
            <li><span>second</span><a href='second.cn'></a></li>
            <li><span>third</span><a href='third.cn'></a></li>
        </ul>
    </div>
    """
    
    #字符串转成HTML对象
    html=etree.HTML(htmlStr)
    #print(html)
    
    #使用xpath语法获取li元素
    li=html.xpath("//li")
    
    #遍历li列表,使用xpath截取文本和链接
    for e in li:
        text=e.xpath("./span/text()")
        href=e.xpath("./a/@href")
        if(len(text)>0):
            print(text[0])
        if(len(href)>0):
            print(href[0])
    

    使用Mongodb存储爬虫数据

    MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
    在高负载的情况下,添加更多的节点,可以保证服务器性能。
    MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。
    MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含> > 其他文档,数组及文档数组。

    1.基本操作
    http://www.runoob.com/mongodb/mongodb-tutorial.html
    2.使用pymongo模块进行Python交互

    五.数据分析

    1.matplotlib模块基本使用

    可参考文档:https://matplotlib.org/

    from matplotlib import pyplot as plt
    import random
    import matplotlib
    
    """折线图"""
    def showzhexian():
        #1.设置显示大小和DPI
        plt.figure(figsize=(20,8),dpi=80)
        #2.定义x坐标和y坐标
        x=range(2,100)
        y1=[random.randint(1,100) for i in range(2,100)]
        plt.plot(x,y1,label="y1")
        y2 = [random.randint(1, 100) for i in range(2, 100)]
        plt.plot(x,y2,label="y2")
        #x_ticks_lab=[i for i in list(x)[::2]]
        x_ticks_lab=["s{}".format(i) for i in x]
        #3.重新定义横坐标显示(加入字符串,设置步长,旋转)
        plt.xticks(list(x)[::3],x_ticks_lab[::3],rotation=45)
        #4.设置中文字体
        font = {'family': 'Helvetica',
                'weight': 'bold',
                'size': '15'}
        matplotlib.rc("font", **font)
        plt.xlabel("x轴名称",fontdict=font)
        plt.ylabel("y轴名称",fontdict=font)
        #5.设置网格
        plt.grid()
        #6.显示图例
        plt.legend()
        #7.展示
        plt.show()
    
    """散点图"""
    def showsandian():
        plt.figure(figsize=(20, 8), dpi=80)
        x = range(2, 100)
        y = [random.randint(1, 100) for i in range(2, 100)]
        plt.scatter(x,y)
        plt.show()
    
    """柱状图"""
    def showzhuzhuang():
        plt.figure(figsize=(20, 8), dpi=80)
        x = range(2, 100)
        y = [random.randint(1, 100) for i in range(2, 100)]
        #竖向
        #plt.bar(x,y)
        #横向
        plt.barh(x,y)
        plt.show()
    
    """直方图"""
    def showzhifang():
        plt.figure(figsize=(20, 8), dpi=80)
        #离散数据
        num = [random.randint(1, 100) for i in range(2, 100)]
        #离散数据分组组数
        numcount=10
        plt.hist(num,numcount)
        plt.show()
    
    if __name__ == '__main__':
        showzhifang()
    
    2.numpy基本使用

    http://www.runoob.com/numpy/numpy-tutorial.html

    import numpy as np
    
    """创建"""
    def create():
        #numpy创建的数据类型为numpy.ndarray,可以通过数组和range初始化
        t1=np.array([1,2,3])
        print(type(t1),t1)
        t2=np.array(range(10))
        print(type(t2),t2)
        t3=np.arange(1,10,2)
        print(type(t3),t3)
    
        #创建时元素类型可以指定修改,包含比Python更多的类型,比如int64,complex...
        t4=np.array(range(5),dtype=float)
        print(t4.dtype,t4)
        t4=t4.astype(dtype="i4")
        print(t4.dtype,t4)
    
        #初始化元素为0,1或者随机数值的二维形状的numpy
        t5=np.empty([2,2],dtype="i4")
        print(t5)
        t6=np.zeros([3,3],dtype=float)
        print(t6)
        t7=np.ones([2,3])
        print(t7)
    
    def operate():
        """切片和基本索引"""
        t1=np.array([[1,2,3,2,1],[4,5,6,5,4],[7,8,9,8,7]])
        print(t1)
        #转置
        print(t1.transpose())
        print(t1.T)
        #取某个数据
        print(t1[0][2])
        print(t1[0,2])
        #取不相邻多个点 (0,1),(2,2),(1,2)三个点
        print(t1[[0,2,1],[1,2,2]])
        #取某一行
        print(t1[1])
        #取连续行(1-2行),切片方式
        print(t1[1:3:])
        #取不连续行
        print(t1[[0,2]])
        #取不连续多列,第1,3列
        print(t1[:,[0,2]])
        #取多行多列,第2行-3行,2-3列(交叉点)
        print(t1[1:3,1:3])
    
        """布尔索引"""
        #取t1<5的数据并赋值为0
        t1[t1<5]=0
        print(t1)
    
    def operate2():
        t1=np.arange(10)
        print(t1)
        t2=np.arange(10,20,1)
        print(t2)
        #水平拼接
        t3=np.vstack((t1,t2))
        print(t3)
        #垂直拼接
        t4=np.hstack((t1,t2))
        print(t4)
        #修改数组形状,切分为(2,5)形状的二维数组
        t5=t1.reshape(2,5)
        print(t5)
        #迭代
        for x in np.nditer(t1):
            print(x,end="")
    
    """广播机制"""
    def calculate():
        #维度相同的对应位置进行计算
        t1=np.array([1,2,3,4])
        t2=np.array([9,8,7,6])
        rs=t1+t2
        print(rs)
        #维度不同的
        """
        当在两个数组上操作时,NumPy在元素级别比较它们的形状。它从尾随的维度开始,并朝着前进的方向前进。两个维度兼容,当
        他们是平等的,或者其中之一是1
        如果不满足这些条件,则抛出ValueError: frames are not aligned异常,指示数组具有不兼容的形状。结果数组的大小是沿着输入数组的每个维度的最大大小。
        """
        t3=np.array([[1,2,3,2,1],[4,5,6,5,4],[7,8,9,8,7]])
        t4=np.array([1,1,1,1,1])
        t5=np.array([[3],[3],[3]])
        print(t3.shape,t4.shape,t5.shape)
        print(t3)
        #相加之后,每个大数组的元素都会和小数组元素相加
        rs2=t3+t4
        print(rs2)
        rs3=t3+t5
        print(rs3)
    
    if __name__ == '__main__':
        calculate()
    
    3.pandas基本使用

    参考文档:https://www.yiibai.com/pandas

    import pandas as pd
    import numpy as np
    
    """Series表示一个带标签index的一维数组"""
    def testseries():
        #创建一个Series数据(type==pandas.core.series.Series)
        #使用list初始化
        t1=pd.Series([3,2,9,7,6])
        print(t1)
        #使用dict初始化
        t2=pd.Series({"key1":"value1","key2":"value2","key3":"value3"})
        print(t2)
    
        #使用切片和索引获取数据
        print(t1[1])
        print(t2["key2"])
        print(t1[[1,2,3]])
        print(t2[["key1","key3"]])
        print(t1[1:3:])
        print(t2[2:])
        print(t1[t1>5])
    
        #迭代标签index和values
        for i in t1.index:
            print(i,end=" ")
    
        for i in t1.values:
            print(i,end=" ")
    
    """DataFrame创建和常用方法"""
    def createDataFrame():
        #创建DataFrame
        t1=pd.DataFrame(np.arange(12).reshape(3,4))
        print(t1)
        t2=pd.DataFrame(np.arange(12).reshape(4,3),index=["A","B","C","D"],columns=["E","F","G"])
        print(t2)
        t3=pd.DataFrame({"key1":["value1","value11"],"key2":["value2","value22"],"key3":["value3","value33"]})
        print(t3)
        t4 = pd.DataFrame([{"k1":"v1","k2":"v2","k3":"v3"},{"k1":"sv1","k2":"sv2"},{"k1":"tv1","k2":"tv2"}])
        print(t4)
    
        #DataFrame常用属性和方法
        print(t4.index)
        print(t4.columns)
        print(t4.values)
        print(t4.info())
        print(t1.describe())
        t1=t1.sort_values(by=0,ascending=False) #排序
        print(t1.head(1)) #去前1行元素
    
    """取DataFrame数据"""
    def getDataFrame():
        t1=pd.DataFrame(np.arange(32).reshape(8,4),index=list("abcdefgh"),columns=list("ABCD"))
        print(t1)
        #使用索引和切片取数据
        #.loc()基于标签 .iloc()基于整数
        print(t1.loc["a"])
        print(t1.loc[:,"A"])
        print(t1.loc[["a","d","e"]])
        print(t1.loc[["b","e"],["B","D"]])
        print("*"*20)
        print(t1.iloc[1:3,2:4])
    
    """NAN的处理"""
    def DataFrameNAN():
        t1 = pd.DataFrame(np.arange(16).reshape(4, 4), index=list("abcd"), columns=list("ABCD"))
        print(t1)
        t1=t1.reindex(list("abcde"))
        print(t1)
        #判断是不是nan数据
        print(t1.isnull())
        #在求和数据时,NA将被视为0;如果数据全部是NA,那么结果将是NA
    
        #填充NAN数据
        print(t1.fillna(0))
        #删除NAN数据
        print(t1.dropna())
    
    
    if __name__ == '__main__':
        DataFrameNAN()
    

    一个DataFrame数据相当于一个包括字段和index的关系数据库的表,所以同样有拥有sql中join(连接),groupby(分组)操作。

    """DataFrame sql operation"""
    def DataFrameSqlOp():
        left = pd.DataFrame({
            'id': [1, 2, 3, 4, 5],
            'Name': ['Alex', 'Amy', 'Allen', 'Alice', 'Ayoung'],
            'subject_id': ['sub1', 'sub2', 'sub4', 'sub6', 'sub5']})
        right = pd.DataFrame(
            {'id': [1, 2, 3, 4, 5],
             'Name': ['Billy', 'Brian', 'Bran', 'Bryce', 'Betty'],
             'subject_id': ['sub2', 'sub4', 'sub3', 'sub6', 'sub5']})
        #on=连接字段
        #how=left(左连接),right(右连接),outer(外连接),inner(内连接)
        rs = pd.merge(left, right, how='outer', on='subject_id')
        print(rs)
    
        t1=pd.DataFrame({
            "city":["BJ","TY","BJ","TY","BJ"],
            "person":["KKW","DZ","WW","ZS","MM"],
            "age":[18,38,29,10,99]
        })
        print(t1)
        #分组
        rs=t1.groupby(by="city")
        #分组数据集
        print(rs.groups)
        #分组后数据
        print(rs.get_group("BJ"))
        #分组统计
        print(rs.count())
        #聚合操作,求和
        print(rs["age"].agg(np.sum))
    
    """索引"""
    def DataFrameIndex():
        t1=pd.DataFrame(np.arange(18).reshape(3,6),index=list("abc"),columns=list("ABCDEF"))
        print(t1)
        #查看索引
        print(t1.index)
        #重新设置索引
        print(t1.reindex(list("abcd")))
        #设置A列为索引且不删除A列数据
        print(t1.set_index("A",drop=False))
        #设置A列为索引且删除A列数据
        print(t1.set_index("A", drop=True))
        #设置A,B列为复合索引
        print(t1.set_index(["A","B"]))
    
        #从复合索引的Series和DataFrame中取值
        sr=t1.set_index(["A", "B"])
        #取C一列结果为Series
        print(sr["C"])
        print(sr["C"].loc[6].loc[7])
        print(sr["C"][6,7])
        #交换复合索引
        sr=sr.swaplevel()
        print(sr["C"])
        #DataFrame
        print(sr.loc[13].loc[12])
    

    时间函数

    """时间"""
    def PandasTime():
        #按照起始时间输出
        start = pd.datetime(2017, 11, 1)
        end = pd.datetime(2017, 11, 5)
        dates = pd.date_range(start, end)
        print(dates)
        # 按照指定周期输出
        datelist = pd.date_range('2020/11/21', periods=5)
        print(datelist)
        #按照频率M输出
        datelist = pd.date_range('2020/11/21', periods=5, freq='M')
        print(datelist)
        #按照工作日输出
        datelist = pd.bdate_range('2011/11/03', periods=5)
        print(datelist)
    
        #str->Timestamp类型转化
        print(type("20190101"))
        print(type(pd.to_datetime("20190101")))
    

    五.机器学习

    1.特征工程

    特征是数据中抽取出来的对结果预测有用的信息,可以是文本或者数据。
    关键步骤是数据采集(清洗,采样),特征处理
    数据采集:哪些数据对最后的结果预测有帮助就采集哪些数据,处理其中脏数据和过多缺省数据,采样正负均衡的数据。
    特征处理,包括数值型,类别型,时间型数据的处理。

    可以使用scikit-learn模块,基于numpy数据做统一处理。

    对于特征为数值型数据的预处理(此时每个特征的重要性看为同等重要):

    • 归一化
    • 标准化
    from sklearn.preprocessing import MinMaxScaler
    from sklearn.preprocessing import StandardScaler
    
    """数值数据特征预处理"""
    #使用MinMaxScaler进行归一化处理
    """
    按列进行x=(x-min/max-min)*(mx-mi)+mi
    其中min=该列最小数值
       max=该列最大数值
       mx=要求结果集范围最大上限,默认1
       mi=要求结果集范围最小下限,默认0
       
    特点:异常数据(极端值)对结果影响大
    """
    def minmaxsc():
        mm=MinMaxScaler(feature_range=(2,3)) #默认(0,1)
        narray =[[53,9,22],[18,66,70],[12,32,91]]
        data=mm.fit_transform(narray)
        print(data)
    
    #使用StandardScaler行标准化处理
    """
    按列进行x=(x-mean)/标准差
    其中mean=该列平均值
       方差=(x1-mean)²+(x2-mean)²+.../n,标准差=方差的平方根
       每一列计算的结果相加为0
    特点:异常数据对结果影响小
         标准差反应数据的稳定性,越大表示数据波动性越强
    """
    def standarsc():
        ss=StandardScaler()
        narray =[[53,9,22],[18,66,70],[12,32,91]]
        data=ss.fit_transform(narray)
        print(data)
    

    对类别数据特征处理,比如文本数据(one-hot方式):

    • 先进行数据的提取,
    • 再按照规则使用数值表示
    from sklearn.feature_extraction import DictVectorizer
    from sklearn.feature_extraction.text import CountVectorizer
    from sklearn.feature_extraction.text import TfidfVectorizer
    import jieba
    
    """
    字典处理
    构成二维矩阵
    分词的数量代表处理的行索引;数据个数作为列索引
    分词原则是非数值数据直接连接为特征(name=zs),对应的二维数组中满足为1,不满足为0
    数值型数据直接赋值到指定二维数组位置
    """
    def dictvec():
        dv=DictVectorizer(sparse=False)
        data=dv.fit_transform([{"name":"zs","age":18},{"name":"mm","age":24},{"name":"cc","age":28}])
        #数据提取结果
        print(dv.get_feature_names())
        #数据显示样式
        print(data)
    
    """
    文本数据处理-普通方式
    同样分词结果作为行索引,矩阵中的数字代表分词出现的次数
    """
    def countvec():
        cv=CountVectorizer()
        #英文会自动按照空格分词,单字母忽略(认为对预测结果无意义)
        earray=["i am zs,i like mm","she is mm,like zs,hi zs"]
        #中文可以先用jieba模块进行分词处理
        zarray=["我是一个小企鹅,我喜欢吃鱼","我是一个大白熊,我喜欢吃企鹅"]
        temp=[]
        for zh in zarray:
            temp.append(jiebafilter(zh))
        print(temp)
        data=cv.fit_transform(temp)
        #单字母不作为特征抽取的元素
        print(cv.get_feature_names())
        print(data.toarray())
    
    """
    文本数据处理-tfidf更优化的方式
    tfidf方式可以计算出分词的重要性
    一个分词在同一段文字中出现的次数越多,且在整个段落中出现的次数越少,那么越重要
    比如我们,那么,等等之类的分词虽然经常出现,但并不重要
    """
    def tfidfvec():
        tf = TfidfVectorizer()
        zarray = ["我是一个小企鹅,我喜欢吃鱼", "我是一个大白熊,我喜欢吃企鹅","我是大鲨鱼,我喜欢吃大白熊"]
        temp = []
        for zh in zarray:
            temp.append(jiebafilter(zh))
        print(temp)
        data = tf.fit_transform(temp)
        print(tf.get_feature_names())
        print(data.toarray())
    
    #使用jieba模块进行中文分词处理
    def jiebafilter(str):
        list=jieba.cut(str)
        content=" ".join(iter(list))
        return content
    
    

    通过数据抽取或者降维精化特征数据

    在用统计分析方法研究多变量的课题时,变量个数太多就会增加课题的复杂性。人们自然希望变量个数较少而得到的
    信息较多。在很多情形,变量之间是有一定的相关关系的,当两个变量之间有一定相关关系时,可以解释为这两个变量反
    映此课题的信息有一定的重叠。主成分分析是对于原先提出的所有变量,将重复的变量(关系紧密的变量)删去多余,建立
    尽可能少的新变量,使得这些新变量是两两不相关的,而且这些新变量在反映课题的信息方面尽可能保持原有的信息。

    常用方式:

    • 数据特征的抽取
    • 主成分分析之PCA
    from sklearn.feature_selection import VarianceThreshold
    from sklearn.decomposition import PCA
    
    """
    数据抽取
    """
    def varienceth():
        #指定方差为0的列被屏蔽
        vt=VarianceThreshold(threshold=0.0)
        data=vt.fit_transform([[1,2,3],[2,2,3],[3,3,3]])
        print(data)
    
    """
    主成分分析
    PCA主要通过把数据从高维映射到低维来降低特征维度。(投影)
    尽可能的保留能够反映真实特征数据的数据量,且去除重复数据
    """
    def pca():
        #保留90%的有效数据
        pc=PCA(n_components=0.9)
        data=pc.fit_transform([[53,9,22,1],[18,66,70,16],[12,32,91,30],[23,76,45,22]])
        print(data)
        print(data.shape)
    
    2.机器学习算法

    学习方式分为监督式学习和非监督式学习
    在监督式学习下,输入数据被称为“训练数据”,每组训练数据有一个明确的标识或结果,如对防垃圾邮件系统中“垃圾邮件”“非垃圾邮件”,对手写数字识别中的“1“,”2“,”3“,”4“等。在建立预测模型的时候,监督式学习建立一个学习过程,将预测结果与“训练数据”的实际结果进行比较,不断的调整预测模型,直到模型的预测结果达到一个预期的准确率。监督式学习的常见应用场景如分类问题和回归问题。

    • 分类算法处理预测目标为离散型的,比如风险评估,常见算法:K-近邻算法,贝叶斯分类,决策树,随机森林,逻辑回归,神经网络
    • 回归算法处理预测目标为连续行的,比如房价预测,常见算法:线性回归,岭回归
      在非监督式学习中,数据并不被特别标识,学习模型是为了推断出数据的一些内在结构。常见的应用场景包括关联规则的学习以及聚类等。常见算法包括Apriori算法以及k-Means算法。

    开发流程

    • 准备数据(75%用于训练,25%用于测试)
    • 建立模型,明确做的事情
    • 基础数据处理
    • 特征工程
    • 使用合适算法
    • 评估模型
    • 上线API
    from sklearn.datasets import load_iris,fetch_20newsgroups,load_boston
    from sklearn.model_selection import train_test_split
    
    """展示一组机器算法监督类目标离散的数据"""
    def testir():
        li=load_iris()
        #输入数据
        print(li.data)
        #目标数据
        print(li.target)
        #描述
        print(li.DESCR)
        #把数据按照75%的训练数据,25%的测试数据切分
        xtrain,xtest,ytrain,ytest=train_test_split(li.data,li.target,test_size=0.25)
        #75%训练的特征值和目标值
        print(xtrain,ytrain)
        #25%测试的特征值和目标值
        print(xtest,ytest)
    
    """展示一组机器算法监督类目标连续的数据"""
    def testlb():
        lb=load_boston()
        print(lb.data)
        print(lb.target)
    

    K-邻近算法

    k近邻法(k-nearest neighbor, k-NN)是1967年由Cover T和Hart P提出的一种基本分类与回归方法。它的工作原理是:存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

    参考:https://cuijiahua.com/blog/2017/11/ml_1_knn.html

    from sklearn.neighbors import KNeighborsClassifier
    
    def knn():
        li = load_iris()
        xtrain, xtest, ytrain, ytest = train_test_split(li.data, li.target, test_size=0.25)
        #构建一个K=3的K-近邻算法模型
        knn=KNeighborsClassifier(n_neighbors=3)
        #根据拆分的训练特征值和目标值进行计算
        knn.fit(xtrain,ytrain)
        #预测测试数据集
        y_predict=knn.predict(xtest)
        #预测结果和真实结果进行比较
        print("预测结果:%s 实际结果:%s"%(y_predict,ytest))
        #得出准备率
        res=knn.score(xtest,ytest)
        print("准确率:%s"%res)
    

    优点:简单,数据不需要迭代训练
    缺点:计算量大(数据量越大,性能越差);K值定义不准影响结果(过大过小都不好);无法给出数据内在定义。

    使用交叉验证和网格搜索优化找更合适的K值

    def knn():
        li = load_iris()
        xtrain, xtest, ytrain, ytest = train_test_split(li.data, li.target, test_size=0.25)
    
        knn = KNeighborsClassifier()
        params={"n_neighbors":[3,5,10]}
        gs=GridSearchCV(knn,param_grid=params,cv=2)
        gs.fit(xtrain,ytrain)
        print("测试集准确率:",gs.score(xtest,ytest))
        print("交叉集最好的结果:",gs.best_score_)
        print("选择最好的模型:",gs.best_estimator_)
        print("每个交叉参数集结果:",gs.cv_results_)
    

    个人理解:
    把训练集特征数据构建N维图形中(eg:2个特征就对应一个平面的点,3个特征就对应一个三维空间的点),输入一个未知目标的特征数据组,映射到该图形中,找到附近已知目标特征中的数据,哪个多就选哪个。

    朴素贝叶斯算法

    原理:朴素贝叶斯(naive Bayes)法是是基于贝叶斯定理 和特征条件独立假设的分类方法,对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合分布概率;然后基于此模型,对给定的输入x,再利用贝叶斯定理求出其后验概率最大的输出y。主要用于文本分类。

    基础知识:
    1.概率论中条件概率P(A|B)=满足B条件下A事件的概率
    2.P(A1,A2|B)=P(A1|B)P(A2|B) (A1,A2相互独立)
    3.P(A|B)=P(B|A)
    P(A)/P(B)
    4.如果有的数据为0,使用拉普拉斯平滑,让分子和分母加一个数字,eg:1
    5.精确率:预测结果为正例样本中真实为正例的比例(准)
    召回率:真实为正例中预测结果为正例比例(全)

    参考:https://blog.csdn.net/zhengzhenxian/article/details/79052185

    from sklearn.naive_bayes import MultinomialNB
    from sklearn.metrics.classification import classification_report
    
    """朴素贝叶斯算法"""
    def mnb():
        newsdata=fetch_20newsgroups()
        xtrain, xtest, ytrain, ytest = train_test_split(newsdata.data,newsdata.target,test_size=0.25)
        tf=TfidfVectorizer()
        #fit_transform训练数据,tranform测试数据
        xtrain=tf.fit_transform(xtrain)
        xtest=tf.transform(xtest)
        print(tf.get_feature_names())
        print(xtrain.toarray())
        print(xtest.toarray())
        mnb=MultinomialNB(alpha=1.0)
        mnb.fit(xtrain,ytrain)
        y_predict=mnb.predict(xtest)
        print(y_predict)
        print("准确率:%s"%mnb.score(xtest,ytest))
        print("新闻数据每种类型的准确率和召回率:",classification_report(ytest,y_predict,target_names=newsdata.target_names))
    

    优点:稳定,对缺失值不敏感
    缺点:条件独立性假设

    个人理解:
    适合多分类任务,特征为离散型数据且相互独立,利用概率论基础,统计这些离散型特征数据对目标影响概率,对于未知目标数据,选择最优概率解。

    决策树算法

    参考:https://www.cnblogs.com/yonghao/p/5061873.html

    from sklearn.model_selection import GridSearchCV
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.ensemble import RandomForestClassifier
    
    """决策树算法"""
    def tree():
        newsdata = fetch_20newsgroups()
        xtrain, xtest, ytrain, ytest = train_test_split(newsdata.data, newsdata.target, test_size=0.25)
        tf = TfidfVectorizer()
        # fit_transform训练数据,tranform测试数据
        xtrain = tf.fit_transform(xtrain)
        xtest = tf.transform(xtest)
        #构建决策树
        dtc=DecisionTreeClassifier()
        dtc.fit(xtrain, ytrain)
        y_predict = dtc.predict(xtest)
        print(y_predict)
        print("准确率:%s" % dtc.score(xtest, ytest))
    
        #构建随机森林,使用交叉验证和网格搜索进行最优解寻找
        rf=RandomForestClassifier()
        params={"n_estimators":[120,200,300,500,600],"max_depth":[5,8,10,15]}
        gs=GridSearchCV(rf,param_grid=params,cv=10)
        gs.fit(xtrain,ytrain)
        print("测试集准确率:", gs.score(xtest, ytest))
        print("交叉集最好的结果:", gs.best_score_)
        print("选择最好的模型:", gs.best_estimator_)
        print("每个交叉参数集结果:", gs.cv_results_)
    

    个人理解:
    以信息论为基础,构建一颗子节点按照重要程度下降的决策树(影响越大的结点越接近根节点),对于未知目标的特征数据,按照路径判断最终所属节点。
    其中:如何找到最重要影响特征以及分裂的属性的选择都是利用信息论数学公式决定。

    线性回归

    目标值是连续性数据的算法

    import numpy as np
    from sklearn.linear_model import LinearRegression,SGDRegressor
    from sklearn.linear_model import Ridge
    from sklearn.datasets import load_boston
    from sklearn.model_selection import  train_test_split
    from sklearn.preprocessing import StandardScaler
    from sklearn.metrics import mean_squared_error
    
    def linear():
        lbdata=load_boston()
        xtrain, xtest, ytrain, ytest = train_test_split(lbdata.data, lbdata.target, test_size=0.25)
        #特征值和目标值都进行标准化处理
        #因为维度不同,所以需要初始化两个StandardScaler
        std_x=StandardScaler()
        xtrain=std_x.fit_transform(xtrain)
        xtest=std_x.transform(xtest)
        print(xtrain)
        print(xtest)
        std_y=StandardScaler()
        ytrain=std_y.fit_transform(ytrain.reshape(-1,1))
        ytest=std_y.transform(ytest.reshape(-1,1))
        print(ytrain)
        print(ytest)
        """
        利用矩阵计算,求得最符合的线性函数权重值
        """
        #正规方程
        lr=LinearRegression()
        lr.fit(xtrain,ytrain)
        print("回归系数:",lr.coef_)
        y_predict=lr.predict(xtest)
        print("预测标准化后价格:",y_predict)
        print("预测价格:", std_y.inverse_transform(y_predict))
        print("均方误差",mean_squared_error(std_y.inverse_transform(ytest),std_y.inverse_transform(y_predict)))
        """
        损失函数记录偏差值,通过不断学习减低偏差值优化线性函数权重的方式
        """
        #梯度下降
        sgd=SGDRegressor()
        sgd.fit(xtrain, ytrain)
        print("回归系数:", sgd.coef_)
        sgd_y_predict = sgd.predict(xtest)
        print("预测标准化后价格:",sgd_y_predict)
        print("预测价格:", std_y.inverse_transform(sgd_y_predict))
        print("均方误差", mean_squared_error(std_y.inverse_transform(ytest), std_y.inverse_transform(sgd_y_predict)))
    
        """
        使用正则化方式优化过拟合和欠拟合的问题
        """
        #岭回归
        rd = Ridge(alpha=1.0)
        rd.fit(xtrain, ytrain)
        print("回归系数:", rd.coef_)
        rd_y_predict = rd.predict(xtest)
        print("预测标准化后价格:", rd_y_predict)
        print("预测价格:", std_y.inverse_transform(rd_y_predict))
        print("均方误差", mean_squared_error(std_y.inverse_transform(ytest), std_y.inverse_transform(rd_y_predict)))
    

    个人理解:
    根据训练数据的特征值和目标值,以线性代数为基础,进行矩阵计算,推测线性函数参数。线性函数:y=k1x1+k2x2+k3x3...+b。

    逻辑回归

    目标值是二分类数值(结果是是否的问题)

    from sklearn.linear_model import LinearRegression,SGDRegressor,LogisticRegression
    from sklearn.model_selection import  train_test_split
    from sklearn.preprocessing import StandardScaler
    from sklearn.metrics.classification import classification_report
    
    def logic():
        """
        可以使用正则化优化
        """
        # 正规方程
        lr = LogisticRegression()
        lr.fit(xtrain, ytrain)
        print("回归系数:",lr.coef_)
        y_predict = lr.predict(xtest)
        #因为目标值是分类定值,所以可以使用准确率和召回率表示结果
        print("准确率:",lr.score(xtest,ytest))
        print("召回率:",classification_report(ytest,y_predict,target_names=lbdata.target_names))
    

    个人理解:
    以线性回归算法为基础,利用signomid函数做处理,使得预测结果为二分类数值。

    参考:https://blog.csdn.net/ustbbsy/article/details/80423294

    保存估算模型和使用模型API

    from sklearn.externals import joblib
    
    lr=LinearRegression()
    lr.fit(xtrain,ytrain)
    #保存模型
    joblib.dump(lr,"./linemodel.pkl")
    #获取模型
    linemodel=joblib.load("./linemodel.pkl")
    y_predict = linemodel.predict(xtest)
    

    K-Means

    没有明确的目标值,把数据分为指定数目的类别。

    参考:https://www.cnblogs.com/bourneli/p/3645049.html

    from sklearn.cluster import KMeans
    from sklearn.metrics import silhouette_score
    
    def kmeans():
        #假定6个3特征数据
        data=np.array([[15,23,35],[123,213,123],[12,321,321],[876,6,678],[93,56,37],[213,3,5]])
        print(data.shape)
        print(data)
        #使用K-means聚合这6个数据为3类
        km=KMeans(n_clusters=3)
        km.fit(data)
        predict=km.predict(data)
        print(predict)
        #使用轮廓系数评估该模型的准确率[-1,1]
        res=silhouette_score(data,predict)
        print("聚类评估结果:",res)
    

    个人理解:
    给定一个没有目标值的特征数据集和分类数目K,从随机K个中心点开始,利用距离和平均值公式,不断优化中心点位置,直到耿更好的满足轮廓系数评估的结果。

    七.深度学习

    使用深度学习框架TensorFlow进行
    TensorFlow属于计算密集型框架

    涉及到大量数据计算属于计算密集型(CPU/GPU密集)
    涉及到多网络,磁盘操作属于I/O密集型

    1.TensorFlow基本介绍
    • Graph(图)
      【Tensor(TensorFlow中数据格式)+Operation(TensorFlow中函数统称)】集合体
    • Session(会话)
      运行图的结构,掌握资源,分配资源;默认只能运行一个图(默认图),使用run方法运行图的结构
    • Tensor(张量)
      TensorFlow中基本数据结构,对numpy(ndarray)的封装,包含【名字,形状,数据类型】
    import tensorflow as tf
    
    """使用TensorFlow进行加法运算"""
    def add():
        a=tf.constant(3)
        b=tf.constant(5)
        #a,b,sum均为Tensor类型数据
        print("a:%s b:%s"%(a,b))
        sum=tf.add(a,b)
        print("sum:",sum)
    
        #指定不定shape
        plt=tf.placeholder(dtype=tf.float32,shape=[None,3])
    
        """
        fetches-列表参数,指定获取图中哪些Tensor
        feed_dict-字典参数,结合placeholder使用
        """
        with tf.Session() as session:
            res=session.run(fetches=[a,sum,plt],feed_dict={plt:[[3,2,3],[1,2,3]]})
            print(res)
            print("a.shape:%s a.name:%s a.op:%s"%(a.shape,a.name,a.op))
            print("plt.shape:%s plt.name:%s plt.op:%s"%(plt.shape, plt.name, plt.op))
    
    """图"""
    def graph():
        #默认图
        print("tf-default-graph:", tf.get_default_graph())
        #创建图,不创建图,默认是在默认图中执行tensor和operation
        gr=tf.Graph()
        with gr.as_default():
            a = tf.constant(7)
            b = tf.constant(10)
            sum = tf.add(a, b)
            #该Graph的Tensor都可以访问到该图
            print("a.graph:",a.graph)
            print("sum.graph:", sum.graph)
    
    """张量"""
    def tensor():
        #创建一个符合正态分布的随机Tensor  mean-均值 stddev-方差 shape-数据形状
        ts = tf.random_normal(mean=0.0, stddev=0.5, shape=[50, 3])
        print(ts)
    
        plt=tf.placeholder(dtype=tf.float32,shape=[None,3])
        print(plt)
        #对不定形状可以使用set_shape设置具体shape
        plt.set_shape([4,3])
        print(plt)
        #设置[4,3]之后不能再次设置
        #plt.set_shape([5,3])
        #print(plt)
        #改变数据形状,reshape()需要保证数据元素个数相同
        plt_reshape=tf.reshape(plt,shape=[3,4])
        print(plt_reshape)
    
        #修改Tensor数据类型
        plt=tf.cast(plt,dtype=tf.int32)
        print(plt)
    

    相关文章

      网友评论

          本文标题:Python应用

          本文链接:https://www.haomeiwen.com/subject/qejddqtx.html