Індекс різноманітності Сімпсона


19

Індекс Сімпсона - це міра різноманітності колекції предметів із дублікатами. Це просто ймовірність малювання двох різних предметів при підборі без заміни рівномірно навмання.

З 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.

Вхід:

Рядок символів Aдо Z. Або список таких символів. Її довжина буде не менше 2. Ви можете не вважати, що вона буде відсортована.

Вихід:

Індекс різноманітності Сімпсона символів у цій рядку, тобто ймовірність того, що два символи, взяті випадковим чином із заміною, різні. Це число від 0 до 1 включно.

При виведенні поплавка, дисплей , щонайменше 4 цифри, хоча припинення точних результатів , як 1або 1.0або 0.375КІ.

Ви не можете використовувати вбудовані модулі, які спеціально обчислюють індекси різноманітності або заходи ентропії. Фактична випадкова вибірка чудова, якщо ви отримаєте достатню точність на тестових прикладах.

Тестові справи

AAABBC 0.73333
ACBABA 0.73333
WWW 0.0
CODE 1.0
PROGRAMMING 0.94545

Таблиця лідерів

Ось мовна таблиця мов, люб’язно надана Мартіном Бюттнером .

Щоб переконатися, що ваша відповідь відображається, будь ласка, почніть свою відповідь із заголовка, використовуючи наступний шаблон Markdown:

# Language Name, N bytes

де Nрозмір вашого подання. Якщо ви покращите свій рахунок, ви можете зберегти старі бали у заголовку, прокресливши їх. Наприклад:

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


Ви використовуєте індекс Джині-Сімпсона, коли набагато кращим показником є ​​зворотний індекс Сімпсона, так само ефективна кількість типів.
Джо З.

1
В основному 1/замість 1-. [аматорський статистик відірвав капелюх]
Джо Z.

Відповіді:


5

Пітон 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

Я вже знаю, що це було б на 2 байти коротше в Python 3, тому, будь ласка, не радить мені :)


Які кутові дужки <>роблять у положенні 36? Я ніколи раніше не бачив цього синтаксису.
Наближення

@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 байт

Дякую @isaacg за те, що він розповів мені про n

Використовує підхід грубої сили з .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 байти

Як функція в постгресах.

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

Пітон 3, 66 58 байт

Для цього використовується проста формула підрахунку, наведена у питанні, нічого надто складного. Це анонімна лямбда-функція, тому для її використання потрібно дати їй ім’я.

Збережено 8 байт (!) Завдяки Sp3000.

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

С, 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

Пітон 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×≢⍵матрицю, де перший стовпець має кількість разів, коли елемент виникає для кожного елемента, а другий - загальна кількість елементів.
  • {⍵×⍵-1}: для кожної комірки в матриці обчисліть N(N-1) .
  • ÷/: зменшити рядки поділом. Це ділить значення для кожного елемента на значення на загальне.
  • +/: підсумовуйте результат для кожного ряду.
  • 1-: відняти його від 1
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.