블록 엔트로피 계산


12

주어진 블록 크기에 대해 주어진 심볼 시리즈의 블록 엔트로피를 계산하는 함수를 작성해야했고 결과가 얼마나 짧은 지 놀랐습니다. 따라서 나는 당신이 그런 기능을 codegolf하도록 도전합니다. 나는 내가 지금 무엇을했는지 (그리고 어떤 언어로) 말하지는 않지만, 일주일 정도 후에 같은 아이디어 나 더 좋은 아이디어를 찾지 못한 사람은 1 주일 정도 후에 할 것입니다.

블록 엔트로피의 정의 :

심볼 시퀀스 A = A_1,…, A_n 및 블록 크기 m이 주어지면 :

  • 크기 m의 블록은 임의의 적절한 i에 대한 심볼 시퀀스의 m 개의 연속적인 요소, 즉 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에 대해 (원하는 합리적인 로그를 선택할 수 있습니다.)

제한 사항 및 설명 :

  • 함수는 기호 시퀀스 A와 블록 크기 m을 인수로 사용해야합니다.
  • 기호가 0부터 시작하는 정수 또는 다른 편리한 형식으로 표시된다고 가정 할 수 있습니다.
  • 귀하의 프로그램은 이론적으로 합리적인 논쟁을 할 수 있어야하며 실제로는 표준 컴퓨터에서 사례를 계산할 수 있어야합니다 (아래 참조).
  • 내장 함수 및 라이브러리는 한 번의 호출로 프로 시저의 많은 부분을 수행하지 않는 한 (예 : 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 2014 년

이것을 위해 log base 2를 사용하는 것이 관습 적이 지 않습니까?
Jonathan Van Matre

끝의 엔트로피 값은 양수이지만 확률의 로그는 음수 또는 0입니다. 따라서 엔트로피 수식에 음수 부호가 없습니다.
Heiko Oberdiek 2016 년

@JonathanVanMatre : 내가 아는 한, 그것은 가장 많이 사용되는 로그의 징계에 달려 있습니다. 어쨌든, 도전에는 그다지 중요하지 않으므로 원하는베이스를 합리적으로 사용할 수 있습니다.
Wrzlprmft

@HeikoOberdiek : 고마워요.
Wrzlprmft

답변:


6

수학 -81 78 75 72 67 65 62 56 바이트

나는 Mathematica에서 골프를 한 적이 없었으므로 개선의 여지가 있다고 가정합니다. 이 기능 PartitionTally기능 으로 인해 규칙을 준수하지는 않지만 매우 깔끔하므로 게시 할 것이라고 생각했습니다.

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

다음은 다소 ungolfed 버전입니다.

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그들은 하나의 호출에서, "A에서 크기 m의 모든 블록을 추출"각각 "소정의 블록 (X)의 발생 횟수를 카운트"대로 경계선 경우, 그들은 명백한 규칙 위반되는 것은 아니다. 그래도 Mathematica에 대해 아는 후에도 해결책이 없다면 놀라지 않을 것입니다.
Wrzlprmft

1
나는 다시 구현하지 않은 소위 golfed 버전을 추가 한 @Wrzlprmft PartitionTally.
Martin Ender

3

펄, 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그리고 %h리셋됩니다 미확정 리스트는 해시 (의 작은 도움으로 열쇠, 첫번째 과제로 $;, 일부 x- 불행하게도) 덜 일반적으로 복잡하고, 비트, 나는 생각한다.
user2846289

@VadimR : 영리한! 내가 제안하는 실질적인 변화 때문에, 당신은 대답을합니다. 공간 values %h이 필요하지 않으므로 솔루션에는 106 바이트 만 필요합니다.
Heiko Oberdiek

2

파이썬 127152B 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

내 첫 파이썬 스크립트! 실제로 확인하십시오 : http://pythonfiddle.com/entropy


지금까지는 좋지만 안타깝게도이 count함수 의 사용 은“주어진 블록 x의 발생 횟수를 세는 것”이므로 규칙에 맞지 않습니다.
Wrzlprmft 2016 년

또한 몇 가지 골프 팁 : 첫 번째 줄을 제외한 모든 줄을 한 줄에 넣으면 일부 문자를 저장할 수 있습니다 ( ;필요한 경우 구분 ). 또한 마지막 줄의 대괄호는 필요하지 않습니다.
Wrzlprmft 2016 년

좋은 대답입니다. 다시 한 번, 일부 골프 팁 : 부울에서 정수 (즉, and 1 or 0) 로의 전체 변환 은 필요하지 않습니다. 또한을 사전 정의하여 일부 문자를 저장할 수 있습니다 range(N).
Wrzlprmft

1

NumPy와, 파이썬 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).

다음은 대부분 ungolfed 및 주석이 달린 버전입니다.

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에 오신 것을 환영합니다! 이것은 가능한 한 적은 문자로 문제를 해결하는 것이 목표 인 코드 골프 도전입니다. 주석이없는 버전, 최소한의 공백 및 단일 문자 변수 이름 (및 생각할 수있는 다른 단축키) 및 해당 코드의 바이트 수를 추가하십시오.
마틴 엔더
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.