如何在R语言中为时间序列绘制多项式回归线?
解决美国新冠日增病例的三次多项式拟合绘图问题
嘿,别纠结lm()函数的适用性啦!你只是想给日增病例散点图加一条三次趋势曲线,这种场景下**lm()完全够用**——ARIMA这类时间序列模型是用来处理自相关结构、做预测的,而你现在的需求是拟合多项式趋势,普通线性回归就能搞定。
我帮你调整了代码,既保留了你原来的绘图样式,又加入了三次拟合曲线的绘制步骤:
options(repr.plot.width=14, repr.plot.height=10) # 安装并加载所需包 install.packages('RCurl') require(repr) require(RCurl) require(tidyverse) # 提取并整理约翰霍普金斯的新冠确诊数据 x = getURL("https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv") corona <- read_csv(x) %>% pivot_longer(cols = -c(`Province/State`, `Country/Region`, Lat, Long), names_to = "date", values_to = "cases") %>% select(`Province/State`, `Country/Region`, date, cases) %>% mutate(date = as.Date(date, format = "%m/%d/%y")) %>% drop_na(cases) %>% rename(country = "Country/Region", provinces = "Province/State") # 筛选美国数据,计算日增病例 cc <- corona %>% filter(country == "US") ccw <- cc %>% pivot_wider(names_from = "country", values_from = "cases") %>% filter(US > 5) # 整理日增病例与对应日期(diff后长度减1,需对齐日期) first.der <- diff(ccw$US, lag = 1, differences = 1) plot_data <- tibble( date = ccw$date[-1], # 去掉第一个日期,和日增数据匹配 daily_cases = first.der ) # 拟合三次多项式回归:将日期转为数值型(天数)作为自变量 # raw=TRUE使用原始多项式项,更贴合我们对三次曲线的直观理解 poly_model <- lm(daily_cases ~ poly(as.numeric(date), 3, raw = TRUE), data = plot_data) # 生成拟合值 plot_data$fit <- predict(poly_model) # 绘制散点图(保留你原有的样式) plot(plot_data$date, plot_data$daily_cases, pch = 19, cex = 1.2, ylab = '', xlab = '', main = 'Daily COVID-19 cases in US', col = "firebrick", axes = FALSE, cex.main = 1.5) abline(h = 0) abline(v = max(plot_data$date), col = 'gray90') abline(h = plot_data$daily_cases[nrow(plot_data)], col = 'firebrick', lty = 2, lwd = .5) # 添加日期轴和Y轴 at1 <- seq(min(plot_data$date), max(plot_data$date), by = 2) axis.Date(1, at = at1, format = "%b %d", las = 2, cex.axis = 0.7) axis(side = 2, seq(min(plot_data$daily_cases), max(plot_data$daily_cases), 1000), las = 2, cex.axis = 1) # 叠加三次拟合曲线 lines(plot_data$date, plot_data$fit, col = "navy", lwd = 2) # 添加图例说明 legend("topright", legend = c("Daily Cases", "3rd Degree Polynomial Fit"), col = c("firebrick", "navy"), pch = c(19, NA), lty = c(NA, 1), lwd = 2, cex = 1.2)
关键细节解释:
- 为什么能用
lm()?:你要的是拟合一条描述数据趋势的曲线,属于回归拟合范畴,和时间序列的“预测建模”是两回事。只要不需要捕捉数据的自相关特性(比如ARIMA的核心功能),lm()完全能胜任这个可视化需求。 - 日期转数值:
lm()无法直接处理Date类型的自变量,所以用as.numeric(date)把日期转换成从1970-01-01开始的天数,作为多项式回归的输入。 poly(..., raw=TRUE):如果不加这个参数,R会默认生成正交多项式,拟合的趋势是一样的,但系数的解释性会变差;我们只需要画曲线,用原始多项式更直观。
如果之后发现残差存在自相关(日增病例的前后值有明显关联),可以考虑用nlme包的gls()函数加入自相关结构,但对于单纯的趋势可视化来说,上面的代码已经完全满足需求啦!
内容的提问来源于stack exchange,提问作者Antoni Parellada




