Simpson Diversity Index

19

Der Simpson-Index ist ein Maß für die Vielfalt einer Sammlung von Elementen mit Duplikaten. Es ist einfach die Wahrscheinlichkeit, zwei verschiedene Gegenstände zu zeichnen, wenn nach dem Zufallsprinzip ohne Austausch gleichförmig kommissioniert wird.

Bei nArtikeln in Gruppen von n_1, ..., n_kidentischen Artikeln ist die Wahrscheinlichkeit für zwei unterschiedliche Artikel

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

Wenn Sie beispielsweise 3 Äpfel, 2 Bananen und 1 Karotte haben, beträgt der Diversitätsindex

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

Alternativ ist die Anzahl der ungeordneten Paare von verschiedenen Gegenständen 3*2 + 3*1 + 2*1 = 11von insgesamt 15 11/15 = 0.7333.

Eingang:

Eine Zeichenfolge Azu Z. Oder eine Liste solcher Zeichen. Ihre Länge beträgt mindestens 2. Sie können nicht davon ausgehen, dass sie sortiert ist.

Ausgabe:

Der Simpson-Diversity-Index der Zeichen in dieser Zeichenfolge, dh die Wahrscheinlichkeit, dass zwei mit Ersetzung zufällig ausgewählte Zeichen unterschiedlich sind. Dies ist eine Zahl zwischen 0 und 1 einschließlich.

Zeigen Sie bei der Ausgabe eines Floats mindestens 4 Stellen an, obwohl die exakten Ausgaben wie 1oder 1.0oder 0.375OK sind.

Sie dürfen keine integrierten Funktionen verwenden, die speziell Diversity-Indizes oder Entropiemaße berechnen. Tatsächliche Zufallsstichproben sind in Ordnung, solange Sie eine ausreichende Genauigkeit für die Testfälle erhalten.

Testfälle

AAABBC 0.73333
ACBABA 0.73333
WWW 0.0
CODE 1.0
PROGRAMMING 0.94545

Bestenliste

Hier ist eine sprachspezifische Rangliste mit freundlicher Genehmigung von Martin Büttner .

Um sicherzustellen, dass Ihre Antwort angezeigt wird, beginnen Sie Ihre Antwort mit einer Überschrift. Verwenden Sie dazu die folgende Markdown-Vorlage:

# Language Name, N bytes

Wo Nist die Größe Ihres Beitrags? Wenn Sie Ihren Score zu verbessern, Sie können alte Rechnungen in der Überschrift halten, indem man sich durch das Anschlagen. Zum Beispiel:

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

xnor
quelle
Sie verwenden den Gini-Simpson-Index, wobei der inverse Simpson-Index (auch als effektive Anzahl von Typen bezeichnet) eine viel bessere Methode darstellt.
Joe Z.
1
Grundsätzlich 1/statt 1-. [Amateur Statistiker schimpfen Hut ab]
Joe Z.

Antworten:

5

Python 2, 72

Die Eingabe kann eine Zeichenfolge oder eine Liste sein.

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

Ich weiß bereits, dass es in Python 3 2 Bytes kürzer wäre, also raten Sie mir bitte nicht :)

Feersum
quelle
Was machen die spitzen Klammern <>an Position 36? Ich habe diese Syntax noch nie gesehen.
ApproachingDarknessFish
@TuttiFruttiJacuzzi: Es ist ein Synonym für !=.
RemcoGerlich
1
@TuttiFruttiJacuzzi Es ist nur Python 2, außer Siefrom __future__ import barry_as_FLUFL
matsjoyce
@ Vioz- Nicht mit der l=len(s);da
drin
@ Sp3000 Richtig, habe nicht bemerkt, wie oft es benutzt wurde.
Kade
4

Pyth - 19 13 12 11 Bytes

Vielen Dank an @isaacg, der mir von n erzählt hat

Verwendet Brute-Force-Ansatz mit .cKombinationsfunktion.

csnMK.cz2lK

Probieren Sie es hier online .

Testsuite .

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
Maltysen
quelle
Sie können ersetzen .{mit n- sie sind hier gleichwertig.
Isaac
@isaacg oh wusste nicht, dass es automatisch splats, cool.
Maltysen
4

SQL (PostgreSQL), 182 Bytes

Als eine Funktion in 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

Erläuterung

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

Verwendung und Testlauf

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
MickyT
quelle
4

J, 26 Bytes

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

das coole teil

Ich fand die Anzahl jedes Zeichens, indem ich </.die Zeichenkette gegen sich selbst ~drückte ( reflexiv) und dann die Buchstaben jedes Kästchens zählte.

Protist
quelle
1
(#&:>@</.~)kann sein (#/.~)und (<:*])kann sein (*<:). Wenn Sie eine ordnungsgemäße Funktion verwenden, gibt dies (1-(#/.~)+/@:%&(*<:)#). Da die umgebenden Klammern hier in der Regel nicht mitgezählt werden (wobei 1-(#/.~)+/@:%&(*<:)#der Hauptteil der Funktion übrig bleibt), ergeben sich 20 Bytes.
Randomra
4

Python 3, 66 58 Bytes

Hierbei wird die in der Frage angegebene einfache Zählformel verwendet, die nicht zu kompliziert ist. Es ist eine anonyme Lambda-Funktion. Um sie zu verwenden, müssen Sie ihr einen Namen geben.

8 Bytes (!) Gespart dank Sp3000.

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

Verwendung:

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

oder

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

APL, 39 36 Bytes

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

Dadurch entsteht eine unbenannte Monade.

{
  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))
}

Sie können es online ausprobieren !

Alex A.
quelle
2

Pyth, 13 Bytes

csnM*zz*lztlz

Ziemlich wörtliche Übersetzung von @ feersums Lösung.

orlp
quelle
2

CJam, 25 Bytes

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

Probieren Sie es online aus

Ziemlich direkte Umsetzung der Formel in der Frage.

Erläuterung:

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.
Reto Koradi
quelle
1

J, 37 Bytes

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

aber ich glaube es kann noch gekürzt werden.

Beispiel

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

Dies ist nur eine stillschweigende Version der folgenden Funktion:

   fun =: 3 : 0
a1=.+/"1 (~.y)=/y
N=.(+/a1)*(<:+/a1)
n=.a1*a1-1
1-(+/n)%N
)
gar
quelle
Nach einigem zusätzlichen Golfen und dem Herstellen einer korrekten Funktion: (1-(%&([:+/]*<:)+/)@(+/"1@=))ergibt 29 Bytes. 27 Wenn wir die Klammern, die die Funktion umgeben, nicht mitzählen, (1-(%&([:+/]*<:)+/)@(+/"1@=))wie es hier üblich ist. Anmerkungen: =yist genau (~.=/])yund die Compose-Konjunktion ( x u&v y= (v x) u (v y)) war auch sehr hilfreich.
zufällig
Danke für die Vorschläge! Ich lerne immer noch, stillschweigende Ausdrücke selbst zu schreiben. Im Moment benutze ich 13: 0, um implizite Definitionen Teil für Teil zu generieren und zu kombinieren.
Gar
1

C 89

Die Bewertung gilt nur für die Funktion fund schließt unnötige Leerzeichen aus, die nur der Übersichtlichkeit halber enthalten sind. Die mainFunktion dient nur zu Testzwecken.

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

Es vergleicht einfach jedes Zeichen mit jedem anderen Zeichen und dividiert dann durch die Gesamtzahl der Vergleiche.

Level River St
quelle
1

Python 3, 56

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

Zählt die Paare ungleicher Elemente und dividiert dann durch die Anzahl solcher Paare.

xnor
quelle
1

Haskell, 83 Bytes

Ich weiß, ich bin zu spät, fand dies, hatte vergessen zu posten. Etwas unelegant, weil Haskell verlangt, dass ich ganze Zahlen in Zahlen umwandle, die Sie durcheinander teilen können.

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

CJam, 23 Bytes

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

Byteweise ist dies eine sehr geringfügige Verbesserung gegenüber Byteweise der Antwort von @ RetoKoradi , aber es wird ein ordentlicher Trick verwendet:

Die Summe der ersten n nicht-negativen ganzen Zahlen entspricht n (n - 1) / 2 , anhand derer wir den Zähler und den Nenner berechnen können, beide geteilt durch 2 , des Bruchs in der Formel der Frage berechnen können.

Probieren Sie es online im CJam-Interpreter aus .

Wie es funktioniert

 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.
Dennis
quelle
0

APL, 26 Bytes

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

Erläuterung:

  • ≢⍵: Ermittelt die Länge der ersten Dimension von . Da dies eine Zeichenkette sein soll, bedeutet dies die Länge der Zeichenkette.
  • {⍴⍵}⌸⍵: für jedes einzelne Element in erhalten Sie die Länge jeder Dimension der Liste der Vorkommen. Dies gibt die Häufigkeit an, mit der ein Element für jedes Element als 1×≢⍵Matrix auftritt .
  • ,: Verketten Sie die beiden entlang der horizontalen Achse. Schon seit≢⍵ es sich um einen Skalar handelt und der andere Wert eine Spalte ist, erhalten wir eine 2×≢⍵Matrix, in der die erste Spalte die Häufigkeit angibt, mit der ein Element für jedes Element auftritt, und die zweite Spalte die Gesamtanzahl der Elemente.
  • {⍵×⍵-1}: Berechnen Sie für jede Zelle in der Matrix N(N-1).
  • ÷/: Zeilen durch Unterteilung reduzieren. Dies dividiert den Wert für jeden Artikel durch den Wert für die Gesamtsumme.
  • +/: summiere das Ergebnis für jede Zeile.
  • 1-: subtrahiere es von 1
Marinus
quelle