在前一段時間,我腦子一熱使用指數迴歸以及多項式迴歸對新型冠狀病毒2019-nCov的感染人數進行預測。後來發現不行啊,感染人數不可能一直上漲啊,總得有停止上漲的時候啊!在多名網友的提醒下,在參考了邢翔瑞大佬的博客之後,我痛定思痛,嘗試使用Logistic增長模型對感染人數進行預測,結果如下圖(下圖是直接使用擬合得到的r值,爲0.303,經過簡單的測試,這個模型預測的數量偏小,如果有大佬對此比較瞭解能否指點一二):
2月9日預測結果(看最近幾天的預測結果已經很接近了):
2月8日預測結果:
2月7日預測結果:
我們在高中生物中有學過,種羣的增長曲線有分"J"型和"S"型,其中"J"型爲理想型,實際中種羣的數量不可能一直像指數函數那樣,而是一個S型曲線,如下圖所示。
這個函數的曲線和機器學習中的Sigmoid函數及其相似,其公式都有點像,logistic增長函數爲”
其中K爲環境最大容量,P0爲初始容量,r爲增長速率,r越大則增長越快(即更快的逼近上限)。
該模型的微分式是:
如果看不懂上面的內容,直接複製粘貼代碼運行一下吧~(其實和之前的思路一樣,使用最小二乘法擬合數據,只是擬合的函數換了而已)
from scipy.optimize import curve_fit
import urllib
import json
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import time
def date_encode(date):
# '01.24' -> 1 * 100 + 24 = 124
d = date.split('/')
month, day = int(d[0]), int(d[1])
return 100 * month + day
def date_decode(date):
# 124 -> '01.24'
return '{}.{}'.format(str(date // 100), str(date % 100))
def sequence_analyse(data):
date_list, confirm_list, dead_list, heal_list, suspect_list = [], [], [], [], []
data.sort(key = lambda x: date_encode(x['date']))
for day in data:
date_list.append(day['date'])
confirm_list.append(int(day['confirm']))
dead_list.append(int(day['dead']))
heal_list.append(int(day['heal']))
suspect_list.append(int(day['suspect']))
return pd.DataFrame({
'date': date_list,
'confirm': confirm_list,
'dead': dead_list,
'heal': heal_list,
'suspect': suspect_list
})
def get_date_list(target_month = 3):
"""
得到從1月13日到month月最後一天的所有日期列表
"""
month_day = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
cur_month, cur_day = 1, 13
ans = []
while cur_month <= target_month:
while cur_day <= month_day[cur_month]:
d = "0" + str(cur_day) if cur_day < 10 else str(cur_day)
ans += [str(cur_month) + "/" + d]
cur_day += 1
cur_day = 1
cur_month += 1
return ans
def logistic_function(t, K, P0, r):
t0 = 0
exp = np.exp(r * (t - t0))
return (K * exp * P0) / (K + (exp - 1) * P0)
def predict():
# 預測未來天數
predict_days = 20
# 獲取實時數據
url = 'https://view.inews.qq.com/g2/getOnsInfo?name=wuwei_ww_cn_day_counts'
response = urllib.request.urlopen(url)
json_data = response.read().decode('utf-8').replace('\n','')
data = json.loads(json_data)
data = json.loads(data['data'])
df = sequence_analyse(data)
date, confirm = df['date'].values, df['confirm'].values
x = np.arange(len(confirm))
date_labels = get_date_list(4)
# 用最小二乘法估計擬合
popt, pcov = curve_fit(logistic_function, x, confirm)
print(popt)
#近期情況預測
predict_x = list(x) + [x[-1] + i for i in range(1, 1 + predict_days)]
predict_x = np.array(predict_x)
predict_y = logistic_function(predict_x, popt[0], popt[1], popt[2])
#繪圖
plt.figure(figsize=(15, 8))
plt.plot(x, confirm, 's',label="confimed infected number")
plt.plot(predict_x, predict_y, 's',label="predicted infected number")
plt.xticks(predict_x, date_labels[:len(predict_x) + 1], rotation=90)
plt.yticks(rotation=90)
plt.suptitle("Logistic Fitting Curve for 2019-nCov infected numbers(Max = {}, r={:.3})".format(int(popt[0]), popt[2]), fontsize=16, fontweight="bold")
plt.title("Predict time:{}".format(time.strftime("%Y-%m-%d", time.localtime())), fontsize=16)
plt.xlabel('date', fontsize=14)
plt.ylabel('infected number', fontsize=14)
plt.plot()
predict()
參考: