R ggplot使用dlnorm为工资密度直方图叠加对数正态曲线的参数问题
问题描述
我使用加拿大人口普查数据绘制x轴为工资(Wages)、y轴为密度的直方图,想要叠加对数正态分布的dlnorm曲线,但不确定meanlog和sdlog参数的正确取值。我先后尝试直接传入mean(data$Wages)、sd(data$Wages)以及两者的自然对数值作为参数,生成的曲线都和现有密度直方图分布差异极大。请问是否是我的数据不符合对数正态分布?如何获取正确的meanlog和sdlog参数?
我的代码如下:
inc_plot <- data_adults %>% ggplot(aes(x=Wages)) + geom_histogram(aes(y=..density..), bins=100,fill="transparent", colour="black")+ scale_x_continuous(labels=scales::comma) + stat_function(fun = dlnorm, args = list(meanlog = 48637.91, sdlog = 62459.15), col = "red") inc_plot
当前代码中使用的参数就是前述的工资均值和标准差,生成的效果如下图:
解决方案
核心错误原因
你对dlnorm的参数定义理解有误:
meanlog对应的是原始工资数据取自然对数后的均值,不是原始工资的均值,也不是原始均值的对数值sdlog对应的是原始工资数据取自然对数后的标准差,不是原始工资的标准差,也不是原始标准差的对数值
你直接传入原始工资的均值、标准差,参数量级完全不符合要求,自然曲线和直方图匹配不上。
正确操作步骤
- 清洗无效数据:对数正态分布仅支持正值,先删除
Wages列中小于等于0的观测,避免取对数时报错 - 计算参数:对清洗后的
Wages列取自然对数,再计算该对数序列的均值和标准差,即为meanlog和sdlog的正确取值
修正后代码
# 清洗数据+计算参数 data_adults_clean <- data_adults %>% filter(Wages > 0) wages_log <- log(data_adults_clean$Wages) meanlog_val <- mean(wages_log) sdlog_val <- sd(wages_log) # 绘图 inc_plot <- data_adults_clean %>% ggplot(aes(x=Wages)) + geom_histogram(aes(y=..density..), bins=100,fill="transparent", colour="black")+ scale_x_continuous(labels=scales::comma) + stat_function(fun = dlnorm, args = list(meanlog = meanlog_val, sdlog = sdlog_val), col = "red") inc_plot
分布符合性验证
如果按上述方法调整后,曲线和直方图仍然差异较大,说明你的工资数据确实不符合对数正态分布,可通过两种方法验证:
- 绘制对数工资的Q-Q图:若散点基本沿着正态分布对角线分布,说明符合对数正态,反之不符合
- 对对数工资做Shapiro-Wilk正态检验,p值大于显著性水平(通常为0.05)则认为符合对数正态
内容的提问来源于stack exchange,提问作者Luke
相关产品推荐
相关产品推荐

