如何在X轴为日期的ggplot时间序列图中添加线性回归平滑趋势线
解决方案
问题原因
你当前无法直接添加线性趋势线的核心原因是:X轴通过reorder(dates, value)将字符型日期转换为了有序分类因子,而线性回归lm()要求自变量为数值类型,直接使用y~x无法适配分类变量。
方案1:不改动现有X轴逻辑,直接适配
直接在stat_smooth中把X轴映射转换为数值型即可,无需修改原有绘图逻辑:
ggplot()+ geom_line(data=combined,aes(x=reorder(dates,value),y=value,color=variable,group=variable))+ # 新增线性趋势线代码 stat_smooth(data=combined, aes(x=as.numeric(reorder(dates,value)), y=value, color=variable, group=variable), method = "lm", formula = y~x, se = FALSE)+ scale_y_continuous(labels=function(x) format(x,scientific=FALSE))+ theme_gray()+ theme(axis.text.x = element_text(angle=90), plot.title=element_text(hjust=0.5),plot.subtitle = element_text(hjust = 0.5))+ annotate(geom = 'text',x='03.5.20',y=150000,label= 'WHO declares Covid-19 a Pandemic')+ annotate(geom = 'point',x='03.11.20',y=125865,size=6,shape=21,fill='blue')+ labs(title='Cases in China vs World ',x='Daily trend from January to March',y='Case Numbers ', subtitle = 'Data From Jan 22,2020 - Mar 23,2020')
参数说明:
as.numeric(reorder(dates,value)):将有序因子转换为1、2、3...的时序数值,适配线性回归的自变量要求se=FALSE可关闭置信区间填充,需要保留可以删掉这个参数- 保留
color=variable和group=variable会自动为中国、全球各生成一条独立的趋势线
方案2:更规范的日期类型转换(推荐)
把字符型日期转换为R原生的日期类型,无需手动reorder排序,后续的标注、轴调整也更灵活:
第一步先处理数据集:
# 转换日期格式,%m代表月,%d代表日,%y代表两位年份 combined$dates <- as.Date(combined$dates, format = "%m.%d.%y")
然后修改绘图代码,X轴直接用日期变量,直接加stat_smooth即可:
ggplot()+ geom_line(data=combined,aes(x=dates,y=value,color=variable,group=variable))+ # 直接添加趋势线,无需额外转换 stat_smooth(data=combined, aes(x=dates, y=value, color=variable, group=variable), method = "lm", formula = y~x, se = FALSE)+ scale_y_continuous(labels=function(x) format(x,scientific=FALSE))+ # 可以保留日期轴的倾斜设置 scale_x_date(date_labels = "%m.%d.%y") + theme_gray()+ theme(axis.text.x = element_text(angle=90), plot.title=element_text(hjust=0.5),plot.subtitle = element_text(hjust = 0.5))+ # 日期类的标注直接用Date类型值,不会出错 annotate(geom = 'text',x=as.Date("2020-03-05"),y=150000,label= 'WHO declares Covid-19 a Pandemic')+ annotate(geom = 'point',x=as.Date("2020-03-11"),y=125865,size=6,shape=21,fill='blue')+ labs(title='Cases in China vs World ',x='Daily trend from January to March',y='Case Numbers ', subtitle = 'Data From Jan 22,2020 - Mar 23,2020')
可选优化提示
新冠病例数属于指数增长特征的数据,线性回归拟合的直线会和实际曲线偏差较大,如果需要更贴合的平滑趋势,可以把method="lm"换成method="loess",或者对y值做对数转换后再拟合线性模型。
内容的提问来源于stack exchange,提问作者lams
相关产品推荐
相关产品推荐

