문자열의 히스토그램 엔트로피 추정값 계산


19

주어진 문자열의 Shannon 엔트로피를 추정하는 프로그램이나 함수를 작성하십시오.

문자열에 n 개의 문자, d 개의 고유 문자, x ii 번째 고유 문자, P (x i ) 가 해당 문자가 문자열에서 발생할 확률 인 경우 해당 문자열에 대한 Shannon 엔트로피 추정값은 다음과 같습니다.

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

이 문제를 추정하기 위해 문자열에서 문자가 발생할 확률은 단순히 문자가 발생하는 횟수를 총 문자 수로 나눈 것으로 가정합니다.

답은 마침표 이후 3 자리 이상이어야합니다.


테스트 사례 :

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

나의 일반적인 도전과는 반대로, 이것은 복잡해 보이지만 실제로는 매우 간단합니다 :)
orlp


입력 문자열에 대해 인쇄 가능한 ASCII를 가정하는 것이 안전합니까?
AdmBorkBork

@TimmyD 아니요. 언어의 문자열 유형이 지원하는 모든 문자열.
orlp

불행히도 Mathematica Entropy는 문자열 당 총계가 아닌 문자 당 비트 수를 계산합니다. 오 잘 ...
2012rcampion

답변:



11

파이썬 3.3+, 64 바이트

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

mbomb007의 솔루션math.log2 에서 얻었습니다 .


그래서 @orlp는 우리에게 완전히 단순화 된 공식을주지 않았습니다.
mbomb007

@ mbomb007 단순화하려는 목적에 따라 다릅니다. 확률과 구별되는 캐릭터로 작성하는 것은 당연한 정의이지만 골프의 경우 카운트로 작업하고 모든 캐릭터를 반복하는 것이 더 짧습니다.
xnor

1
수식과 Pyth 답변 : pyth.herokuapp.com/... 8 바이트
Maltysen

2

APL, 18 14 바이트

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

이것은 이름없는 monadic function train이며 오른쪽에있는 문자열을 받아 실수를 반환합니다.

인생의 모든 좋은 것들과 마찬가지로, 이것은 xnor 's formula를 사용 합니다. 을 사용하여 문자열에서 각 문자의 발생에 해당하는 부울 행렬을 가져 와서 ∘.=⍨첫 번째 축 ( +/)을 따라 합산 하여 각 문자의 발생 횟수를 얻고 문자열 길이를 각각으로 나눈 다음 로그베이스 2를 취합니다. ( 2⍟) 및 합계

여기 사용해보십시오

Dennis 덕분에 4 바이트를 절약했습니다!



1

자바 스크립트 (ES6), 67 바이트

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

~-s.split정규 표현식 대신 문자열을 허용 하기 때문에 사용해야 합니다. 평소와 같이 1 바이트 씩 map뛰고 reduce있습니다.

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

1

펄 5, 58 바이트

서브 루틴 :

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

수식을 위해 모자에 팁을 주지 않습니다 .


-F를 포함하기 때문에 (딸기에서는) 작동하지 않습니다 $/.
msh210

1

MATL , 14 바이트

!Gu=stGn/Zl*s|

온라인으로 사용해보십시오!

!      % 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 바이트

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

Dennis의 방법으로 아이디어를 사용하여 단축했습니다.

용법

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

설명

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
나는 이것이 함수라고 생각하지 않습니다. 코드를 변수에 할당하면 완전히 다른 일을합니다.
Dennis

@Dennis 내가 수집 한 것으로부터 J는 그것을 컴포지션 체인으로 해석하는 것으로 보입니다 3 : '... y'. 동일한 구문을 사용하면 함수로 정의하는 유효한 방법이됩니다. J는 오른쪽에서 왼쪽으로 평가되므로 코드를 기차로 리팩토링했습니다. 나는 모자를 좋아하지 않지만 [:기차를 만드는 다른 방법을 찾을 수 없습니다.
마일


0

줄프, 26 바이트

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

여기 사용해보십시오! (테스트 스위트 기능이 중단되었습니다.)

설명

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

파이썬 3.3+, 95 91 89 85 바이트

간단한 해결책. 를 사용하려면 버전 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))

온라인으로 사용해보십시오


여기에 불필요한 것이 있다고 생각하십니까? n*sum(s.count(c)/n
orlp

@orlp 감사합니다. 원래 확률을 찾기위한 별도의 기능이 있었지만 두 번 안에 붙여 넣고 문자를 저장하기 위해 삭제했습니다.
mbomb007

n변수를 한 번만 사용하므로 변수 에 저장할 필요가 없습니다 .
Maltysen

0

자바 7, 207 바이트

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

자세한 온라인 시도

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

팩터, 98 바이트

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

이것은 이 Python 답변 의 직접 번역입니다 . 저녁 식사에 대한 설명을 추가하겠습니다.


0

라켓, 130 바이트

:씨

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

내 요인 답변의 번역이므로 Kenny Lau의 Python 답변을 간접적으로 번역했습니다.


0

k (32 바이트)

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

또는에서 q번역이 짧지는 않지만 명확하지 않습니다.

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

0

Mathematica, 45 바이트

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

용법

이것은 정확한 결과를 반환하므로 대략적으로로 결과를 구합니다 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 바이트

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

설명

stdin에서 입력을 받아서 문자 목록으로 나눕니다. (이 성가신 구문은 문자열 골프 도전이 R에서 그렇게 어려운 이유입니다 ...)

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

이 과제는 length명령 안에 숨겨져 있으므로 하나의 가격에 두 가지 과제가 있습니다. 우리는이 i문자의 목록을하고 l, 길이를.

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

이제 엔트로피를 계산합니다. R에는 table모든 고유 값의 개수를 반환 하는 멋진 기능 이 있습니다. 입력의 This is a test경우 table(i)반환

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

이것은 문자별로 색인화되며, 색인으로 사용 i하여 각 문자의 개수를 얻을 수 있습니다.

> 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 

코드의 나머지 부분은 엔트로피 공식의 간단한 구현이며 약간 뒤집어졌습니다.

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

2 바이트 저장 (TIO에서는 제출이 작동하지 않음)
JayCe


0

C #, 159 바이트

골프 :

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

언 골프 드 :

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

테스트:

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

그루비, 100 바이트

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

테스트 :

This is a test. = 45.09358393449714
00001111 = 8.0
cwmfjordbankglyphsvextquiz = 122.21143275636976
aaaaaaaa = -0.0
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.