R Delphi中对数似然函数的实现
我试图计算文本中成对单词出现的对数似然分数,并且在我的Delphi实现中得到了相同的异常结果,这是我从在线找到的Java和Python源代码中得到的。泰德·邓宁(Ted Dunning)于1993年在该资料来源上发表了一篇文章,给出了一对特定对象的结果:R Delphi中对数似然函数的实现,r,delphi,R,Delphi,我试图计算文本中成对单词出现的对数似然分数,并且在我的Delphi实现中得到了相同的异常结果,这是我从在线找到的Java和Python源代码中得到的。泰德·邓宁(Ted Dunning)于1993年在该资料来源上发表了一篇文章,给出了一对特定对象的结果: K11(AB,ie接头频率)=110 K12(A字附近没有B)=2442 K21(B,无附近A)=111 K22(文本中除A或B以外的字数)=29114 并给出了270.72的期望结果 Dunning还提供了R at中的一个实现 计算对数
- K11(AB,ie接头频率)=110
- K12(A字附近没有B)=2442
- K21(B,无附近A)=111
- K22(文本中除A或B以外的字数)=29114
LLR=2和(k)(H(k)-H(行和(k))-H(列和(k)))
其中H是香农熵,计算为
(k_ij/sum(k))log(k_ij/sum(k))
之和。在R中,此函数定义为
H=function(k){N=sum(k);return(sum(k/N*log(k/N+(k==0)))}
但我不知道R,也不确定如何将其翻译成Pascal
我的翻译尝试包括这些功能
function LnOK(x : integer): extended;
begin
if x<=0 then Result :=0
else Result := Ln(x);
end;
function Entropy2(a, b: Integer): extended;
begin
Result := LnOK(a + b) - LnOK(a) - LnOK(b);
end;
function Entropy4(a, b, c, d: Integer): extended;
begin
Result := LnOK(a + b + c + d) - LnOK(a) - LnOK(b) - LnOK(c) - LnOK(d);
end;
function Log_likelihood_from_Java(f1, f2, joint, total_tokens: Integer):
single;
var
k11, k12, k21, k22: Integer;
matrixEntropy, rowEntropy, colEntropy: extended;
begin
k11 := joint;
k12 := f2 - joint;
k21 := f1 - joint;
k22 := total_tokens - f1 - f2 + joint;
rowEntropy := Entropy2(k11 + k12, k21 + k22);
colEntropy := Entropy2(k11 + k21, k12 + k22);
matrixEntropy := Entropy4(k11, k12, k21, k22);
if (rowEntropy + colEntropy < matrixEntropy) then
Result := 0.0 // round off error
else
Result := 2.0 * (rowEntropy + colEntropy - matrixEntropy);
end;
感谢您的帮助!我无法理解您编写的代码与您链接的R代码没有明显关系。我没有试图调和这些差异 这是R代码的直译。我相信你会同意,用这种方式编写的算法要简单得多
{$APPTYPE CONSOLE}
uses
SysUtils, Math;
type
TVector2 = array [1..2] of Double;
TMatrix2 = array [1..2] of TVector2;
function rowSums(const M: TMatrix2): TVector2;
begin
Result[1] := M[1,1] + M[1,2];
Result[2] := M[2,1] + M[2,2];
end;
function colSums(const M: TMatrix2): TVector2;
begin
Result[1] := M[1,1] + M[2,1];
Result[2] := M[1,2] + M[2,2];
end;
function H(const k: array of Double): Double;
var
i: Integer;
N, kOverN: Double;
begin
N := Sum(k);
Result := 0.0;
for i := low(k) to high(k) do begin
kOverN := k[i]/N;
if kOverN>0.0 then begin
Result := Result + kOverN*Ln(kOverN);
end;
end;
end;
function LLR(const M: TMatrix2): Double;
var
k: array [1..4] of Double absolute M; // this is a little sneaky I admit
rs, cs: TVector2;
begin
rs := rowSums(M);
cs := colSums(M);
Result := 2.0*Sum(k)*(H(k) - H(rs) - H(cs));
end;
var
M: TMatrix2;
begin
M[1,1] := 110;
M[1,2] := 2442;
M[2,1] := 111;
M[2,2] := 29114;
Writeln(LLR(M));
end.
输出
2.70721876936232E+0002
2.70721876936232E+0002
我在翻译
LnOk
函数时发现了问题,应该如下所示:
function LnOK(x: Integer): Extended;
begin
if x = 0 then
Result := 0
else
Result := x * Ln(x);
end;
离题 如果允许的话,作为补充说明,为了改进编码风格,您可能更喜欢重载
Entropy
函数,而不是使用不同的名称调用它们:
function Entropy(a, b: Integer): Extended; overload;
begin
Result := LnOK(a + b) - LnOK(a) - LnOK(b);
end;
function Entropy(a, b, c, d: Integer): Extended; overload;
begin
Result := LnOK(a + b + c + d) - LnOK(a) - LnOK(b) - LnOK(c) - LnOK(d);
end;
真正奇怪的是,你的代码与你链接到的R代码没有明显的联系。@DavidHeffernan这似乎是从Java@Fantagirocco移植过来的。似乎询问者选择了一个糟糕且不清楚的实现,因为他理解Java而不是R。但R代码中的算法更清晰。@MikeScott LnOK暗示了一个专业的人如果Ln以特定方式处理域外情况,则为受保护的实现。但此函数不这样做。是的,它选择x=0,但忽略x
function Entropy(a, b: Integer): Extended; overload;
begin
Result := LnOK(a + b) - LnOK(a) - LnOK(b);
end;
function Entropy(a, b, c, d: Integer): Extended; overload;
begin
Result := LnOK(a + b + c + d) - LnOK(a) - LnOK(b) - LnOK(c) - LnOK(d);
end;