在R语言中如何将两条曲线下面积归一化至1及相关绘图问题
嘿,咱们一步步拆解你的问题,把曲线归一化、绘图合并和代码正确性的事儿说清楚~
一、先澄清:你用的Z-score方法不是面积归一化
你写的 N1 = (x1 - mean(x1))/sd(x1) 是Z-score标准化,它的作用是把数据调整到均值为0、标准差为1的分布,和你要的「曲线下面积归一到1」完全不是一回事哦。面积归一化的核心是让曲线与x轴围成的总面积等于1,所以这个方法不适用你的需求。
二、曲线下面积归一化的正确方法
不管是单条曲线单独归一,还是两条一起归一,核心逻辑都是先算出曲线下的总面积,再把每个y值除以这个总面积。
1. 单条曲线单独归一到面积=1
你的代码里已经用到了黎曼和计算面积的思路,咱们修正一下细节:
- 首先,正确计算曲线下面积:用梯形法(比简单黎曼和更准确),公式是每个区间的面积 = (当前y值 + 下一个y值)/2 × 区间x的差值。对应代码:
# 计算曲线y1下的总面积(梯形法) area1 <- sum( (y1[-1] + y1[-length(y1)]) * diff(x1) / 2 ) # 归一化后的y值(保证总面积为1) y1_normalized <- y1 / area1 - 如果你要的是累积分布曲线(CDF)(也就是从左到右累积面积从0到1),你的代码思路是对的,但要修正面积计算:
# 计算每个区间的梯形面积 A <- (y1[-1] + y1[-length(y1)]) * diff(x1) / 2 total_area <- sum(A) # 累积归一化面积,补全起点0 yn <- c(0, cumsum(A) / total_area) # 绘制CDF曲线(x轴用x1,不是y1) plot(x1, yn, type = "l", xlab = "X", ylab = "Cumulative Area")
2. 两条曲线一起归一化到总面积=1
分两种情况:
- 如果是两条曲线的面积之和为1:先分别算两条曲线的面积
area1和area2,总面总total_area = area1 + area2,再分别把y1、y2除以total_area。 - 如果是把两条曲线合并为一个整体后归一化:先把两条曲线的x轴对齐(比如插值到相同的x网格),合并y值,再计算合并后曲线的总面积,最后归一化。
三、合并两个绘图为一个图
在R里,先画第一条曲线,再用lines()叠加第二条就行,举个例子:
# 先计算两条曲线各自归一化后的y值 area1 <- sum( (y1[-1] + y1[-length(y1)]) * diff(x1) / 2 ) y1_norm <- y1 / area1 area2 <- sum( (y2[-1] + y2[-length(y2)]) * diff(x2) / 2 ) y2_norm <- y2 / area2 # 绘制合并图 plot(x1, y1_norm, type = "l", col = "red", xlab = "X", ylab = "Normalized Y", main = "Normalized Curves") lines(x2, y2_norm, col = "blue") legend("topright", legend = c("Curve 1 (Area=1)", "Curve 2 (Area=1)"), col = c("red", "blue"), lty = 1)
如果是一起归一化(总面积=1),把上面的y1_norm和y2_norm换成除以总面总即可。
四、评估你的代码可行性
咱们逐行分析:
A = diff(y1)*rollmean(x1,2):这里有小错误,这个公式计算的不是梯形面积(和正确的梯形面积公式有差异),应该换成上面说的(y1[-1] + y1[-length(y1)]) * diff(x1) / 2。riemann_sum = sum(A):如果A是正确的梯形面积,这个就是总面积,没问题。yn = cumsum(A)/riemann_sum:这个是累积面积占比,也就是CDF的近似,逻辑正确。yn = c(0,yn):给CDF补全起点0,正确。plot(y1,yn ):这里x轴用y1是不合理的,应该用x1作为x轴,因为yn是随x变化的累积面积。plot(y1, c(0, diff(yn)/ diff(x1) )):这行是通过CDF的导数反推归一化密度,其实直接用y1/riemann_sum更简单准确。
整体思路是对的,只是面积计算的公式和绘图的x轴需要调整。
内容的提问来源于stack exchange,提问作者Amani




