文字列のヒストグラムエントロピー推定を計算します


19

特定の文字列のシャノンエントロピーを推定するプログラムまたは関数を作成します。

文字列にn個の文字、d個の 個別の文字、x ii番目の個別の文字、P(x iが文字列に出現する確率である場合、その文字列のシャノンエントロピー推定は次のようになります。

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

Python 3.3以降、64バイト

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

手に入れたmath.log2からmbomb007のソリューション


@orlpは完全に単純化された式を提供しませんでした。
mbomb007

@ mbomb007単純化する目的に依存します。確率と明確なキャラクターの観点からそれを書くことは定義としては自然ですが、ゴルフではカウントを処理してすべてのキャラクターを反復する方が短いです。
-xnor

1
あなたの式を使った答え:pyth.herokuapp.com/…8バイト
Maltysen

2

APL、18 14バイト

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

これは名前のない単項関数列で、右側の文字列を受け入れて実数を返します。

人生のすべての良いものと同様に、これはxnorの式を使用します。を使用して文字列内の各文字の出現に対応するブール値の行列を取得し、∘.=⍨これを最初の軸(+/)に沿って合計して各文字の出現回数を取得し、文字列の長さをそれぞれで除算してから、対数ベース2を取得します(2⍟)および合計。

ここで試してみてください

デニスのおかげで4バイト節約できました!



1

JavaScript(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

Perl 5、58バイト

サブルーチン:

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

式のxnorに私の帽子の先端。


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

デニスの方法のアイデアを使用して短縮。

使用法

   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私が収集したものから、Jはそれを一連の構成として解釈しているように見え3 : '... y'ます。同じ構文を使用することは、それを関数として定義する有効な方法です。Jは、右から左に評価すると述べているため、コードをトレインとしてリファクタリングしました。私は帽子[:が好きではないが、電車を作る他の方法を見つけることができない。
マイル


0

Jolf、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

Python 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ありがとう。私はもともと確率を見つけるための別の機能を持っていましたが、文字を保存するために2回内側に貼り付けて削除しました。
mbomb007

n一度使用するだけなので、変数に保存する必要はありません。
マルティセン

0

Java 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

ラケット、130バイト

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

Factorの回答の翻訳です。したがって、これは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]))

説明

標準入力から入力を取得し、文字のリストに分割します。(この不格好な構文は、Rでストリングゴルフの挑戦がとても難しい理由です...)

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

この割り当てはlengthコマンド内に隠されているため、1つの価格で2つの割り当てを取得します。我々は持っているi、文字のリストを、そしてl、その長さ。

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

ここでエントロピーを計算します。Rには、tableすべての一意の値のカウントを返す便利な関数があります。入力の場合This is a testtable(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]))



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

Groovy、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.