2010-11-17 23 views
2

我有以下函数从卡方分布中抽取一些数据,并使用最大似然比较X的分布与已知的卡方分布。该过程被模拟nSims次。 (我这些结果进行比较,从置换的测试结果,但代码除外)。'优化'找不到函数调用中的变量

chi2c <- function(xdf=2, yObs=100, xObs=100, nSims=1000, nPerm=500, alpha=0.05){ 
    simResults <- sapply(1:nSims, function(x){ 
    # Draw variables 
    x <- rchisq(xObs, df=xdf) 
    # Other variables not relevant here 
    # [[snip]] 

    # Permutation test 
    # [[snip]] 

    # Calculate the statistics necessary for maximum likelihood 
    n  <<- length(x) 
    sumlx <<- sum(log(x)) 
    sumx <<- sum(x) 
    # Calculate the maximum likelihood estimate 
    dfhat <- optimize(f=c2ll, interval=c(1, 10), maximum=TRUE)$maximum 
    # Calculate the test statistic: -2 times the log likelihood ratio 
    llr  <- -2 * (c2ll(2) - c2ll(dfhat)) 
    # Compare the test statistic to its asymptotic dist: chi-squared 
    lReject <- llr > qchisq(1 - alpha, df=1) 

    # Provide the results 
    # [[snip]] 
    }) 
    # Calcuate means across simulations 
    rowMeans(simResults) 
} 

这个函数调用c2ll,卡方似然函数

c2ll <- function(dfHat){ 
    -n * log(gamma(dfHat/2)) - n * (dfHat/2) * log(2) + 
    (dfHat/2 - 1) * sumlx - sumx/2 
} 

此功能不只是我希望和准确,但我不明白为什么我必须设置全局最大似然统计(n,sumlxsumx)才能使其运行; optimize找不到它们,如果我只使用<-将它们设置在函数内部。我尝试将它们设置在optimize之内,但那也不起作用。谢谢你的帮助。

Charlie

+0

我有点困惑。它看起来像人们所期望的那样行事:如果c2ll是全局定义的,那么词法范围会要求任何变量查找首先在c2ll中发生,然后在全局中发生。如果将c2ll的所有输入定义为函数参数,那么混淆会更少。 – 2010-11-17 07:54:36

回答

2

R的词汇范围,这意味着函数查找变量的环境中它们被定义。 c2ll是在全局环境中定义的,因此在函数内部看不到n,sumx和sum1x的定义。 S另一方面使用动态作用域,其行为与你期望的相同(即它在它所称的范围内寻找变量)。计算机科学家普遍认为,动态范围确定是一个死胡同的坏主意,而词汇范围确实是一条路。

作为一个实际问题,您可以对此做些什么?

嗯,有一对夫妇选择...

首先,您可以在本地定义功能:

n  <- length(x) 
sumlx <- sum(log(x)) 
sumx <- sum(x) 
c2ll <- function(dfHat){ 
    -n * log(gamma(dfHat/2)) - n * (dfHat/2) * log(2) + (dfHat/2 - 1) * sumlx - sumx/2 
} 
dfhat <- optimize(f=c2ll, interval=c(1, 10), maximum=TRUE)$maximum 

,你可以有c2ll采取额外的参数,通过优化来传递这些参数。

#in global env 
c2ll <- function(dfHat,n,sum1x,sumx){ 
    -n * log(gamma(dfHat/2)) - n * (dfHat/2) * log(2) + 
    (dfHat/2 - 1) * sumlx - sumx/2 
} 

#... 
#in function 
n  <- length(x) 
sumlx <- sum(log(x)) 
sumx <- sum(x) 
dfhat <- optimize(f=c2ll, interval=c(1, 10), n=n,sum1x=sum1x,sumx=sumx, maximum=TRUE)$maximum 

两者都是干净的选项,可以保留函数的封装。

+0

你的第一段最后一句话有错误...动态两次? – John 2010-11-17 13:15:39

+0

谢谢。固定 – 2010-11-17 14:56:12

1

您的simResults函数返回一个逻辑向量。而不是使用rowMeans,只需使用平均(simResults),结果看起来相当明智的......至少在某种程度上是:

> chi2c(alpha=0.05) 
[1] 0.057 
> chi2c(alpha=0.5) 
[1] 0.503 
+0

谢谢,迪文。是的,该函数工作正常,但我想知道为什么我需要使用'<< - '在全局环境中设置ML统计信息以便'optimize'找到它们,而如果我只在使用'<-','optimize'的函数环境没有找到它们。看起来有点古怪,我不喜欢在函数之外定义变量(即全局)。 – Charlie 2010-11-17 06:04:50

+0

我意识到可能存在范围问题,因此将c2ll函数作为chi2c主体中的第一行。这并没有产生预期的结果,我的建议改为意味着(simResults)是我从那里进行调试的结果。 – 2010-11-17 15:06:02

1

您的问题源于R使用的词法范围规则。详见language definitions手册。总之,你的函数c2ll正在寻找它定义的环境中的变量。

为了避免这个问题,你必须将n,sum1x和sum2x明确地作为参数传递给你的函数,或者直接在ch2c函数中本地定义你的函数。

这是一个很常见的问题,SO上有很多有趣的例子。