zoukankan      html  css  js  c++  java
  • Python简单传染病模型

    数据分析期末大作业的时候做的,真实情况更为复杂和多变,还有很多不足的地方,暂且留档保存一下

    # -*- coding: utf-8 -*-
    """
    @描述:本模型利用Python的动画功能,简单模拟了传染病的传播过程;为了防止疫情的快速传播,
          要求完善该模型,设置相应参数,使之能够具有实际意义,为控制疫情提供参考。
    @要求1:添加隔离措施参数,限制生成的每个点的下一次随机位置不能超过某个范围(半径为x的圆内),
           超过系统边界[0,1]的数值置为边界值;
    @要求2:添加医院收治被感染者参数,在第x天可以收治n名病人,收治的病人用黄色点表示,
           收治后的病人不具有传染性;
    @要求3:添加被感染者的死亡参数,被感染者n天内没有被医院收治,则设置为死亡状态,用黑色点表示;
    @要求4:实时统计出相应的数据并打印输出,如当前被感染人数、收治人数、死亡人数等信息,并对比
           采取措施前后对疫情发展的影响,用图表展示;
    @要求5:增加防疫措施指数,跟被感染者一定距离内的正常人会有感染风险但不一定感染
    @要求6: 增加病毒潜伏期以及患者没有得到有效治疗的最长存活期
    @要求7:医院里的患者治疗完毕后会出院,或者治疗失败导致死亡,出院后假定该病不会产生抗体之类的,仍有感染风险
    @要求8:增加疫情情况曲线图,显示各日的感染人数、收治人数、死亡人数
    @要求n:以上4个要求为模型必须提供的功能;另外,还可以根据实际情况自行设置参数,使模型更加
           完善,如数据点全部被感染后跳出循环;
    """
    
    import math
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    # 随机样本点总数
    SAMPLE_NUM = 500
    # # 感染天数,应为2的倍数,表示[x,y]坐标
    INFECTION_DAYS = 50
    # 感染最小距离
    INFECTION_DISTANCE = 0.015
    # 生成点最远半径
    Move_dis = 0.5
    
    # 随机生成样本点
    sample_data = np.random.rand(SAMPLE_NUM, INFECTION_DAYS * 2)
    
    # 医院收治人员标志,未收治标0
    Receive = np.zeros(SAMPLE_NUM)
    # 死亡人员标志,未死亡标0
    Dedper = np.zeros(SAMPLE_NUM)
    
    # 增加防疫措施指数(表示在满足感染距离下的感染百分比)
    EpLevel = 80
    
    # 医院每天的收治人数
    recen = 50
    # 被医院收治的死亡率
    depe = 0.05
    # 病毒潜伏期
    mgs = 7
    
    # 患病时间(距离感染后的时间,即便被收治后达到最长存活时间根据死亡率可能存活或死亡,未被收治就..)
    sufftime = np.zeros(SAMPLE_NUM)
    
    # 患病后最长存活时间
    ltime = 15
    # 患者被医院收治的时间
    hossuff = np.zeros(SAMPLE_NUM)
    
    
    # 获取该点颜色的映射值
    def gc(x):
        if Dedper[x] == 1:
            return 3  # 死亡
        elif Receive[x] == 1:
            return 2  # 目前在医院收治
        else:
            return sample_data[x, 0]
    
    
    # 添加隔离措施
    for i in range(SAMPLE_NUM):
        for j in range(INFECTION_DAYS):
            if j == 0:
                continue
            # 隔离 下次生成的点由之前的点决定
            x1 = sample_data[i][(j << 1) - 2]
            y1 = sample_data[i][(j << 1) - 1]
            tmpx = np.random.uniform(max(0, x1 - Move_dis), min(1, x1 + Move_dis))
            tmpl = np.sqrt(Move_dis * Move_dis - (x1 - tmpx) * (x1 - tmpx))
            tmpy = np.random.uniform(max(0, y1 - tmpl), min(1, y1 + tmpl))
            sample_data[i][j << 1] = tmpx
            sample_data[i][j << 1 | 1] = tmpy
    
    # 第1列作为标志位:1表示已感染(红色),0表示未感染(绿色)
    sample_flag = np.zeros(len(sample_data))
    sample_data = np.insert(sample_data, 0, values=sample_flag, axis=1)
    # 随机产生一个感染者,并将标志位设为0(红色)
    seed = np.random.randint(0, SAMPLE_NUM, 1)
    sample_data[seed, 0] = 1
    sufftime[seed] = 1
    # 创建一个绘图窗口对象
    fig = plt.figure()
    # 初始化画散列点函数
    scat = plt.scatter(sample_data[:, 1], sample_data[:, 2], s=5, marker='o')
    
    # 设置折线图
    # 患病
    x = np.array([i for i in range(0, INFECTION_DAYS + 1)])
    yy1 = np.zeros(INFECTION_DAYS + 1)
    yy1[0] = 0
    # 收治
    yy2 = np.zeros(INFECTION_DAYS + 1)
    yy2[0] = 0
    # 死亡
    yy3 = np.zeros(INFECTION_DAYS + 1)
    yy3[0] = 0
    
    stepp = np.array([i for i in range(SAMPLE_NUM)])
    
    
    def init():
        # 输出当前感染人数
        print(u"第{}天 => 被感染人数:{}".format(1, 1))
        # 根据不同的标签,显示当前感染者
        map_color = {1: 'r', 0: 'g'}
        color = list(map(lambda c: map_color[c], sample_data[:, 0]))
        scat.set_color(color)
        scat.set_offsets(sample_data[:, 1:3])
    
    
    # 定义更新数据点的函数
    def update(n):
        # 使用全局变量
        global sufftime
        global Dedper
        global Receive
        global hossuff
        global yy1
        global yy2
        global yy3
        # 外层循环为得到当前感染者,获取索引及当前感染者对应的位置坐标
        it = np.nditer(np.argwhere(sample_data == 1), flags=['f_index'])
        while not it.finished:
            if it[0] != 1:
                # 计算该感染者与其他点的距离,两者距离小于设定值表示有可能被感染
                # 两者距离小于设定值时有概率感染,设防疫措施x表示当满足条件时有x%感染,
                for i in range(0, SAMPLE_NUM):
                    # 计算两点间距离,感染者坐标 - 其他点坐标
                    p = sample_data[it[0], n:n + 2] - sample_data[i, n:n + 2]
                    d = math.hypot(p[0], p[1])
                    # 距离小于设定阈值表示感染同時运气不太好..,置0
                    if d <= INFECTION_DISTANCE and np.random.randint(100) < EpLevel:
                        sample_data[i, 0] = 1
            it.iternext()
        # 开始收治
        # 根据已经超过潜伏期的人员按照患病时间先后收治
        cnt = recen
        # 先根据患病时间排序,保留索引
        temp = np.argsort(sufftime)
        # 取出时间大于潜伏期的
        temp = temp[sufftime[temp] > mgs]
        for item in temp:
            # 能够收治并且未被收治以及未死亡
            if cnt != 0 and Receive[item] == 0 and Dedper[item] == 0:
                cnt = cnt - 1
                Receive[item] = 1
            else:
                break
        # 被收治的患者就当就地隔离好了..,覆盖之后的坐标为当前坐标,出院后再做考虑
        for item in temp[Receive[temp] == 1]:
            for j in range(n, INFECTION_DAYS * 2 + 1):
                sample_data[item][j] = sample_data[item][j - 2]
    
        tempp1 = np.sum(sample_data[:, 0] == 1)
        tempp2 = np.sum(Receive[:] == 1)
        tempp3 = np.sum(Dedper[:] == 1)
        tday = n // 2 + 1
        yy1[tday] = tempp1
        yy2[tday] = tempp2
        yy3[tday] = tempp3
        # 输出当前感染人数
        print(u"第{}天 => 被感染人数:{} => 被收治总人数:{} =>死亡总人数:{}".format(tday, tempp1, tempp2, tempp3))
        # 根据不同的标签,显示当前感染者
        map_color = {0: 'g', 1: 'r', 2: 'yellow', 3: 'black'}
        color = list(map(lambda c: map_color[c], list(map(gc, stepp))))
        scat.set_color(color)
        scat.set_offsets(sample_data[:, n:n + 2])
        # 一天结束 患病天数达到最大天数且未被收治的患者死亡并将坐标保持不变
        # 先筛选未收治患者且未被标记死亡的患者
        Dlist = np.argwhere(Receive == 0)
        Dlist = Dlist[Dedper[Dlist] == 0]
        # 再筛选患病达最大天数
        Dlist = Dlist[sufftime[Dlist] >= ltime]
        for item in Dlist:
            # 死亡tag标上
            Dedper[item] = 1
            # 将之后的坐标全部标为当前值
            for j in range(n, INFECTION_DAYS * 2 + 1):
                sample_data[item][j] = sample_data[item][j - 2]
    
        # 患者患病时间增加一天,被收治的患者患病时间满三十天 运气好的出院 不好的去世...出院的患者对于之后的坐标进行重写,不排除被再次感染的可能
        sufftime = sufftime + sample_data[:, 0]
        # 被收治的患者住院时间增加一天
        hossuff = hossuff + np.where(Receive == 1, 1, 0)
        # 记录满足住院时长超过最长存活时长的患者
        temp_hos = np.argwhere(hossuff >= ltime)
        # 生死俄罗斯转盘....
        for i in temp_hos:
            Receive[i[0]] = 0  # 出院了
            hossuff[i[0]] = 0
            sample_data[i[0]][0] = 0
            if np.random.uniform(0, 1) < depe:
                # 即便得到合理的救治也没法的患者们
                Dedper[i[0]] = 1
            else:
                # 痊愈出院的患者 重写之后的坐标
                sufftime[i[0]] = 0
                # SAMPLE_NUM[i[0]][0]=0
                for j in range(n // 2 + 1, INFECTION_DAYS):
                    x1 = sample_data[i[0]][(j << 1) - 2]
                    y1 = sample_data[i[0]][(j << 1) - 1]
                    tmpx = np.random.uniform(max(0, x1 - Move_dis), min(1, x1 + Move_dis))
                    tmpl = np.sqrt(Move_dis * Move_dis - (x1 - tmpx) * (x1 - tmpx))
                    tmpy = np.random.uniform(max(0, y1 - tmpl), min(1, y1 + tmpl))
                    sample_data[i[0]][j << 1] = tmpx
                    sample_data[i[0]][j << 1 | 1] = tmpy
    
    
    # 动画显示
    
    ani = animation.FuncAnimation(fig, update, range(3, (INFECTION_DAYS * 2) + 1, 2),
                                  init_func=init, interval=500, repeat=0)
    
    plt.show()
    
    plt.figure()
    plt.plot(x,yy1, label="Infected_num")#感染人数
    plt.plot(x,yy2, label="Take_num")#收治人数
    plt.plot(x,yy3, label="Dead_num")#死亡人数
    plt.legend(loc='upper left')
    plt.show()
    
  • 相关阅读:
    转换时间对象和字符串对象&添加时间
    jquery深入学习17-2-19
    jquery深入学习
    java上传附件含有%处理或url含有%(URLDecoder: Illegal hex characters in escape (%) pattern
    数据库备份脚本(整库备份)
    docker 利用maven插件推送镜像
    排序算法对比分析图
    Java计算时间差、日期差总结
    百度地图计算点是否在园,正方形,多边形范围内。电子围栏
    java maven docker-maven-plugin 结合Dockerfile 构建 docker image 并上传到docker server
  • 原文地址:https://www.cnblogs.com/graytido/p/13399158.html
Copyright © 2011-2022 走看看