ブロックエントロピーを計算する


12

私はかつて、与えられたブロックサイズに対して与えられたシンボルシリーズのブロックエントロピーを計算する関数を書く必要があり、結果がどれほど短いかに驚いた。したがって、私はあなたにそのような機能をcodegolfに挑戦しています。私が今何をしたか(およびどの言語で)を言っているわけではありませんが、同じまたはより良いアイデアを最初に思い付かなかった場合は、1週間ほど後にします。

ブロックエントロピーの定義:

シンボルシーケンスA = A_1、…、A_nおよびブロックサイズmが与えられた場合:

  • サイズmのブロックは、シンボルシーケンスのm個の連続した要素のセグメント、つまり、適切なiのA_i、…、A_(i + m-1)です。
  • xがサイズmのシンボルシーケンスの場合、N(x)はxと同じAのブロック数を示します。
  • p(x)は、Aからのブロックがサイズmのシンボルシーケンスxと同一である確率です。つまり、p(x)= N(x)/(n−m + 1)
  • 最後に、Aのブロックサイズmのブロックエントロピーは、Aのサイズmのすべてのブロックxでの-log(p(x))の平均、または-p(x)・log(pの合計(x))Aで発生するサイズmのすべてのxに対して(必要な適切な対数を選択できます。)

制限と説明:

  • 関数は、ブロックシーケンスmとブロックサイズmを引数として使用する必要があります。
  • シンボルは、ゼロベースの整数として、または別の便利な形式で表されると想定できます。
  • あなたのプログラムは理論的に合理的な議論をとることができなければならず、実際には標準的なコンピューターで事例を計算できなければなりません(下記参照)。
  • 組み込み関数およびライブラリは、1回の呼び出しでプロシージャの大部分を実行しない限り許可されます。つまり、Aからサイズmのすべてのブロックを抽出し、特定のブロックxの出現回数をカウントするか、エントロピーを計算します一連のp値から–これらを自分で行う必要があります。

テスト:

[2, 3, 4, 1, 2, 3, 0, 0, 3, 2, 3, 0, 2, 2, 4, 4, 4, 1, 1, 1, 0, 4, 1,
2, 2, 4, 0, 1, 2, 3, 0, 2, 3, 2, 3, 2, 0, 1, 3, 4, 4, 0, 2, 1, 4, 3,
0, 2, 4, 1, 0, 4, 0, 0, 2, 2, 0, 2, 3, 0, 0, 4, 4, 2, 3, 1, 3, 1, 1,
3, 1, 3, 1, 0, 0, 2, 2, 4, 0, 3, 2, 2, 3, 0, 3, 3, 0, 0, 4, 4, 1, 0,
2, 3, 0, 0, 1, 4, 4, 3]

このシーケンスの最初のブロックエントロピーは次のとおりです(自然対数の場合)。

  • m = 1:1.599
  • m = 2:3.065
  • m = 3:4.067
  • m = 4:4.412
  • m = 5:4.535
  • m = 6:4.554

@ m.buettner:私のルールに関するソリューションの境界線を考慮しても、まだ試してみることができますentropy(probabilities(blocks(A,m)))。
— Wrzlprmft

これに対数ベース2を使用するのは慣習ではありませんか?
— ジョナサンヴァンマトレ14年

最後のエントロピーの値は正ですが、確率の対数は負またはゼロです。したがって、エントロピーの式には負の符号がありません。
— ヘイコOberdiek 14年

@JonathanVanMatre:私の知る限り、それは対数の最もよく使われるペースに依存しています。とにかく、チャレンジにとってそれほど重要ではないので、あなたが望む合理的なベースを使用できます。
— Wrzlprmft 14年

@HeikoOberdiek:ありがとう、忘れてた。
— Wrzlprmft 14年

回答:


6

Mathematica- 81 78 75 72 67 65 62 56バイト

Mathematicaでゴルフをしたことがないので、改善の余地があると思います。これはPartitionとのTally機能によりルールに完全には準拠していませんが、非常にきれいなので、とにかく投稿したいと思いました。

f=N@Tr[-Log[p=#2/Length@b&@@@Tally[b=##~Partition~1]]p]&

これは任意の記号セットで機能し、次のように使用できます

sequence = {2, 3, 4, 1, 2, 3, 0, 0, 3, 2, 3, 0, 2, 2, 4, 4, 4, 1, 1, 
   1, 0, 4, 1, 2, 2, 4, 0, 1, 2, 3, 0, 2, 3, 2, 3, 2, 0, 1, 3, 4, 4, 
   0, 2, 1, 4, 3, 0, 2, 4, 1, 0, 4, 0, 0, 2, 2, 0, 2, 3, 0, 0, 4, 4, 
   2, 3, 1, 3, 1, 1, 3, 1, 3, 1, 0, 0, 2, 2, 4, 0, 3, 2, 2, 3, 0, 3, 
   3, 0, 0, 4, 4, 1, 0, 2, 3, 0, 0, 1, 4, 4, 3};
f[sequence, 3]

> 4.06663

これはやや手付かずのバージョンです:

f[sequence_, m_] := (
    blocks = Partition[sequence, m, 1];
    probabilities = Apply[#2/Length[blocks] &, Tally[blocks], {1}];
    N[Tr[-Log[probabilities]*probabilities]]
)

Nの結果に直接適用すると、おそらくより高速に実行されますTally。

ところで、Mathematicaは実際にEntropyこれを28バイトに減らす関数を持っていますが、それは間違いなくルールに反しています。

f=N@Entropy@Partition[##,1]&

一方、ここに再実装する128バイトのバージョンがPartitionありTallyます:

f=N@Tr[-Log[p=#2/n&@@@({#[[i;;i+#2-1]],1}~Table~{i,1,(n=Length@#-#2+1)}//.{p___,{s_,x_},q___,{s_,y_},r___}:>{p,{s,x+y},q,r})]p]&

ゴルフをしていない:

f[sequence_, m_] := (
    n = Length[sequence]-m+1; (*number of blocks*)
    blocks = Table[{Take[sequence, {i, i+m-1}], 1},
                   {i, 1, n}];
    blocks = b //. {p___, {s_, x_}, q___, {s_, y_}, r___} :> {p,{s,x+y},q,r};
    probabilities = Apply[#2/n &, blocks, {1}];
    N[Tr[-Log[probabilities]*probabilities]]
)

Partitionそして、はTally、それらが1回の呼び出しで、「Aからサイズmの全てのブロックを抽出する」とはそれぞれ、「所定のブロックXの出現数をカウント」される境界の場合、それらは、完全にルールを破るされていません。それでも、Mathematicaについて知っているのに、まともな解決策がなかったとしても驚かないだろう。
— Wrzlprmft 14年

1
私は再実装それほどgolfedバージョン追加しました@Wrzlprmft PartitionとをTally。
— マーティンエンダー14年

3

Perl、140バイト

次のPerlスクリプトは、E引数としてセグメントサイズが後に続くシンボルシーケンスを受け取る関数を定義します。

sub E{$m=pop;$E=0;%h=();$"=',';$_=",@_,";for$i(0..@_-$m){next
if$h{$s=",@_[$i..$i+$m-1],"}++;$E-=($p=s|(?=$s)||g/(@_-$m+1))*log$p;}return$E}

テスト済みの非ゴルフバージョン

sub E { # E for "entropy"
    # E takes the sequence and segment size as arguments
    # and returns the calculated entropy.
    $m = pop;    # get segment size (last argument)
    $E = 0;      # initialize entropy
    %h = ();     # hash that remembers already calculated segments
    $" = ',';#"  # comma is used as separator
    $_ = ",@_,"; # $_ takes sequence as string, with comma as delimiters
    for $i (0 .. @_-$m) {
        $s = ",@_[$i..$i+$m-1],"; # segment
        next if$h{$s}++;          # check, if this segment is already calculated
        $p = s|(?=\Q$s\E)||g / (@_ - $m + 1); # calculate probability
             # N(x) is calculated using the substitution operator
             # with a zero-width look-ahead pattern
             # (golfed version without "\Q...\E", see below)
        $E -= $p * log($p); # update entropy
    }
    return $E
}

# Test

my @A = (
    2, 3, 4, 1, 2, 3, 0, 0, 3, 2, 3, 0, 2, 2, 4, 4, 4, 1, 1, 1, 0, 4, 1,
    2, 2, 4, 0, 1, 2, 3, 0, 2, 3, 2, 3, 2, 0, 1, 3, 4, 4, 0, 2, 1, 4, 3,
    0, 2, 4, 1, 0, 4, 0, 0, 2, 2, 0, 2, 3, 0, 0, 4, 4, 2, 3, 1, 3, 1, 1,
    3, 1, 3, 1, 0, 0, 2, 2, 4, 0, 3, 2, 2, 3, 0, 3, 3, 0, 0, 4, 4, 1, 0,
    2, 3, 0, 0, 1, 4, 4, 3
);

print "m = $_: ", E(@A, $_), "\n" for 1 .. @A;

結果:

m = 1: 1.59938036027528
m = 2: 3.06545141203611
m = 3: 4.06663334311518
m = 4: 4.41210802885304
m = 5: 4.53546705894451
m = 6: 4.55387689160055
m = 7: 4.54329478227001
m = 8: 4.53259949315326
m = 9: 4.52178857704904
...
m = 97: 1.38629436111989
m = 98: 1.09861228866811
m = 99: 0.693147180559945
m = 100: 0

記号:

文字列に基づくパターンマッチングが使用されるため、シンボルは整数に制限されません。シンボルの文字列表現には、区切り文字として使用されるため、カンマを含めることはできません。もちろん、異なるシンボルには異なる文字列表現が必要です。

ゴルフバージョンでは、記号の文字列表現にパターンの特殊文字を含めることはできません。追加の4バイト\Q... \E は、数値には必要ありません。


約1/4短くすることができますsub f{($s,$m,$r,%h)=@_;$h{x,@$s[$_..$_+$m-1]}++for 0..@$s-$m;$r-=($_/=@$s-$m+1)*log for values %h;return$r}。$s参照はどこですか$rあり、最初の割り当てでundefに%hリセットされます。リストはハッシュキーであり(残念ながら少しの助けが$;ありますx-残念ながら)、一般的にはそれほど複雑ではありません。
— user2846289 14年

@VadimR:賢い!私が提案する大幅な変更のため、あなたは答えを出します。のスペースvalues %hは必要ないため、ソリューションに必要なのは106バイトだけです。
— ヘイコオベルディク14年

2

Python 127 152B 138B

import math
def E(A,m):N=len(A)-m+1;R=range(N);return sum(math.log(float(N)/b) for b in [sum(A[i:i+m]==A[j:j+m] for i in R) for j in R])/N

ルールをこれ以上破らないように調整され、アルゴリズムがわずかに削減されました。小さく調整

古いバージョン:

import math
def E(A,m):
 N=len(A)-m+1
 B=[A[i:i+m] for i in range(N)]
 return sum([math.log(float(N)/B.count(b)) for b in B])/N

初めてのPythonスクリプト!実際にご覧ください:http : //pythonfiddle.com/entropy


これまでのところ素晴らしいですが、残念ながら、このcount関数の使用は「特定のブロックxの出現回数をカウントする」ため、ルールに反します。
— Wrzlprmft 14年

また、いくつかのゴルフのヒント:最初の行を除くすべての行を1行に詰め込んで(;必要に応じて区切ります)、一部のキャラクターを保存できます。また、最後の行の角括弧は必要ありません。
— Wrzlprmft 14年

いい答え。繰り返しますが、いくつかのゴルフのヒント:ブール値から整数への完全な変換(つまりand 1 or 0)は不要です。また、を事前定義することにより、一部の文字を保存できますrange(N)。
— Wrzlprmft 14年

1

Numpyを使用したPython、146 143バイト

約束どおり、ここに私自身の解決策があります。非負整数の入力が必要です:

from numpy import*
def e(A,m):
    B=zeros(m*[max(A)+1]);j=0
    while~len(A)<-j-m:B[tuple(A[j:j+m])]+=1;j+=1
    return -sum(x*log(x)for x in B[B>0]/j)

欠点は、これにより大容量mまたは大容量のメモリがバーストすることですmax(A)。

以下は、主に未公開でコメント付きのバージョンです。

from numpy import *
def e(A,m):
    B = zeros(m*[max(A)+1])          # Generate (max(A)+1)^m-Array of zeroes for counting.
    for j in range(len(A)-m+1):
        B[tuple(A[j:j+m])] += 1      # Do the counting by directly using the array slice
                                     # for indexing.
    C = B[B>0]/(len(A)-m+1)          # Flatten array, take only non-zero entries,
                                     # divide for probability.
    return -sum(x*log(x) for x in C) # Calculate entropy

1

MATLAB

function E =BlockEntropy01(Series,Window,Base )

%-----------------------------------------------------------
% Calculates BLOCK ENTROPY of Series
% Series: a Vector of numbers
% Base: 2 or 10 (affects logarithm of the Calculation)
% for 2 we use log2, for 10 log10
% Windows: Length of the "Sliding" BLOCK
% E: Entropy
%-----------------------------------------------------------
% For the ENTROPY Calculations
% http://matlabdatamining.blogspot.gr/2006/....
% 11/introduction-to-entropy.html
% BlogSpot: Will Dwinnell
%-----------------------------------------------------------
% For the BLOCK ENTROPY
% http://codegolf.stackexchange.com/...
% questions/24316/calculate-the-block-entropy
%-----------------------------------------------------------
% Test (Base=10)
% Series=[2, 3, 4, 1, 2, 3, 0, 0, 3, 2, 3, 0, ....
%     2, 2, 4, 4, 4, 1, 1, 1, 0, 4, 1,2, 2, 4, 0, ....
%     1, 2, 3, 0, 2, 3, 2, 3, 2, 0, 1, 3, 4, 4, 0, ....
%     2, 1, 4, 3,0, 2, 4, 1, 0, 4, 0, 0, 2, 2, 0, ....
%     2, 3, 0, 0, 4, 4, 2, 3, 1, 3, 1, 1,3, 1, 3, 1, ....
%     0, 0, 2, 2, 4, 0, 3, 2, 2, 3, 0, 3, 3, 0, 0, 4, ...
%     4, 1, 0,2, 3, 0, 0, 1, 4, 4, 3]';
%
% Results 
%
% Window=1: 1.599
% Window=2: 3.065
% Window=3: 4.067
% Window=4: 4.412
% Window=5: 4.535
% Window=6: 4.554
%-----------------------------------------------------------
n=length(Series);
D=zeros(n,Window); % Pre Allocate Memory
for k=1:Window;    D(:,k)=circshift(Series,1-k);end
D=D(1:end-Window+1,:); % Truncate Last Part
%
% Repace each Row with a "SYMBOL"
% in this Case a Number ...............
[K l]=size(D);
for k=1:K; MyData(k)=polyval(D(k,:),Base);end
clear D
%-----------------------------------------------------------
% ENTROPY CALCULATIONS on MyData
% following  Will Dwinnell
%-----------------------------------------------------------
UniqueMyData = unique(MyData);
nUniqueMyData = length(UniqueMyData);
FreqMyData = zeros(nUniqueMyData,1); % Initialization
for i = 1:nUniqueMyData
    FreqMyData(i) = ....
        sum(double(MyData == UniqueMyData(i)));
end
% Calculate sample class probabilities
P = FreqMyData / sum(FreqMyData);
% Calculate entropy in bits
% Note: floating point underflow is never an issue since we are
%   dealing only with the observed alphabet
if Base==10
    E= -sum(P .* log(P));
elseif BASE==2
    E= -sum(P .* log2(P));
else
end
end

WITH TEST SCRIPT 
%-----------------------------------------------------------
Series=[2, 3, 4, 1, 2, 3, 0, 0, 3, 2, 3, 0, ....
    2, 2, 4, 4, 4, 1, 1, 1, 0, 4, 1,2, 2, 4, 0, ....
    1, 2, 3, 0, 2, 3, 2, 3, 2, 0, 1, 3, 4, 4, 0, ....
    2, 1, 4, 3,0, 2, 4, 1, 0, 4, 0, 0, 2, 2, 0, ....
    2, 3, 0, 0, 4, 4, 2, 3, 1, 3, 1, 1,3, 1, 3, 1, ....
    0, 0, 2, 2, 4, 0, 3, 2, 2, 3, 0, 3, 3, 0, 0, 4, ...
    4, 1, 0,2, 3, 0, 0, 1, 4, 4, 3]';
Base=10;
%-----------------------------------------------------------
for Window=1:6
    E =BlockEntropy01(Series,Window,Base )
end

3
PPCG.SEへようこそ!これはコードゴルフチャレンジであり、目標はできるだけ少ないキャラクターで問題を解決することです。コメント、最小限の空白、1文字の変数名(および考えられるその他のショートカット)のないバージョンと、そのコードのバイト数を追加してください。
— マーティンエンダー14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.