Hitung estimasi entropi histogram string


19

Tulis program atau fungsi yang memperkirakan entropi Shannon dari string yang diberikan.

Jika string memiliki n karakter, d karakter berbeda , x i adalah karakter berbeda ke- i , dan P (x i ) adalah probabilitas karakter tersebut muncul dalam string, maka estimasi entropi Shannon kami untuk string tersebut diberikan oleh:

H = -n \ jumlah \ limit_ {i = 1} ^ d P (x_i) \ log_2 P (x_i)

Untuk estimasi dalam tantangan ini, kita mengasumsikan bahwa probabilitas suatu karakter yang muncul dalam sebuah string hanyalah berapa kali itu terjadi dibagi dengan jumlah total karakter.

Jawaban Anda harus akurat setidaknya 3 digit setelah periode.


Kasus uji:

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

Menentang tantangan yang biasa saya lakukan, yang ini terlihat rumit, tetapi sebenarnya cukup sederhana :)
orlp


Apakah aman untuk mengasumsikan ASCII yang dapat dicetak untuk string input?
AdmBorkBork

@TimmyD Tidak. Semua string yang didukung oleh tipe string bahasa Anda.
orlp

Sayangnya, Mathematica Entropymenghitung bit per karakter, bukan total untuk string; oh well ...
2012rcampion

Jawaban:


2

Jelly, 11 8 byte

ċЀ÷Ll.S

Cobalah online!


Bisakah saya bertanya, bagaimana Anda memasukkan karakter-karakter itu? Dengan salin dan tempel?
Bálint

Setidaknya di Linux, semuanya dapat diketik di papan ketik internasional AS.
Dennis

11

Python 3.3+, 64 byte

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

Dapatkan math.log2dari solusi mbomb007 .


Jadi @orlp tidak memberi kami formula yang disederhanakan sepenuhnya, eh ...?
mbomb007

@ mbomb007 Tergantung untuk tujuan apa yang Anda sederhanakan. Menulis dalam hal probabilitas dan karakter yang berbeda adalah wajar sebagai definisi, tetapi untuk bermain golf lebih pendek untuk bekerja dengan jumlah dan mengulangi semua karakter.
xnor

1
Pyth menjawab dengan rumus Anda: pyth.herokuapp.com/... 8 bytes
Maltysen

2

APL, 18 14 byte

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

Ini adalah kereta fungsi monadik tanpa nama yang menerima string di sebelah kanan dan mengembalikan yang asli.

Seperti semua hal baik dalam hidup, ini menggunakan rumus xnor . Kami mendapatkan matriks boolean yang sesuai dengan kemunculan setiap karakter dalam string menggunakan ∘.=⍨, jumlah ini sepanjang sumbu pertama ( +/) untuk mendapatkan jumlah kemunculan masing-masing karakter, bagi panjang string dengan masing-masing, kemudian ambil basis log 2 ( 2⍟) dan jumlah.

Coba di sini

Disimpan 4 byte berkat Dennis!



1

JavaScript (ES6), 67 byte

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

Saya perlu menggunakan ~-s.splitkarena menerima string daripada regexps. Seperti biasa, mapketukan reducesatu byte.

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

1

Perl 5, 58 byte

Subrutin:

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

Ujung topi saya untuk xnor untuk formula.


-Ftidak berfungsi (dalam Strawberry, lagi pula) karena termasuk $/.
msh210

1

MATL , 14 byte

!Gu=stGn/Zl*s|

Cobalah online!

!      % 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#.=/~

Dipersingkat menggunakan ide dalam metode Dennis.

Pemakaian

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

Penjelasan

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
Saya tidak berpikir ini dianggap sebagai fungsi. Jika Anda menetapkan kode ke variabel, ia melakukan sesuatu yang sama sekali berbeda.
Dennis

@ Dennis Dari apa yang saya kumpulkan, tampaknya J menafsirkannya sebagai rantai komposisi, menggunakan 3 : '... y'dengan sintaks yang sama akan menjadi cara yang valid untuk mendefinisikannya sebagai fungsi. J menyatakan bahwa itu mengevaluasi dari kanan ke kiri, jadi saya telah refactored kode saya sebagai kereta. Saya tidak suka topi [:tapi saya tidak bisa menemukan cara lain untuk membuat kereta.
mil


0

Jolf, 26 byte

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

Coba di sini! (Perhatikan bahwa fungsi test suite borked.)

Penjelasan

_*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

Solusi sederhana. Versi 3.3 diperlukan untuk digunakan 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))

Cobalah online


Apakah Anda pikir ada sesuatu yang tidak perlu di sini? n*sum(s.count(c)/n
orlp

@ orlp Terima kasih. Saya awalnya memiliki fungsi terpisah untuk menemukan probabilitas, tetapi telah menyisipkannya di dalam dua kali dan menghapusnya untuk menghemat karakter.
mbomb007

Anda tidak harus menyimpan ndalam variabel sekarang karena Anda hanya menggunakannya sekali.
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;}

Detail coba online

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

Faktor, 98 byte

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

Ini adalah terjemahan langsung dari jawaban Python ini . Saya akan menambahkan penjelasan saat makan malam.


0

Racket, 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))))

Terjemahan dari jawaban Factor saya, jadi ini adalah terjemahan tidak langsung dari jawaban Python Kenny Lau.


0

k (32 byte)

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

Atau dalam q, terjemahannya tidak sesingkat itu tetapi lebih jelas:

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

0

Mathematica, 45 byte

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

Pemakaian

Ini mengembalikan hasil yang tepat sehingga kami memperkirakannya dengan 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]))

Penjelasan

Ambil input dari stdin dan bagi menjadi daftar karakter. (Sintaks kikuk inilah yang menyebabkan tantangan golf sangat sulit di R ...)

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

Tugas ini disembunyikan di dalam sebuah lengthperintah, jadi kami mendapatkan dua tugas dengan harga satu. Kami punya i, daftar karakter, dan lpanjangnya.

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

Sekarang kita menghitung entropi. R memiliki fungsi tableyang bagus yang mengembalikan jumlah semua nilai unik. Untuk input This is a test, table(i)kembali

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

Ini diindeks oleh karakter, yang bagus, karena kita dapat menggunakan isebagai indeks untuk mendapatkan hitungan setiap karakter, seperti:

> 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 

Sisa kode selanjutnya merupakan implementasi sederhana dari rumus entropi, diputar sedikit.

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

Simpan dua byte (juga kiriman Anda tidak berfungsi pada TIO)
JayCe


0

C #, 159 byte

Golf:

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)+"";}}

Tidak Disatukan:

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) + "";
}

Uji:

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 Bytes

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

Tes:

This is a test. = 45.09358393449714
00001111 = 8.0
cwmfjordbankglyphsvextquiz = 122.21143275636976
aaaaaaaa = -0.0
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.