Oblicz szacunkową entropię histogramu ciągu

19

Napisz program lub funkcję, która oszacuje entropię Shannona danego ciągu.

Jeśli łańcuch ma n znaków, d różnych znaków, x i jest i- tym odrębnym znakiem, a P (x i ) jest prawdopodobieństwem wystąpienia tego znaku w ciągu, wówczas naszą ocenę entropii Shannona dla tego łańcucha podaje:

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

Do oszacowania w tym wyzwaniu zakładamy, że prawdopodobieństwo wystąpienia znaku w ciągu jest po prostu liczbą jego wystąpienia podzieloną przez całkowitą liczbę znaków.

Twoja odpowiedź musi zawierać co najmniej 3 cyfry po upływie tego okresu.


Przypadki testowe:

"This is a test.", 45.094
"00001111", 8.000
"cwmfjordbankglyphsvextquiz", 122.211
"             ", 0.0
orlp
źródło
W przeciwieństwie do moich zwykłych wyzwań, ten wygląda na skomplikowany, ale w rzeczywistości jest dość prosty :)
lub
Powiązane: codegolf.stackexchange.com/q/24316
msh210 25.04.2016
Czy bezpiecznie jest założyć drukowalny ASCII dla ciągu wejściowego?
AdmBorkBork
@TimmyD Nie. Dowolny ciąg obsługiwany przez typ Twojego języka.
lub
Niestety, Mathematica Entropyzlicza bity na znak, nie całkowite dla łańcucha; no cóż ...
2012rcampion 26.04.16

Odpowiedzi:

2

Galaretka, 11 8 bajtów

ċЀ÷Ll.S

Wypróbuj online!

Dennis
źródło
Czy mogę zapytać, jak wpisać te postacie? Z kopiowaniem i wklejaniem?
Bálint,
Przynajmniej w Linuksie wszystkie można pisać na klawiaturze międzynarodowej w USA.
Dennis
11

Python 3.3+, 64 bajty

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

Dostałem math.log2z rozwiązania mbomb007 .

xnor
źródło
Więc @orlp nie dał nam w pełni uproszczonej formuły, co ...?
mbomb007
@ mbomb007 Zależy od tego, w jakim celu upraszczasz. Pisanie w kategoriach prawdopodobieństwa i odrębnych postaci jest z natury naturalne, ale w golfa krótsza jest praca z liczeniem i powtarzanie wszystkich postaci.
xnor
1
Odpowiedz na pytanie z formułą: pyth.herokuapp.com/… 8 bajtów
Maltysen
2

APL, 18 14 bajtów

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

Jest to nienazwany, monadyczny ciąg funkcji, który przyjmuje ciąg po prawej stronie i zwraca wartość rzeczywistą.

Podobnie jak wszystkie dobre rzeczy w życiu, wykorzystuje on formułę xnor . Otrzymujemy macierz booleanów odpowiadających wystąpieniom każdego znaku w ciągu używającym∘.=⍨ , zsumuj to wzdłuż pierwszej osi ( +/), aby uzyskać liczbę wystąpień każdego znaku, podziel długość łańcucha przez każdy, a następnie weź podstawę logarytmu 2 (2⍟ ) i suma.

Wypróbuj tutaj

Zaoszczędź 4 bajty dzięki Dennisowi!

Alex A.
źródło
1

MATL, 17 bajtów

S4#Y'ts/tZl*sGn_*

Wypróbuj online!

zlewka
źródło
Możesz być w stanie zaoszczędzić trochę bajtów za pomocąYm
Luis Mendo
1

JavaScript (ES6), 67 bajtów

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

Muszę użyć, ~-s.splitponieważ akceptuje ciągi zamiast wyrażeń regularnych. Jak zwykle mapbije reducebajt.

s=>[...s].reduce((t,c)=>t+Math.log2(s.length/~-s.split(c).length),0)
Neil
źródło
1

Perl 5, 58 bajtów

Podprogram:

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

Czubek mojego kapelusza dla Xnora dla formuły.

msh210
źródło
-Fnie działa (w każdym razie Strawberry), ponieważ zawiera $/.
msh210,
1

MATL , 14 bajtów

!Gu=stGn/Zl*s|

Wypróbuj 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
Luis Mendo
źródło
1

Julia, 37 bajtów

x->sum(log2(endof(x)./sum(x.==x',1)))

Bierze tablicę znaków jako dane wejściowe. Wypróbuj online!

Dennis
źródło
1

J - 18 16 14 bajtów

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

Skrócony przy użyciu pomysłu w metodzie Dennisa.

Stosowanie

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

Wyjaśnienie

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
mile
źródło
1
Nie sądzę, że liczy się to jako funkcja. Jeśli przypiszesz kod do zmiennej, robi to coś zupełnie innego.
Dennis
@Dennis Z tego, co zbieram, wydaje się, że J interpretuje to jako ciąg kompozycji, przy użyciu 3 : '... y'tej samej składni byłby prawidłowy sposób zdefiniowania go jako funkcji. J stwierdza, że ​​ocenia od prawej do lewej, więc zreorganizowałem kod jako pociąg. Nie lubię czapek, [:ale nie mogę znaleźć innego sposobu na pociąg.
mil
0

Jolf, 26 bajtów

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

Wypróbuj tutaj! (Uwaga: funkcja zestawu testów jest błędna).

Wyjaśnienie

_*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
Conor O'Brien
źródło
0

Python 3.3+, 95 91 89 85 bajtów

Proste rozwiązanie. Wymagana jest wersja 3.3 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))

Wypróbuj online

mbomb007
źródło
Myślisz, że jest tu coś niepotrzebnego? n*sum(s.count(c)/n
lub
@orlp Thanks. Pierwotnie miałem osobną funkcję do znalezienia prawdopodobieństwa, ale wkleiłem ją do środka dwa razy i usunąłem, aby zapisać znaki.
mbomb007
Nie musisz już przechowywać nzmiennej, ponieważ używasz jej tylko raz.
Maltysen
0

Java 7, 207 bajtów

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;}

Szczegółowa próba 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;
}
Khaled.K
źródło
0

Współczynnik, 98 bajtów

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

To jest bezpośrednie tłumaczenie tej odpowiedzi w języku Python . Dodam wyjaśnienie przy obiedzie.

kot
źródło
0

Rakieta, 130 bajtów

:do

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

Tłumaczenie mojej odpowiedzi Factor, więc jest to pośrednie tłumaczenie odpowiedzi Pythona Kenny'ego Lau.

kot
źródło
0

k (32 bajty)

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

Albo w q, tłumaczenie nie jest wcale takie krótkie, ale jaśniejsze:

{neg sum c*2 xlog c%n:sum c:count each group x}
skeevey
źródło
0

Mathematica, 45 bajtów

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

Stosowanie

To zwraca dokładne wyniki, więc przybliżamy je 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.
mile
źródło
0

R, 67 bajtów

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

Wyjaśnienie

Pobierz dane wejściowe ze standardowego wejścia i podziel je na listę znaków. (Ta niezdarna składnia jest powodem, dla którego wyzwania w golfie strunowym są tak trudne w R ...)

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

To zadanie jest ukryte w lengthpoleceniu, więc dostajemy dwa zadania w cenie jednego. Mamy ilistę znaków i lich długość.

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

Teraz obliczamy entropię. R ma ładną funkcję, tablektóra zwraca liczbę wszystkich unikalnych wartości. Dla wejściowych This is a test, table(i)zwrotów

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

Jest to indeksowane przez znaki, co jest miłe, ponieważ możemy następnie użyć ijako indeksu, aby uzyskać liczbę każdego znaku, tak:

> 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 

Reszta kodu jest więc prostą implementacją formuły entropii, nieco odwróconą.

                                           -sum(log2(l/table(i)[i]))
rturnbull
źródło
Zaoszczędź dwa bajty (również twoje zgłoszenie nie działa na TIO)
JayCe
0

C #, 159 bajtów

Gra w golfa:

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

Nie golfowany:

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

Test:

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
Pete Arden
źródło
0

Groovy, 100 bajtów

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

Testy:

This is a test. = 45.09358393449714
00001111 = 8.0
cwmfjordbankglyphsvextquiz = 122.21143275636976
aaaaaaaa = -0.0
Urna Magicznej Ośmiornicy
źródło