Indeks keanekaragaman Simpson


19

The Indeks Simpson adalah ukuran dari keragaman koleksi item dengan duplikat. Ini hanya probabilitas menggambar dua item yang berbeda saat memilih tanpa penggantian secara acak.

Dengan nitem dalam kelompok n_1, ..., n_kitem identik, probabilitas dua item berbeda adalah

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

Misalnya, jika Anda memiliki 3 apel, 2 pisang, dan 1 wortel, indeks keanekaragamannya adalah

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

Atau, jumlah pasangan yang tidak berurutan dari berbagai item berbeda 3*2 + 3*1 + 2*1 = 11dari 15 pasangan secara keseluruhan, dan 11/15 = 0.7333.

Memasukkan:

String karakter Auntuk Z. Atau, daftar karakter semacam itu. Panjangnya minimal 2. Anda mungkin tidak menganggapnya disortir.

Keluaran:

Indeks keanekaragaman Simpson karakter dalam string itu, yaitu probabilitas bahwa dua karakter diambil secara acak dengan penggantian berbeda. Ini adalah angka antara 0 dan 1 inklusif.

Saat mengeluarkan float, tampilkan setidaknya 4 digit, meskipun mengakhiri output persis seperti 1atau 1.0atau 0.375OK.

Anda tidak boleh menggunakan bawaan yang secara khusus menghitung indeks keanekaragaman atau ukuran entropi. Pengambilan sampel acak yang sebenarnya baik-baik saja, selama Anda mendapatkan akurasi yang cukup pada kasus uji.

Uji kasus

AAABBC 0.73333
ACBABA 0.73333
WWW 0.0
CODE 1.0
PROGRAMMING 0.94545

Papan peringkat

Berikut adalah papan peringkat berdasarkan bahasa, milik Martin Büttner .

Untuk memastikan bahwa jawaban Anda muncul, silakan mulai jawaban Anda dengan tajuk utama, menggunakan templat Penurunan harga berikut:

# Language Name, N bytes

di mana Nukuran kiriman Anda. Jika Anda meningkatkan skor Anda, Anda dapat menyimpan skor lama di headline, dengan mencoretnya. Contohnya:

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


Anda menggunakan indeks Gini-Simpson, ketika ukuran yang jauh lebih baik untuk digunakan adalah indeks Simpson terbalik alias jumlah tipe yang efektif.
Joe Z.

1
Pada dasarnya, 1/bukannya 1-. [amati ahli statistik amatir lepas landas]
Joe Z.

Jawaban:


5

Python 2, 72

Input mungkin berupa string atau daftar.

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

Saya sudah tahu bahwa itu akan menjadi 2 byte lebih pendek di Python 3 jadi tolong jangan beri tahu saya :)


Apa yang <>dilakukan kurung sudut pada posisi 36? Saya belum pernah melihat sintaks itu sebelumnya.
ApproachingDarknessFish

@TuttiFruttiJacket: ini adalah sinonim untuk !=.
RemcoGerlich

1
@TuttiFruttiJacket Ini hanya python 2 kecuali Andafrom __future__ import barry_as_FLUFL
matsjoyce

@ Vioz- Tidak dengan l=len(s);di sana
Sp3000

@ Sp3000 Benar, tidak memperhatikan berapa kali itu digunakan.
Kade

4

Pyth - 19 13 12 11 byte

Terima kasih kepada @isaacg karena memberi tahu saya tentang n

Menggunakan pendekatan brute force dengan .cfungsi kombinasi.

csnMK.cz2lK

Coba di sini online .

Suite uji .

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

Anda dapat mengganti .{dengan n- mereka setara di sini.
isaacg

@isaacg oh tidak tahu secara otomatis percikan, keren.
Maltysen

4

SQL (PostgreSQL), 182 Bytes

Sebagai fungsi 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

Penjelasan

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

Penggunaan dan Uji Coba

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-+/((#&:>@</.~)%&(<:*])#)

bagian yang keren

Saya menemukan jumlah setiap karakter dengan memasukkan </.string ke dirinya sendiri ( ~untuk refleksif) kemudian menghitung huruf setiap kotak.


1
(#&:>@</.~)bisa (#/.~)dan (<:*])bisa (*<:). Jika Anda menggunakan fungsi yang tepat ini memberi (1-(#/.~)+/@:%&(*<:)#). Karena kurung kurawal di sekitarnya umumnya tidak dihitung di sini (meninggalkan 1-(#/.~)+/@:%&(*<:)#, tubuh fungsi) ini menghasilkan 20 byte.
randomra

4

Python 3, 66 58 Bytes

Ini menggunakan rumus penghitungan sederhana yang disediakan dalam pertanyaan, tidak ada yang terlalu rumit. Ini adalah fungsi lambda anonim, jadi untuk menggunakannya, Anda harus memberi nama.

Disimpan 8 byte (!) Berkat Sp3000.

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

Pemakaian:

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

atau

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

Ini menciptakan monad yang tidak disebutkan namanya.

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

Anda dapat mencobanya secara online !


2

Pyth, 13 byte

csnM*zz*lztlz

Cukup banyak terjemahan harfiah dari solusi @ feersum.


2

CJam, 25 byte

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

Cobalah online

Implementasi formula yang cukup langsung dalam pertanyaan.

Penjelasan:

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

tapi saya yakin itu masih bisa dipersingkat.

Contoh

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

Ini hanya versi diam-diam dari fungsi berikut:

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

Setelah beberapa golf ekstra dan menjadikannya fungsi yang tepat: (1-(%&([:+/]*<:)+/)@(+/"1@=))memberikan 29 byte. 27 jika kita tidak menghitung kawat gigi yang mengelilingi fungsi (1-(%&([:+/]*<:)+/)@(+/"1@=))seperti yang biasa terjadi di sini. Catatan: =ytepat (~.=/])ydan kata kerja penulisan ( x u&v y= (v x) u (v y)) juga sangat membantu.
randomra

Terima kasih atas sarannya! Saya sendiri masih belajar menulis ekspresi diam-diam. Untuk saat ini, saya menggunakan 13: 0 untuk menghasilkan definisi diam-diam bagian demi bagian dan menggabungkan.
gar

1

C, 89

Skor hanya untuk fungsi fdan tidak termasuk spasi yang tidak perlu, yang hanya termasuk untuk kejelasan. yang mainfungsi hanya untuk pengujian.

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

Ini hanya membandingkan setiap karakter dengan setiap karakter lain, kemudian membaginya dengan jumlah total perbandingan.


1

Python 3, 56

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

Menghitung pasangan elemen yang tidak sama, kemudian membaginya dengan jumlah pasangan tersebut.


1

Haskell, 83 byte

Saya tahu saya terlambat, menemukan ini, lupa memposting. Agak tidak sopan dengan Haskell yang mengharuskan saya untuk mengkonversi bilangan bulat ke angka yang dapat Anda bagi satu sama lain.

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/-

Byte-wise, ini adalah peningkatan yang sangat kecil dari jawaban @ RetoKoradi , tetapi menggunakan trik yang rapi:

Jumlah dari bilangan bulat n -negatif pertama sama dengan n (n - 1) / 2 , yang dapat kita gunakan untuk menghitung pembilang dan penyebut, keduanya dibagi dengan 2 , dari fraksi dalam rumus pertanyaan.

Cobalah online di juru bahasa CJam .

Bagaimana itu bekerja

 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}({⍴⍵}⌸⍵),≢⍵}

Penjelasan:

  • ≢⍵: dapatkan panjang dimensi pertama . Mengingat yang seharusnya berupa string, ini berarti panjang string.
  • {⍴⍵}⌸⍵: untuk setiap elemen unik , dapatkan panjang setiap dimensi dari daftar kejadian. Ini memberikan berapa kali suatu item muncul untuk setiap item, sebagai sebuah 1×≢⍵matriks.
  • ,: menyatukan keduanya di sepanjang sumbu horizontal. Karena ≢⍵skalar, dan nilai lainnya adalah kolom, kita mendapatkan 2×≢⍵matriks di mana kolom pertama memiliki jumlah kali suatu item terjadi untuk setiap item, dan kolom kedua memiliki jumlah total item.
  • {⍵×⍵-1}: untuk setiap sel dalam matriks, hitung N(N-1).
  • ÷/: kurangi baris dengan pembagian. Ini membagi nilai untuk setiap item dengan nilai untuk total.
  • +/: jumlah hasil untuk setiap baris.
  • 1-: kurangi dari 1
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.