You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在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:先分别算两条曲线的面积area1area2,总面总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_normy2_norm换成除以总面总即可。

四、评估你的代码可行性

咱们逐行分析:

  1. A = diff(y1)*rollmean(x1,2):这里有小错误,这个公式计算的不是梯形面积(和正确的梯形面积公式有差异),应该换成上面说的(y1[-1] + y1[-length(y1)]) * diff(x1) / 2
  2. riemann_sum = sum(A):如果A是正确的梯形面积,这个就是总面积,没问题。
  3. yn = cumsum(A)/riemann_sum:这个是累积面积占比,也就是CDF的近似,逻辑正确。
  4. yn = c(0,yn):给CDF补全起点0,正确。
  5. plot(y1,yn ):这里x轴用y1是不合理的,应该用x1作为x轴,因为yn是随x变化的累积面积。
  6. plot(y1, c(0, diff(yn)/ diff(x1) )):这行是通过CDF的导数反推归一化密度,其实直接用y1/riemann_sum更简单准确。

整体思路是对的,只是面积计算的公式和绘图的x轴需要调整。

内容的提问来源于stack exchange,提问作者Amani

火山引擎 最新活动