Delphi中的对数似然实现

时间:2016-02-10 14:02:43

标签: r delphi

我正在尝试计算文本中单词对出现的Log Likelihood得分,并且在我的Delphi实现中得到了相同的异常结果,这是我从在线发现的Java和Python源代码中得到的。 1993年在这个来源上发表的Ted Dunning给出了一对特定的结果:

  • K11(AB,即关节频率)= 110,
  • K12(附近没有B的字A)= 2442,
  • K21(B附近没有A)= 111
  • K22(文本中除A或B以外的单词数)= 29114

并给出所需的结果为270.72

Dunning还在R at中给出了一个实现 http://tdunning.blogspot.co.uk/2008/03/surprise-and-coincidence.html

  

计算对数似然比得分(也称为G2)非常好   简单,(k_ij / sum(k)) log (k_ij / sum(k))
  其中H是香农的熵,计算为H = function(k) {N = sum(k) ; return (sum(k/N * log(k/N + (k==0)))}的总和。在R中,此函数定义为   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并且不确定如何将其转换为Pascal。

我的翻译尝试包括这些功能

7.9419

如上所述,上面的内容会返回270.72而不是所需的Log_likelihood_from_Java(2552, 221, 110, 31777);

<html>
<body>
<script type="text/javascript" src="http://www.old.newton.ac.uk/js/jwplayer/jwplayer.js"></script>  

<div id="myvideo5">Loading the player...</div>

    <script type="text/javascript">
        jwplayer("myvideo5").setup({
            file: "http://download.wavetlan.com/SVV/Media/HTTP/H264/Talkinghead_Media/H264_test1_Talkinghead_mp4_480x360.mp4",
        });
    </script>
</body>
</html>

感谢帮助!

2 个答案:

答案 0 :(得分:6)

我在LnOk函数的翻译中发现了这个问题,应该如下:

function LnOK(x: Integer): Extended;
begin
  if x = 0 then
    Result := 0
  else
    Result := x * Ln(x);
end;

非主题

作为旁注,如果我允许,只是为了改进编码风格,您可能更喜欢重载 Entropy函数,而不是使用不同的名称调用它们: / p>

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;

答案 1 :(得分:4)

我无法理解您编写的代码与您链接的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