Tính toán ước lượng entropy của một chuỗi


19

Viết chương trình hoặc hàm ước tính entropy Shannon của một chuỗi đã cho.

Nếu một chuỗi có n ký tự, d ký tự riêng biệt , x i là ký tự riêng biệt thứ iP (x i ) là xác suất của ký tự đó xảy ra trong chuỗi, thì ước tính entropy Shannon của chúng tôi cho chuỗi đó được đưa ra bởi:

H = -n \ sum \ Giới hạn_ {i = 1} ^ d P (x_i) \ log_2 P (x_i)

Đối với ước tính trong thử thách này, chúng tôi giả định rằng xác suất của một ký tự xuất hiện trong một chuỗi chỉ đơn giản là số lần nó xảy ra chia cho tổng số ký tự.

Câu trả lời của bạn phải chính xác đến ít nhất 3 chữ số sau khoảng thời gian.


Các trường hợp thử nghiệm:

"This is a test.", 45.094
"00001111", 8.000
"cwmfjordbankglyphsvextquiz", 122.211
"             ", 0.0

Đối lập với những thách thức thông thường của tôi, điều này có vẻ phức tạp, nhưng thực ra khá đơn giản :)
orlp


Có an toàn không khi giả sử ASCII có thể in được cho chuỗi đầu vào?
admBorkBork

@TimmyD Không. Bất kỳ chuỗi nào mà loại chuỗi ngôn ngữ của bạn hỗ trợ.
orlp

Thật không may, Mathicala Entropytính số bit trên mỗi ký tự, không phải tổng số cho chuỗi; ồ ...
2012rcampion

Câu trả lời:


2

Thạch, 11 8 byte

ċЀ÷Ll.S

Hãy thử trực tuyến!


Cho tôi hỏi, làm thế nào bạn nhập những ký tự đó? Với bản sao và dán?
Bálint

Ít nhất là trên Linux, tất cả chúng đều có thể được gõ trên bàn phím quốc tế của Hoa Kỳ.
Dennis

11

Python 3,3+, 64 byte

import math
lambda s:sum(math.log2(len(s)/s.count(c))for c in s)

math.log2từ giải pháp của mbomb007 .


Vì vậy, @orlp đã không cung cấp cho chúng tôi một công thức đơn giản hóa hoàn toàn, eh ...?
mbomb007

@ mbomb007 Tùy thuộc vào mục đích bạn đang đơn giản hóa. Viết nó theo xác suất và các ký tự riêng biệt là điều tự nhiên như một định nghĩa, nhưng đối với việc chơi golf, nó ngắn hơn để làm việc với số lượng và lặp lại trên tất cả các ký tự.
xnor

1
Câu trả lời thứ ba với công thức của bạn: pyth.herokuapp.com/ Triều 8 byte
Maltysen

2

APL, 18 14 byte

+/2⍟≢÷(+/∘.=⍨)

Đây là một hàm chức năng đơn âm, không tên, chấp nhận một chuỗi bên phải và trả về một số thực.

Giống như tất cả những điều tốt đẹp trong cuộc sống, điều này sử dụng công thức của xnor . Chúng ta có một ma trận booleans tương ứng với các lần xuất hiện của từng ký tự trong chuỗi bằng cách sử dụng ∘.=⍨, tính tổng này dọc theo trục đầu tiên ( +/) để lấy số lần xuất hiện của mỗi ký tự, chia độ dài của chuỗi cho mỗi ký tự, sau đó lấy cơ sở log 2 ( 2⍟) và tổng hợp.

Hãy thử nó ở đây

Đã lưu 4 byte nhờ Dennis!



1

JavaScript (ES6), 67 byte

s=>[...s].map(c=>t+=Math.log2(s.length/~-s.split(c).length),t=0)&&t

Tôi cần sử dụng ~-s.splitvì điều đó chấp nhận chuỗi chứ không phải regexps. Như thường lệ, mapnhịp đập reducecủa một byte.

s=>[...s].reduce((t,c)=>t+Math.log2(s.length/~-s.split(c).length),0)

1

Perl 5, 58 byte

Một chương trình con:

{for$a(@a=split'',pop){$t+=(log@a/grep/\Q$a/,@a)/log 2}$t}

Một mẹo của tôi để xnor cho công thức.


-Fkhông hoạt động (trong Dâu, dù sao) bởi vì nó bao gồm $/.
msh210

1

MATL , 14 byte

!Gu=stGn/Zl*s|

Hãy thử trực tuyến!

!      % transpose implicit input into column vector
Gu     % row vector with unique elements of input
=      % test for equality, element-wise with broadcast
s      % sum of each column
tGn/   % duplicate. Divide by number of input characters
Zl     % binary logarithm
*      % element-wise multiplication
s      % sum of array
|      % absolute value. Display implicitly


1

J - 18 16 14 byte

1#.2^.#%1#.=/~

Rút ngắn bằng cách sử dụng ý tưởng trong phương pháp của Dennis.

Sử dụng

   f =: 1#.2^.#%1#.=/~
   f 'This is a test.'
45.0936
   f '00001111'
8
   f 'cwmfjordbankglyphsvextquiz'
122.211
   f '             '
0

Giải trình

1#.2^.#%1#.=/~  Input: string S
           =/~  Create a table testing for equality
        1#.     Convert each row from a list of base 1 digits to decimal
                This is equivalent to taking the sum and forms a list of tallies
      #         Get the length of S
       %        Divide the length by each tally
   2^.          Log base 2 of each
1#.             "Sum" those values and return

1
Tôi không nghĩ rằng điều này được coi là một chức năng. Nếu bạn gán mã cho một biến, nó sẽ làm một cái gì đó hoàn toàn khác.
Dennis

@Dennis Từ những gì tôi thu thập được, có vẻ như J diễn giải nó như một chuỗi các tác phẩm, sử dụng 3 : '... y'cùng một cú pháp sẽ là một cách hợp lệ để định nghĩa nó là một hàm. J nói rằng nó đánh giá từ phải sang trái, vì vậy tôi đã cấu trúc lại mã của mình dưới dạng một chuyến tàu. Tôi không thích mũ [:nhưng tôi không thể tìm thấy bất kỳ cách nào khác để làm một chuyến tàu.
dặm


0

Jolf, 26 byte

_*liuΜGμiEd*γ/l miLeHlimzγ

Hãy thử nó ở đây! (Lưu ý rằng chức năng của bộ kiểm tra bị borked.)

Giải trình

_*liuΜGμiEd*γ/l miLeHlimzγ
       μi                   unique members of i
      G  E                  split on ""
     Μ    d                 map over function
               _miLeH       match i with regex escaped member
             /l      li     divide length of (^) by length of i
            γ               γ = (^)
           *           mzγ  (^) * log_2(γ)
 *li                        (^) * length of i
_                           negate

0

Python 3.3+, 95 91 89 85 byte

Giải pháp đơn giản. Phiên bản 3.3 là bắt buộc để sử dụng math.log2.

import math
def f(s):C=s.count;return-sum(C(x)*math.log2(C(x)/len(s))for x in set(s))

Dùng thử trực tuyến


Bạn có nghĩ rằng có gì không cần thiết ở đây không? n*sum(s.count(c)/n
orlp

@orlp Cảm ơn. Ban đầu tôi có một chức năng riêng để tìm xác suất, nhưng đã dán nó vào bên trong hai lần và xóa nó để lưu ký tự.
mbomb007

Bây giờ bạn không phải lưu trữ ntrong một biến mà bạn chỉ sử dụng nó một lần.
Maltysen

0

Java 7, 207 byte

double C(String x,Map<Character,Integer>f){double H=0,g;for(char c:x.toCharArray())f.put(c,f.containsKey(c)?f.get(c)+1:1);for(char c:f.keySet()){g=f.get(c);H+=g*Math.log(g/x.length())/Math.log(2);}return-H;}

Chi tiết thử trực tuyến

double log2(double d) { return Math.log(d) / Math.log(2); }

double C(String x, Map<Character,Integer>f)
{
    double H=0,g;

    // frequency
    for(char c : x.toCharArray())
    {
        f.put(c, f.containsKey(c) ? f.get(c)+1 : 1);
    }

    // calculate entropy
    for(char c : f.keySet())
    {
        g = f.get(c);
        H += g * log2(g / x.length());
    }

    return -H;
}

0

Yếu tố, 98 byte

[ [ length ] [ dup [ [ = ] curry dupd count ] { } map-as nip ] bi [ / log 2 log / ] with map sum ]

Đây là bản dịch trực tiếp câu trả lời Python này . Tôi sẽ thêm một lời giải thích trong bữa tối.


0

Vợt, 130 byte

: c

#lang racket
(require math)(λ(S)(let([s(string->list S)])(sum(map(λ(c)(/(log(/(length s)(count(λ(x)(char=? c x))s)))(log 2)))s))))

Bản dịch câu trả lời Yếu tố của tôi, vì vậy đó là bản dịch gián tiếp câu trả lời Python của Kenny Lau.


0

k (32 byte)

{-+/c*(log c%n:+/c:#:'=x)%log 2}

Hoặc trong q, bản dịch không quá ngắn gọn nhưng rõ ràng hơn:

{neg sum c*2 xlog c%n:sum c:count each group x}

0

Toán học, 45 byte

Tr[Log[2,Tr@#/#]#]&@Values@CharacterCounts@#&

Sử dụng

Điều này trả về kết quả chính xác để chúng tôi ước tính chúng với N.

  f = Tr[Log[2,Tr@#/#]#]&@Values@CharacterCounts@#&
  f["This is a test."]//N
45.0936
  f["00001111"]//N
8.
  f["cwmfjordbankglyphsvextquiz"]//N
122.211
  f["             "]//N
0.

0

R, 67 byte

l=length(i<-strsplit(readline(),"")[[1]]);-sum(log2(l/table(i)[i]))

Giải trình

Lấy đầu vào từ stdin và chia nó thành một danh sách các ký tự. (Cú pháp khó hiểu này là lý do tại sao các thử thách chơi gôn rất khó trong R ...)

         i<-strsplit(readline(),"")[[1]])

Nhiệm vụ này được ẩn bên trong một lengthlệnh, vì vậy chúng tôi nhận được hai nhiệm vụ với giá của một. Chúng tôi có i, danh sách các ký tự, và l, độ dài của nó.

l=length(i<-strsplit(readline(),"")[[1]]);

Bây giờ chúng ta tính toán entropy. R có một hàm đẹp tabletrả về tổng của tất cả các giá trị duy nhất. Đối với đầu vào This is a test, table(i)trả về

> table(i)
i
  . a e h i s t T 
3 1 1 1 1 2 3 2 1

Điều này được lập chỉ mục bởi các ký tự, rất hay, vì sau đó chúng ta có thể sử dụng ilàm chỉ mục để lấy số lượng của mỗi ký tự, như vậy:

> table(i)[i]
i
T h i s   i s   a   t e s t . 
1 1 2 3 3 2 3 3 1 3 2 1 3 2 1 

Phần còn lại của mã sau đó là một triển khai đơn giản của công thức entropy, lật xung quanh một chút.

                                           -sum(log2(l/table(i)[i]))

Lưu hai byte (đồng thời, việc gửi của bạn không hoạt động trên TIO)
JayCe


0

C #, 159 byte

Chơi gôn

string f(string s){var l=s.Length;double sum=0;foreach(var item in s.GroupBy(o=>o)){double p=(double)item.Count()/l;sum+=p*Math.Log(p,2);}return(sum*=-l)+"";}}

Ung dung:

string f(string s)
{
  var l = s.Length;
  double sum = 0;
  foreach (var item in s.GroupBy(o => o))
  {
    double p = (double)item.Count() / l;
    sum += p * Math.Log(p, 2);
  }
  return (sum *= -l) + "";
}

Kiểm tra:

var codeGolf = new StringHistogramEntropyEstimation();
    Console.WriteLine(codeGolf.f("This is a test.")); //45.0935839298008
    Console.WriteLine(codeGolf.f("00001111")); //8
    Console.WriteLine(codeGolf.f("cwmfjordbankglyphsvextquiz")); //122.211432671668
    Console.WriteLine(codeGolf.f("             ")); //0

0

Groovy, 100 byte

{a->n=a.size();a.toList().unique().collect{p=a.count(it)/n;p*(Math.log(p)/Math.log(2.0f))}.sum()*-n}

Các xét nghiệm:

This is a test. = 45.09358393449714
00001111 = 8.0
cwmfjordbankglyphsvextquiz = 122.21143275636976
aaaaaaaa = -0.0
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.