シンプソン多様性指数


19

シンプソン指数は、重複を持つアイテムのコレクションの多様性の尺度です。単純にランダムに交換せずにピッキングするときに2つの異なるアイテムを描画する確率です。

nグループ内の項目n_1, ..., n_kと同じ項目、二つの異なるアイテムの確率であります

$$ 1- \ sum_ {i = 1} ^ k \ frac {n_i(n_i-1)} {n(n -1)} $$

たとえば、リンゴが3個、バナナが2個、ニンジンが1個ある場合、ダイバーシティインデックスは

D = 1 - (6 + 2 + 0)/30 = 0.7333

あるいは、異なるアイテムの順序付けられていないペアの数は3*2 + 3*1 + 2*1 = 11、全体で15ペアのうちです11/15 = 0.7333

入力:

文字の文字列AZ。または、そのようなキャラクターのリスト。その長さは少なくとも2になります。ソートされていると想定することはできません。

出力:

その文字列内の文字のシンプソンダイバーシティインデックス、つまり、置換でランダムに取得された2つの文字が異なる確率。これは、0から1までの数値です。

以下のような正確な出力を終了するが、フロート、表示少なくとも4桁を出力する場合1、または1.0、または0.375OKです。

ダイバーシティインデックスまたはエントロピー測定を具体的に計算するビルトインを使用することはできません。テストケースで十分な精度が得られる限り、実際のランダムサンプリングは問題ありません。

テストケース

AAABBC 0.73333
ACBABA 0.73333
WWW 0.0
CODE 1.0
PROGRAMMING 0.94545

リーダーボード

これは、MartinBüttnerの厚意による言語別のリーダーボードです。

回答が表示されるようにするには、次のマークダウンテンプレートを使用して、見出しから回答を開始してください。

# Language Name, N bytes

N提出物のサイズはどこですか。スコアを改善する場合、古いスコアを打つことで見出しに残すことができます。例えば:

# Ruby, <s>104</s> <s>101</s> 96 bytes


Gini-Simpsonインデックスを使用している場合、使用するのにはるかに優れた尺度は、逆シンプソンインデックス、つまり有効な型の数です。
ジョーZ.

1
基本的にの1/代わりに1-。[アマチュア統計学者の暴言の帽子]
ジョーZ.

回答:


5

Python 2、72

入力は文字列またはリストです。

def f(s):l=len(s);return sum(s[i%l]<>s[i/l]for i in range(l*l))/(l-1.)/l

Python 3では2バイト短くなることは既にわかっているので、アドバイスしないでください:)


<>36番の山かっこは何をしていますか?その構文を見たことがありません。
ApproachingDarknessFish

@TuttiFruttiJacuzzi:これはの同義語です!=
-RemcoGerlich

1
@TuttiFruttiJacuzziそれはあなた以外のPython 2だけですfrom __future__ import barry_as_FLUFL
-matsjoyce

@ Vioz-ないとl=len(s);そこに
SP3000

@ Sp3000そう、何回使用されたか気がつかなかった。
ケード

4

Pyth- 19 13 12 11バイト

nについて教えてくれた@isaacgに感謝

.c組み合わせ機能でブルートフォースアプローチを使用します。

csnMK.cz2lK

こちらからオンラインでお試しください

テストスイート

c                Float division
 s               Sum (works with True and False)
  nM             Map uniqueness
   K             Assign value to K and use value
    .c 2         Combinations of length 2
      z          Of input
 lK              Length of K

あなたは置き換えることができ.{n-彼らはここに同等です。
isaacg

@isaacgああ、それが自動的に飛び散るのを知らなかった、クール。
マルティセン

4

SQL(PostgreSQL)、182バイト

postgresの関数として。

CREATE FUNCTION F(TEXT)RETURNS NUMERIC AS'SELECT 1-sum(d*(d-1))/(sum(d)*(sum(d)-1))FROM(SELECT COUNT(*)d FROM(SELECT*FROM regexp_split_to_table($1,''''))I(S)GROUP BY S)A'LANGUAGE SQL

説明

CREATE FUNCTION F(TEXT) -- Create function f taking text parameter
RETURNS NUMERIC         -- declare return type
AS'                     -- return definition
    SELECT 1-sum(d*(d-1))/(sum(d)*(sum(d)-1)) -- Calculate simpson index
    FROM(
        SELECT COUNT(*)d  -- Count occurrences of each character
        FROM(             -- Split the string into characters
            SELECT*FROM regexp_split_to_table($1,'''')
            )I(S)
        GROUP BY S        -- group on the characters
        )A 
'
LANGUAGE SQL

使用法とテスト実行

SELECT S, F(S)
FROM (
    VALUES
    ('AAABBC'),
    ('ACBABA'),
    ('WWW'),
    ('CODE'),
    ('PROGRAMMING')
   )I(S)

S              F
-------------- -----------------------
AAABBC         0.73333333333333333333
ACBABA         0.73333333333333333333
WWW            0.00000000000000000000
CODE           1.00000000000000000000
PROGRAMMING    0.94545454545454545455

4

J、26バイト

1-+/((#&:>@</.~)%&(<:*])#)

クールな部分

</.文字列をそれ自体にキーイングして(~再帰的に)、各ボックスの文字をカウントすることで、各文字のカウントを見つけました。


1
(#&:>@</.~)可能(#/.~)(<:*])することができ(*<:)。適切な関数を使用すると、が得られ(1-(#/.~)+/@:%&(*<:)#)ます。周囲の中括弧は通常ここではカウントされないため(1-(#/.~)+/@:%&(*<:)#関数の本体を残して)、これは20バイトになります。
randomra

4

Pythonの3、66の 58バイト

これは、質問で提供されている単純なカウント式を使用しており、複雑すぎません。これは匿名のラムダ関数なので、使用するには名前を付ける必要があります。

Sp3000のおかげで8バイト(!)を節約できました。

lambda s:1-sum(x-1for x in map(s.count,s))/len(s)/~-len(s)

使用法:

>>> f=lambda s:1-sum(x-1for x in map(s.count,s))/len(s)/~-len(s)
>>> f("PROGRAMMING")
0.945454

または

>>> (lambda s:1-sum(x-1for x in map(s.count,s))/len(s)/~-len(s))("PROGRAMMING")
0.945454

3

APL、39 36バイト

{n←{≢⍵}⌸⍵⋄N←≢⍵⋄1-(N-⍨N×N)÷⍨+/n-⍨n×n}

これにより、名前のないモナドが作成されます。

{
  n ← {≢⍵}⌸⍵               ⍝ Number of occurrences of each letter
  N ← ≢⍵                   ⍝ Number of characters in the input
  1-(N-⍨N×N)÷⍨+/n-⍨n×n     ⍝ Return 1 - sum((n*n-n)/(N*N-N))
}

オンラインで試すことができます


2

Pyth、13バイト

csnM*zz*lztlz

@feersumのソリューションのほぼ文字通りの翻訳。


2

CJam、25バイト

l$_e`0f=_:(.*:+\,_(*d/1\-

オンラインで試す

質問の式のかなり直接的な実施。

説明:

l     Get input.
$     Sort it.
_     Copy for evaluation of denominator towards the end.
e`    Run-length encoding of string.
0f=   Map letter/length pairs from RLE to only length.
      We now have a list of letter counts.
_     Copy list.
:(    Map with decrement operator. Copy now contains letter counts minus 1.
.*    Vectorized multiply. Results in list of n*(n-1) for each letter.
:+    Sum vector. This is the numerator.
\     Bring copy of input string to top.
,     Calculate length.
_(    Copy and decrement.
*     Multiply. This is the denominator, n*(n-1) for the entire string.
d     Convert to double, otherwise we would get integer division.
/     Divide.
1\-   Calculate one minus result of division to get final result.

1

J、37バイト

(1-([:+/]*<:)%+/*[:<:+/)([:+/"1~.=/])

しかし、まだ短縮できると思います。

(1-([:+/]*<:)%+/*[:<:+/)([:+/"1~.=/]) 'AAABBC'

これは、次の関数の暗黙バージョンです。

   fun =: 3 : 0
a1=.+/"1 (~.y)=/y
N=.(+/a1)*(<:+/a1)
n=.a1*a1-1
1-(+/n)%N
)

いくつかの余分なゴルフとそれを適切な機能にした後:(1-(%&([:+/]*<:)+/)@(+/"1@=))29バイトを与えます。27 (1-(%&([:+/]*<:)+/)@(+/"1@=))ここで一般的であるため、関数を囲む中括弧をカウントしない場合。注:=yはまさにその通りで(~.=/])yあり、構成結合(x u&v y= (v x) u (v y))も非常に役立ちました。
-randomra

提案をありがとう!私はまだ暗黙の表現を自分で書くことを学んでいます。今のところ、13:0を使用して、暗黙の定義を部分ごとに生成し、結合します。
ガー

1

C、89

スコアは関数f専用であり、明確にするためにのみ含まれている不要な空白は除外されます。このmain機能はテスト専用です。

i,c,n;
float f(char*v){
  n=strlen(v);
  for(i=n*n;i--;)c+=v[i%n]!=v[i/n]; 
  return 1.0*c/(n*n-n);
}

main(int C,char**V){
  printf("%f",f(V[1]));
}

単にすべての文字を他のすべての文字と比較し、比較の総数で除算します。


1

Python 3、56

lambda s:sum(a!=b for a in s for b in s)/len(s)/~-len(s)

等しくない要素のペアをカウントし、そのようなペアの数で除算します。


1

Haskell、83バイト

遅れて、これを見つけて、投稿するのを忘れていました。Haskellとはまったく関係なく、整数を整数に変換する必要があります。

s z=(l(filter id p)-l z)/(l p-l z) where p=[c==d|c<-z,d<-z]
l=fromIntegral.length

0

CJam、23バイト

1r$e`{0=,~}%_:+\,,:+d/-

バイト単位では、これは@RetoKoradiの回答に対する非常に小さな改善ですが、きちんとしたトリックを使用します。

最初のn個の非負整数の合計はn(n-1)/ 2に等しく、これを使用して、問題の式の分数の分子と分母をともに2で割った値を計算できます。

CJamインタープリターでオンラインで試してください。

使い方

 r$                     e# Read a token from STDIN and sort it.
   e`                   e# Perform run-length encoding.
     {    }%            e# For each [length character] pair:
      0=                e#   Retrieve the length of the run (L).
        ,~              e#   Push 0 1 2 ... L-1.
                        e# Collect all results in an array.
            _:+         e# Push the sum of the entries of a copy.
               \,       e# Push the length of the array (L).
                 ,:+    e# Push 0 + 1 + 2 + ... + L-1 = L(L-1)/2.
                    d/  e# Cast to Double and divide.
1                     - e# Subtract the result from 1.

0

APL、26バイト

{1-+/÷/{⍵×⍵-1}({⍴⍵}⌸⍵),≢⍵}

説明:

  • ≢⍵:の最初の次元の長さを取得します。それが文字列であると想定される場合、これは文字列の長さを意味します。
  • {⍴⍵}⌸⍵:の一意の要素ごとに、出現リストの各次元の長さを取得します。これは、1×≢⍵マトリックスとして、アイテムごとにアイテムが発生する回数を示します。
  • ,:水平軸に沿って2つを連結します。ため≢⍵スカラーであり、他の値が列であり、我々が得る2×≢⍵最初の列は、アイテムが各アイテムに対して発生回量を有するマトリックスを、第2列は、商品の合計金額を持っています。
  • {⍵×⍵-1}:マトリックス内の各セルについて、を計算しN(N-1)ます。
  • ÷/:分割により行を減らします。これにより、各項目の値が合計の値で除算されます。
  • +/:各行の結果を合計します。
  • 1-:1から引きます
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.