คำนวณเอนโทรปีของบล็อก


12

ฉันเคยต้องเขียนฟังก์ชั่นที่คำนวณเอนโทรปีของบล็อกของชุดสัญลักษณ์ที่กำหนดสำหรับขนาดบล็อกที่กำหนดและรู้สึกประหลาดใจว่าผลลัพธ์สั้นเพียงใด ดังนั้นฉันขอท้าให้คุณ codegolf ฟังก์ชั่นดังกล่าว ฉันไม่ได้บอกคุณว่าฉันทำอะไรในตอนนี้ (และในภาษาใด) แต่ฉันจะทำในหนึ่งสัปดาห์หรือมากกว่านั้นถ้าไม่มีใครคิดเรื่องเดิมหรือแนวคิดที่ดีกว่ามาก่อน

คำจำกัดความของเอนโทรปีของบล็อก:

กำหนดลำดับสัญลักษณ์ A = A_1, …, A_n และขนาดบล็อก m:

  • บล็อกของขนาด m คือส่วนขององค์ประกอบต่อเนื่องของลำดับสัญลักษณ์คือ A_i, …, A_ (i + m − 1) สำหรับ i ที่เหมาะสม
  • ถ้า x เป็นลำดับสัญลักษณ์ของขนาด m, N (x) หมายถึงจำนวนบล็อกของ A ซึ่งเหมือนกับ x
  • p (x) คือความน่าจะเป็นที่บล็อกจาก A นั้นเหมือนกับลำดับสัญลักษณ์ x ของขนาด m คือ p (x) = N (x) / (n − m + 1)
  • ในที่สุดการบล็อกเอนโทรปีสำหรับบล็อกขนาด m ของ A คือค่าเฉลี่ยของ −log (p (x)) ในทุกบล็อค x ของขนาด m ใน A หรือ (ซึ่งเทียบเท่า) ผลรวมของ −p (x) · log (p) (x)) ในทุก ๆ x ขนาด m ที่เกิดขึ้นใน A (คุณสามารถเลือกลอการิทึมที่เหมาะสมที่คุณต้องการ)

ข้อ จำกัด และการชี้แจง:

  • ฟังก์ชันของคุณควรใช้ลำดับสัญลักษณ์ A และขนาดบล็อก m เป็นอาร์กิวเมนต์
  • คุณอาจสันนิษฐานว่าสัญลักษณ์แสดงเป็นจำนวนเต็มตามศูนย์หรือในรูปแบบที่สะดวกอื่น
  • โปรแกรมของคุณควรมีความสามารถในการโต้แย้งเหตุผลในทางทฤษฎีและในความเป็นจริงควรสามารถคำนวณกรณีตัวอย่าง (ดูด้านล่าง) บนคอมพิวเตอร์มาตรฐาน
  • อนุญาตให้มีฟังก์ชั่นและไลบรารีในตัวได้ตราบใดที่มันไม่ได้ทำการประมวลผลส่วนใหญ่ในการโทรครั้งเดียวนั่นคือการแยกบล็อคทั้งหมดของขนาด m จาก A นับจำนวนการเกิดขึ้นของบล็อก 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 สำหรับสิ่งนี้
Jonathan Van Matre

ค่าของเอนโทรปีในตอนท้ายเป็นค่าบวก แต่ลอการิทึมของความน่าจะเป็นเป็นค่าลบหรือศูนย์ ดังนั้นเครื่องหมายลบจะหายไปในสูตรสำหรับเอนโทรปี
Heiko Oberdiek

@JonathanVanMatre: เท่าที่ฉันรู้มันขึ้นอยู่กับระเบียบวินัยที่เป็นที่ใช้มากที่สุดของลอการิทึม อย่างไรก็ตามมันไม่สำคัญมากสำหรับความท้าทายและทำให้คุณสามารถใช้ฐานที่คุณต้องการ
Wrzlprmft

@HeikoOberdiek: ขอบคุณฉันลืมไปแล้ว
Wrzlprmft

คำตอบ:


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 bytesแต่ก็ผิดกฎ

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]&

Ungolfed:

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ไม่ใช่กรณีเขตแดนพวกเขากำลังทำลายกฎโดยสิ้นเชิงเนื่องจาก "การสกัดบล็อกทั้งหมดของขนาด m จาก A" และ "นับจำนวนการเกิดขึ้นของบล็อก x ที่กำหนด" ตามลำดับในการเรียกครั้งเดียว ถึงกระนั้นหลังจากทั้งหมดที่ฉันรู้เกี่ยวกับ Mathematica ฉันจะไม่แปลกใจถ้ามีวิธีการแก้ปัญหาที่เหมาะสมโดยไม่มีพวกเขา
Wrzlprmft

1
@Wrzlprmft ฉันได้เพิ่มรุ่นที่ไม่ให้แข็งแรงเล่นกอล์ฟที่ฉัน reimplement และPartition Tally
Martin Ender

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

สัญลักษณ์:

สัญลักษณ์ไม่ได้ถูก จำกัด อยู่ที่จำนวนเต็มเนื่องจากการจับคู่รูปแบบตามสตริงใช้ การแทนค่าสตริงของสัญลักษณ์ต้องไม่มีเครื่องหมายจุลภาคเนื่องจากใช้เป็นตัวคั่น แน่นอนสัญลักษณ์ที่แตกต่างต้องมีการแทนค่าสตริงที่แตกต่างกัน

ในเวอร์ชัน golfed การแทนค่าสตริงของสัญลักษณ์ไม่ควรมีอักขระพิเศษของรูปแบบ ไม่จำเป็นต้องเพิ่มสี่ไบต์\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ถูกรีเซ็ตเป็นundefด้วยการกำหนดที่ 1 รายการคือคีย์แฮช (ด้วยความช่วยเหลือเล็กน้อย$;และบางอันx- โชคไม่ดี) และโดยทั่วไปแล้วฉันคิดว่าซับซ้อนน้อยลงเล็กน้อย
2846289

@VadimR: ฉลาด! เนื่องจากการเปลี่ยนแปลงที่สำคัญที่ฉันแนะนำคุณจึงต้องตอบ values %hไม่จำเป็นต้องใช้พื้นที่ในดังนั้นวิธีการแก้ปัญหาของคุณต้องการเพียง 106 ไบต์
Heiko Oberdiek

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

นอกจากนี้เคล็ดลับการเล่นกอล์ฟ: คุณสามารถบันทึกอักขระบางตัวได้โดยยัดเยียดทุกบรรทัดยกเว้นตัวแรกเป็นตัวเดียว (คั่นด้วย;ถ้าจำเป็น) นอกจากนี้ยังไม่จำเป็นต้องใช้วงเล็บเหลี่ยมในบรรทัดสุดท้าย
Wrzlprmft

คำตอบที่ดี เคล็ดลับการเล่นกอล์ฟอีกครั้ง: การแปลงทั้งหมดจากบูลีนเป็นจำนวนเต็ม (เช่นand 1 or 0) ไม่จำเป็น นอกจากนี้คุณยังสามารถบันทึกตัวอักษรบางตัวโดย range(N)predefining
Wrzlprmft

1

Python กับ Numpy, 146 143 Bytes

ตามที่สัญญานี่คือทางออกของฉันเอง มันต้องมีการป้อนข้อมูลของจำนวนเต็มไม่ลบ:

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! นี่คือความท้าทายของการเล่นกอล์ฟซึ่งเป้าหมายคือการแก้ปัญหาด้วยตัวละครน้อยที่สุด โปรดเพิ่มรุ่นที่ไม่มีความคิดเห็นชื่อช่องว่างขั้นต่ำและชื่อตัวแปรอักขระเดี่ยว (และทางลัดอื่น ๆ ที่คุณนึกถึง) รวมถึงจำนวนไบต์ในรหัสนั้น
Martin Ender
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.