计算块熵


12

我曾经需要编写一个函数,计算给定块大小下给定符号系列的块熵,结果很短。因此,我正在挑战您对这种功能进行编码。我没有告诉您我现在所做的事情(以及使用哪种语言),但是如果没有人首先提出相同或更好的想法,我会在一周左右的时间内告诉您。

块熵的定义:

给定一个符号序列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中出现的每x个大小为m的x上。(您可以选择任意合理的对数。)

限制和澄清:

  • 您的函数应将符号序列A以及块大小m作为参数。
  • 您可以假定符号表示为从零开始的整数或其他方便的格式。
  • 您的程序应该在理论上能够接受任何合理的论据,而实际上应该能够在标准计算机上计算示例案例(见下文)。
  • 允许内置函数和库,只要它们在一次调用中不执行大部分过程,即从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年

这不是习惯使用日志库2吗?
Jonathan Van Matre 2014年

最后的熵值为正,但概率的对数为负或零。因此,熵公式中缺少负号。
Heiko Oberdiek'3

@JonathanVanMatre:据我所知,这取决于对数中最常用的规则。无论如何,对于挑战来说并没有那么重要,因此您可以使用任何您想要的基础。
Wrzlprmft 2014年

@HeikoOberdiek:谢谢,我忘了。
Wrzlprmft

Answers:


6

Mathematica- 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

这是一个有点古板的版本:

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

PartitionTally没有边缘的情况下,它们被彻底破坏规则,因为它们是“从A中提取大小为m的所有块”和“计数的给定块x的出现的次数”分别地,在一个呼叫。尽管如此,毕竟我对Mathematica有所了解,如果没有它们,我将不会感到惊讶。
Wrzlprmft 2014年

1
@Wrzlprmft我添加了一个不太实用的版本,我在其中重新实现PartitionTally
Martin Ender 2014年

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

符号:

符号不限于整数,因为使用了基于字符串的模式匹配。符号的字符串表示形式不能包含逗号,因为它用作定界符。当然,不同的符号必须具有不同的字符串表示形式。

在高尔夫球版本中,符号的字符串表示形式不应包含特殊的图案字符。 数字不需要额外的四个字节\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,列表是哈希键(在的帮助下$;,以及一些x-不幸的是,有些帮助),并且总体上来说,它的复杂程度有所降低。
user2846289 2014年

@VadimR:聪明!由于我建议进行重大更改,因此您可以做出答案。values %h不需要空间,因此您的解决方案仅需要106个字节。
Heiko Oberdiek

2

蟒蛇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 2014年

此外,还有一些打高尔夫球的技巧:您可以通过将除第一行以外的每一行都塞入一行(;如果需要,可以将其分隔开)来保存一些字符。另外,不需要最后一行的方括号。
Wrzlprmft 2014年

好答案。同样,有一些打高尔夫球的技巧:从布尔到整数(即and 1 or 0)的整个转换是不必要的。另外,您可以通过预定义来保存一些字符range(N)
Wrzlprmft 2014年

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!这是一个标准的高尔夫挑战赛,其目标是以尽可能少的字符来解决问题。请添加一个没有注释的版本,最少的空格和单字符变量名(以及您可以想到的任何其他快捷方式)以及该代码中的字节数。
Martin Ender 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.