Indice di diversità Simpson


19

L' indice Simpson è una misura della diversità di una raccolta di elementi con duplicati. È semplicemente la probabilità di estrarre due oggetti diversi quando si sceglie senza sostituzione uniformemente a caso.

Con noggetti in gruppi di n_1, ..., n_koggetti identici, la probabilità di due oggetti diversi è

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

Ad esempio, se hai 3 mele, 2 banane e 1 carota, l'indice di diversità è

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

In alternativa, è il numero di coppie non ordinate di elementi diversi 3*2 + 3*1 + 2*1 = 11 complessivamente di 15 coppie e 11/15 = 0.7333.

Ingresso:

Una serie di caratteri A per Z. Oppure, un elenco di tali personaggi. La sua lunghezza sarà di almeno 2. Non puoi presumere che sia ordinato.

Produzione:

L'indice di diversità Simpson dei caratteri in quella stringa, ovvero la probabilità che due caratteri presi casualmente con la sostituzione siano diversi. Questo è un numero compreso tra 0 e 1 incluso.

Quando si emette un float, visualizzare almeno 4 cifre, anche se terminano output esatti come 1o 1.0o0.375 sono OK.

Non è possibile utilizzare componenti incorporati che calcolano specificamente gli indici di diversità o le misure di entropia. Il campionamento casuale effettivo va bene, purché si ottenga una precisione sufficiente sui casi di test.

Casi test

AAABBC 0.73333
ACBABA 0.73333
WWW 0.0
CODE 1.0
PROGRAMMING 0.94545

Classifica

Ecco una classifica per lingua, per gentile concessione di Martin Büttner .

Per assicurarti che la tua risposta venga visualizzata, ti preghiamo di iniziare la risposta con un titolo, utilizzando il seguente modello Markdown:

# Language Name, N bytes

dov'è Nla dimensione del tuo invio. Se si migliora il punteggio, è possibile mantenere i vecchi punteggi nel titolo, colpendoli. Per esempio:

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


Stai utilizzando l'indice Gini-Simpson, quando una misura molto migliore da utilizzare è l'indice Simpson inverso, noto anche come numero effettivo di tipi.
Joe Z.

1
Fondamentalmente 1/invece di 1-. [lo statista dilettante si toglie il cappello]
Joe Z.

Risposte:


5

Python 2, 72

L'input può essere una stringa o un elenco.

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

So già che sarebbe più breve di 2 byte in Python 3, quindi per favore non avvisarmi :)


Cosa stanno <>facendo le parentesi angolari in posizione 36? Non ho mai visto questa sintassi prima.
avvicina

@TuttiFruttiJacuzzi: è sinonimo di !=.
RemcoGerlich,

1
@TuttiFruttiJacuzzi È solo Python 2 a meno che tufrom __future__ import barry_as_FLUFL
matsjoyce,

@ Vioz- Non con l' l=len(s);
SP3000

@ Sp3000 Giusto, non ho notato quante volte è stato utilizzato.
Kade,

4

Pyth - 19 13 12 11 byte

Grazie a @isaacg per avermi parlato di n

Utilizza l'approccio della forza bruta con la .cfunzione combinazioni.

csnMK.cz2lK

Provalo qui online .

Suite di test .

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

Puoi sostituirlo .{con n- sono equivalenti qui.
isaacg,

@isaacg oh non sapevo che si stacca automaticamente, bello.
Maltysen,

4

SQL (PostgreSQL), 182 byte

In funzione di 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

Spiegazione

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

Utilizzo e test

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 byte

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

la parte interessante

Ho trovato i conteggi di ogni personaggio digitando </.la stringa su se stessa ( ~per riflesso), quindi contando le lettere di ogni casella.


1
(#&:>@</.~)può essere (#/.~)e (<:*])può essere (*<:). Se si utilizza una funzione corretta, questo dà (1-(#/.~)+/@:%&(*<:)#). Dato che qui non vengono conteggiati i controventi circostanti (lasciando 1-(#/.~)+/@:%&(*<:)#, il corpo della funzione), questo dà 20 byte.
randomra,

4

Python 3, 66 58 byte

Questo sta usando la semplice formula di conteggio fornita nella domanda, niente di troppo complicato. È una funzione lambda anonima, quindi per usarla, devi dargli un nome.

Risparmiato 8 byte (!) Grazie a Sp3000.

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

Uso:

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

o

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

3

APL, 39 36 byte

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

Questo crea una monade senza nome.

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

Puoi provarlo online !


2

Pyth, 13 byte

csnM*zz*lztlz

Praticamente una traduzione letterale della soluzione di @ feersum.


2

CJam, 25 byte

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

Provalo online

Implementazione abbastanza diretta della formula nella domanda.

Spiegazione:

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 byte

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

ma credo che possa essere ancora abbreviato.

Esempio

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

Questa è solo una versione tacita della seguente funzione:

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

Dopo un po 'di golf in più e rendendolo una funzione adeguata: (1-(%&([:+/]*<:)+/)@(+/"1@=))dà 29 byte. 27 se non contiamo le parentesi graffe che circondano la funzione (1-(%&([:+/]*<:)+/)@(+/"1@=))come è comune qui. Note: =yè esattamente (~.=/])ye anche la coniugazione compose ( x u&v y= (v x) u (v y)) è stata molto utile.
randomra,

Grazie per i suggerimenti! Sto ancora imparando a scrivere espressioni tacite da solo. Per ora, uso 13: 0 per generare definizioni tacite parte per parte e combinare.
gar

1

C, 89

Il punteggio è solo per la funzione fed esclude gli spazi bianchi non necessari, inclusi solo per chiarezza. la mainfunzione è solo per il test.

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

Confronta semplicemente ogni personaggio con ogni altro personaggio, quindi si divide per il numero totale di confronti.


1

Python 3, 56

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

Conta le coppie di elementi disuguali, quindi si divide per il numero di tali coppie.


1

Haskell, 83 byte

So di essere in ritardo, ho scoperto questo, avevo dimenticato di pubblicare. Un po 'inelegante con Haskell che mi richiede di convertire numeri interi in numeri che puoi dividere l'uno con l'altro.

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 byte

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

A proposito, questo è un miglioramento molto minore rispetto a alla risposta di @RetoKoradi , ma usa un trucco accurato:

La somma dei primi n numeri interi non negativi è uguale a n (n - 1) / 2 , che possiamo usare per calcolare il numeratore e il denominatore, entrambi divisi per 2 , della frazione nella formula della domanda.

Provalo online nell'interprete CJam .

Come funziona

 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 byte

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

Spiegazione:

  • ≢⍵: ottieni la lunghezza della prima dimensione di . Dato che si suppone che sia una stringa, ciò significa la lunghezza della stringa.
  • {⍴⍵}⌸⍵: per ogni elemento univoco in , ottieni le lunghezze di ciascuna dimensione dell'elenco delle occorrenze. Ciò fornisce la quantità di volte in cui si verifica un articolo per ciascun articolo, come una 1×≢⍵matrice.
  • ,: concatena i due lungo l'asse orizzontale. Poiché ≢⍵è uno scalare e l'altro valore è una colonna, otteniamo una 2×≢⍵matrice in cui la prima colonna ha il numero di volte in cui si verifica un articolo per ciascun articolo e la seconda colonna ha il totale degli articoli.
  • {⍵×⍵-1}: per ogni cella della matrice, calcola N(N-1).
  • ÷/: riduce le righe per divisione. Ciò divide il valore per ogni articolo per il valore per il totale.
  • +/: somma il risultato per ogni riga.
  • 1-: sottralo da 1
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.