Blok entropisini hesaplayın


12

Bir keresinde, belirli bir blok boyutu için belirli bir sembol serisinin blok entropisini hesaplayan ve sonucun ne kadar kısa olduğuna şaşırdım bir fonksiyon yazmam gerekiyordu. Böylece size böyle bir işlevi kodlamada meydan okuyorum. Sana şimdilik ne yaptığımı (ve hangi dilde) söylemiyorum, ama önce kimse aynı veya daha iyi fikirlerle gelmediyse bir hafta içinde yapacağım.

Blok entropinin tanımı:

A = A_1,…, A_n sembol sırası ve m blok boyutu verildiğinde:

  • M büyüklüğünde bir blok, herhangi bir uygun i için sembol dizisinin m ardışık elemanlarının bir segmentidir, yani A_i,…, A_ (i + m-1).
  • X, m boyutunda bir sembol dizisi ise, N (x), A'nın x ile aynı olan blok sayısını belirtir.
  • p (x), A'dan bir bloğun, m boyutunda bir sembol dizisi x ile özdeş olma olasılığıdır, yani p (x) = N (x) / (n − m + 1)
  • Son olarak, A blok boyutu m için blok entropisi, A boyutunda m boyutundaki x veya x eşdeğeri olan tüm bloklar üzerindeki −log (p (x)) ortalamasıdır ((p (x) · log (p (x)) A'da meydana gelen her bir m boyutunda x (İstediğiniz makul logaritmayı seçebilirsiniz.)

Kısıtlamalar ve açıklamalar:

  • İşlevin argüman olarak A sembol dizisini ve m blok boyutunu alması gerekir.
  • Sembollerin sıfır tabanlı tamsayılarla veya başka bir uygun biçimde temsil edildiğini varsayabilirsiniz.
  • Programınız teoride makul bir argüman alabilmeli ve gerçekte standart bir bilgisayarda örnek durumu (aşağıya bakınız) hesaplayabilmelidir.
  • Yerleşik işlevlere ve kitaplıklara, bir çağrıda yordamın büyük bölümlerini gerçekleştirmedikleri sürece, yani m boyutundaki tüm blokları A'dan ayıklayarak, belirli bir bloğun x oluşum sayısını sayarak veya entropileri hesapladıkları sürece izin verilir p değerleri dizisinden - bunları kendiniz yapmanız gerekir.

Ölçek:

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

Bu dizinin ilk blok entropileri (doğal logaritma için):

  • 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: Kurallarla ilgili çözüm sınır çizginizi düşünürseniz, yine de deneyebilirsiniz - gerçekten sadece çizgiler boyunca çözümlerden kaçınmak istiyorum entropy(probabilities(blocks(A,m))).
Wrzlprmft

Bunun için günlük tabanı 2'yi kullanmak geleneksel değil mi?
Jonathan Van Matre

Sondaki entropi değerleri pozitiftir, ancak bir olasılığın logaritması negatif veya sıfırdır. Bu nedenle entropi formülünde negatif bir işaret eksik.
Heiko Oberdiek

@JonathanVanMatre: Bildiğim kadarıyla, logaritmanın en çok kullanılan pasedisi olan disipline bağlı. Her neyse, meydan okuma için o kadar önemli olmamalı ve böylece makul olan herhangi bir üssü kullanabilirsiniz.
Wrzlprmft

@HeikoOberdiek: Teşekkürler, bunu unuttum.
Wrzlprmft

Yanıtlar:


6

Mathematica - 81 78 75 72 67 65 62 56 bayt

Daha önce Mathematica'da golf oynamadım, bu yüzden iyileştirme için yer var. Bu, Partitionve Tallyişlevleri nedeniyle kurallara tam olarak uymuyor , ancak oldukça düzgün, bu yüzden yine de göndereceğimi düşündüm.

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

Bu, herhangi bir sembol seti ile çalışır ve aşağıdaki gibi kullanılabilir

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

İşte biraz ungolfed versiyonu:

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

NDoğrudan sonucuna başvurursam muhtemelen daha hızlı çalışır Tally.

Bu arada, Mathematica'nın bunu 28 baytaEntropy indiren bir işlevi var , ama bu kesinlikle kurallara aykırı.

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

Öte yandan, yeniden uygulayan 128 baytlık bir sürüm Partitionve 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]]
)

Partitionve Tallysınırda olmadıkları durumlarda, bir çağrıda sırasıyla "m boyutundaki tüm blokları A'dan ayıklıyorlar ve" belirli bir x bloğunun gerçekleşme sayısını sayıyorlar ". Yine de, Mathematica hakkında bildiğim her şeyden sonra, onlarsız iyi bir çözüm olsaydı şaşırmazdım.
Wrzlprmft

1
@Wrzlprmft Ben yeniden uygulamak Partitionve o kadar golf değil bir sürüm ekledim ve Tally.
Martin Ender

3

Perl, 140 bayt

Aşağıdaki Perl betiği E, sembol dizisini alan bir işlevi ve ardından segment boyutunu bağımsız değişken olarak tanımlar .

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}

Test edilmemiş versiyon

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;

Sonuç:

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

Semboller:

Dizelere dayalı desen eşleşmesi kullanıldığından, semboller tamsayılarla sınırlı değildir. Bir sembolün dize olarak temsil edilmesi virgül içermemelidir, çünkü sınırlayıcı olarak kullanılır. Tabii ki, farklı sembollerin farklı dize gösterimleri olmalıdır.

Golfçü versiyonda, sembollerin dize gösterimi özel desen karakterleri içermemelidir. Sayılar için ek dört bayt \Q... \Egerekmez.


Yaklaşık 1/4 daha kısa olabilir 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}:; burada $sbir referans $rve 1. atama ile undef%h olarak sıfırlanır , listeler hash anahtarları (az yardımı ile ve bazı - ne yazık ki) ve genel olarak biraz daha az karmaşık, sanırım. $;x
Kullanıcı2846289

@VadimR: Zeki! Önerdiğim önemli değişiklikler nedeniyle bir cevap veriyorsunuz. İçindeki alana values %hihtiyaç yoktur, bu nedenle çözümünüzün yalnızca 106 bayta ihtiyacı vardır.
Heiko Oberdiek

2

Python 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

Artık kuralları ihlal etmeyecek ve biraz cuter algoritmasına sahip olacak şekilde ayarlandı. Daha küçük olacak şekilde ayarlandı

Eski versiyon:

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

İlk Python senaryom! Uygulamaya bakın: http://pythonfiddle.com/entropy


Şimdiye kadar güzel, ama ne yazık ki, countfonksiyonun kullanımı kurallara aykırıdır, çünkü “belirli bir x bloğunun oluşum sayısını sayar”.
Wrzlprmft

Ayrıca, bazı golf ipuçları: Birincisi hariç her satırı sıkıştırarak bazı karakterleri kaydedebilirsiniz ( ;gerekirse ayırın ). Ayrıca son satırdaki köşeli parantezlere gerek yoktur.
Wrzlprmft

Güzel cevap. Yine, bazı golf ipuçları: Boole'den tamsayıya (yani, and 1 or 0) tüm dönüşüm gereksizdir. Ayrıca, önceden tanımlayarak bazı karakterleri kaydedebilirsiniz range(N).
Wrzlprmft

1

Numpy ile Python 146 143 Bayt

Söz verdiğim gibi, işte benim kendi çözümüm. Negatif olmayan bir tamsayı girişi gerektirir:

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)

Dezavantajı bu büyük bir kitle için hafızanızı patlamaları olmasıdır mya max(A).

İşte çoğunlukla ungolfed ve yorumlanmış sürüm:

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'ye hoş geldiniz! Bu, mümkün olan en az karakterde bir sorunu çözmek olan bir kod golf mücadelesidir. Lütfen yorum içermeyen bir sürüm, minimum boşluk ve tek karakterlik değişken adları (ve aklınıza gelebilecek diğer kısayollar) yanı sıra bu koddaki bayt sayısını ekleyin.
Martin Ender
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.