评论部分充斥着迂腐的注释和关于数据中噪音来源的问题,我感觉有点糟糕。所以我会用一个比那些小评论更体面的答案来弥补它。
这个答案将证明一个简单的(非线性)最小二乘拟合(也可以用 glm* 完成)将如何高估两种化合物之间差异的重要性。发生这种高估的原因是噪声不是均匀的,而用于计算 p 值的模型假设所有点都具有相同的噪声。实际上,在模型之间产生很大差异的主要是中点周围的几个点。因此,有效自由度远小于计算假设的。
这使得来自@jbowman 答案的排列测试成为一种更强大的方法。置换测试的问题是您需要足够数量的相关数据点才能使测试变得强大。此外,由于特定的实验程序导致错误不独立,因此置换测试不能避免数据点相关的情况。其他一些方法,例如使用对整个过程进行建模并包含所有错误的贝叶斯模型可能会更好。
底线是没有单一的解决方案可以应用于所有这些类型的曲线。您不能将一组数据连同一个函数而没有其他信息一起提供给统计学家。了解数据的来源和生成方式非常重要。这需要纳入统计模型。
在此示例中,我们生成数据点,不是通过向曲线添加噪声,而是通过更改每个数据点的参数。
a∼Unif(4,6)b=3y=1−11+(x/a)b
然后我们会得到一个这样的图来生成两次 80 个数据点。

曲线的可变性不像添加到某个“真实”值的噪声,而是因为曲线本身的变化每次都不同。这可能与使用的(细菌?)细胞的变化相对应。它们中的每一个都是不同的,并且可能根据不同的系数表现a和b. 结果是噪声不均匀。大多在中间x=5变化最大的地方。
如果我们重复这个模拟104次并使用 glm 模型或非线性最小二乘拟合计算 p 值,那么 p 值的分布如下所示

因此,您不会得到 p 值的均匀分布,并且模型会高估出现某种差异的概率。
原因是变化主要发生在几个点,而 p 值的计算假设它均匀地发生在所有点。这高估了自由度。特别是包含点x=0完全没用,因为系数的变化对结果的价值没有影响。
示例代码:
sigmoid = function(x,a=5,b=3) {
1-(1+(x/a)^b)^-1
}
simulate_test = function(plot = TRUE) {
### create data
x = rep(0:15,10)
y = sigmoid(x, a = runif(length(x),4,6))
compound = c(rep(0,16*5), rep(1,16*5))
### make a plot if desired
if (plot == TRUE) {
plot(x, y, pch = 21, col = 1, bg = 0 + compound * 2, cex = 0.7)
}
### Perform fitting
###
### we can do the fitting with nls but the lines below shows that glm works as well
### For glm points with x=0 need to be removed because we use log(x), but these do not add information anyway
modnls = nls(y ~ sigmoid(x,a+c*compound,b), start = c(a=5,b=3,c=0),
control = nls.control(minFactor = 10^-4,warnOnly = TRUE))
modglm = glm(y[-which(x==0)] ~ log(x[-which(x==0)]) + compound[-which(x==0)], family = gaussian(link = "logit"))
#lines below demonstrate how you would get the (same) coefficients with the two methods glm vs nls
#coefficients(modnls)
#coefficients(modglm)
#exp(-modglm$coefficients[1]/modglm$coefficients[2])
#exp((-modglm$coefficients[1]-modglm$coefficients[3])/modglm$coefficients[2])-exp(-modglm$coefficients[1]/modglm$coefficients[2])
return(list(nls_p = summary(modnls)$coefficients[3,4],
glm_p = summary(modglm)$coefficients[3,4]))
}
set.seed(1)
x = replicate(10^4, as.numeric(simulate_test(plot = FALSE)))
x = list(nls_p = x[1,],
glm_p = x[2,])
hist(x$glm_p, breaks = seq(0,1,0.01))
hist(x$nls_p, breaks = seq(0,1,0.01))
simulate_test(plot = TRUE)
*拟合也可以使用广义线性模型来完成,因为我们可以找到一个链接函数,使得转换后的值是回归量的线性函数:log(y1−y)=blog(x)−blog(a). 这在代码中得到了证明。由于计算错误,系数和估计值之间存在细微差异,而 p 值则因为 glm 模型必须使用log(x)并排除该值x=0. 但这些价值观x=0无论如何不添加任何信息,并使 glm 模型实际上比 nls 模型更精确。