Колмогоров без Складності (-Смірнов)


12

У статистиці іноді корисно знати, чи походять два зразки даних з одного базового розподілу. Один із способів зробити це - скористатися двопробним тестом Колмогорова-Смірнова .

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


Дано масив Aі реальне число x, визначте функцію розподілу Fза

F(A,x) = (#number of elements in A less than or equal to x)/(#number of elements in A)

Дано два масиви A1і A2, визнач

D(x) = |F(A1, x) - F(A2, x)|

Дві зразки статистики Колмогорова-Смірнова є максимальним значенням Dнад усім реальним x.

Приклад

A1 = [1, 2, 1, 4, 3, 6]
A2 = [3, 4, 5, 4]

Потім:

D(1) = |2/6 - 0| = 1/3
D(2) = |3/6 - 0| = 1/2
D(3) = |4/6 - 1/4| = 5/12
D(4) = |5/6 - 3/4| = 1/12
D(5) = |5/6 - 4/4| = 1/6
D(6) = |6/6 - 4/4| = 0

Статистика KS для двох масивів - 1/2максимальне значення D.

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

[0] [0] -> 0.0
[0] [1] -> 1.0
[1, 2, 3, 4, 5] [2, 3, 4, 5, 6] -> 0.2
[3, 3, 3, 3, 3] [5, 4, 3, 2, 1] -> 0.4
[1, 2, 1, 4, 3, 6] [3, 4, 5, 4] -> 0.5
[8, 9, 9, 5, 5, 0, 3] [4, 9, 0, 5, 5, 0, 4, 6, 9, 10, 4, 0, 9] -> 0.175824
[2, 10, 10, 10, 1, 6, 7, 2, 10, 4, 7] [7, 7, 9, 9, 6, 6, 5, 2, 7, 2, 8] -> 0.363636

Правила

  • Ви можете написати функцію або повну програму. Введення може бути через аргумент STDIN або аргумент функції, а вихід може бути через STDOUT або повернути значення.
  • Ви можете припустити будь-який однозначний список або формат рядка для введення, якщо він відповідає обом масивам
  • Якщо ви не маєте шансів, що ваша мова має для цього вбудований, ви можете не використовувати її.
  • Відповіді повинні бути правильними принаймні до 3 значущих цифр
  • Це , тому програма виграє в найменших байтах

Чи всі входи будуть цілими масивами, або вони можуть містити плаваючі точки?
kennytm

@KennyTM Просто неотримані цілі числа. Я думав, що все буде просто.
Sp3000

Чи існує максимальне значення, яке ми можемо припустити для масивів? (Наприклад, усі записи Aнижче length(A)?)
недолік

@flawr Ні, ви не можете припустити максимальне значення
Sp3000

Мені подобається назва. Я стильно орієнтуюся на складність колгорогоров bagde, але не цього разу.
edc65

Відповіді:


10

APL ( 29 24)

(Дякую Згарбу за додаткове натхнення.)

{⌈/|-⌿⍺⍵∘.(+/≤÷(⍴⊣))∊⍺⍵}

Це функція, яка приймає масиви як аргументи зліва та справа.

      8 9 9 5 5 0 3 {⌈/|-⌿⍺⍵∘.(+/≤÷(⍴⊣))∊⍺⍵} 4 9 0 5 5 0 4 6 9 10 4 0 9 
0.1758241758

Пояснення:

{⌈/                                maximum of
   |                               the absolute value of
    -⌿                             the difference between
      ⍺⍵∘.(         )∊⍺⍵          for both arrays, and each element in both arrays
            +/≤                    the amount of items in that array ≤ the element
               ÷                   divided by
                (⍴⊣)              the length of that array
                          }

Я не знав, що ти можеш зробити ⍺⍵! Це зручно.
Zgarb

1
Крім того, я вважаю ⍳⌈/зайвим, оскільки максимум отримується саме за одним із значень масиву.
Згарб

@ Zgarb: ти, звичайно, маєш рацію, я просто повинен перевірити кожне можливе значення масиву. Це означає, що я можу позбутися і цього 0,, оскільки він перевірить це, якщо масив містить його. Дякую! (І це навчить мене, як зазвичай, якщо вам доведеться додати в спеціальному випадку, це означає, що алгоритм недостатньо простий.)
marinus

2
Це справжня чаклунство, саме тут.
Стівен Лу

@ Sp3000: чи правильно ви написали одноелементні масиви? Ви не можете просто писати 1, оскільки це було б скаларом. (,1)Натомість слід писати . Якщо ви це зробите, це працює.
Марін

4

J - 39

Я впевнений, що можна скоротити набагато більше

f=:+/@|:@(>:/)%(]#)
>./@:|@((,f])-(,f[))

Використання

2 10 10 10 1 6 7 2 10 4 7 >./@:|@((,f])-(,f[)) 7 7 9 9 6 6 5 2 7 2 8
0.363636

Це створює функцію чи використовує stdin / stdout? Що саме робить друга частина? (Шукає функцію виклику трохи?)
недолік

@flawr Функція, схожа на APL
swish

Я думаю, ви могли б уникнути явного визначення, fякщо ви використовуєте щось подібне, >./@:|@({.-{:)f"1@,але я не зовсім впевнений.
FUZxxl

4

Пітон 3, 132 108 95 88

f=lambda a,x:sum(n>x for n in a)/len(a)
g=lambda a,b:max(abs(f(a,x)-f(b,x))for x in a+b)

Вхід є 2 списками до функції g

Завдяки: Sp3000, xnor, підземниймонорельс

Рядок 2, перший дзвінок на fтакий текст, як "факс". Я виявив це м'яко забавно


2
Для підрахунку кількості елементів списку, які задовольняють властивість, це зробити коротше sum(n>x for n in a). Крім того, схоже, ви не використовуєте s=filter. А для того max, що вам не потрібні дужки списків; Python дає можливість подвоїти функцію паронів у порівнянні з паронами розуміння.
xnor

Дякую! Я використовував filterу попередній версії, забув її видалити. На жаль, я не можу зняти першу пару квадратних дужок, оскільки тоді це буде генератор, якого немає len.
Кролтан

вам не потрібно len, читайте коментар ще раз: P
undergroundmonorail

3

JavaScript (ES6) 99 119 128

Більш-менш відверта реалізація JavaScript , ймовірно, більш грізна . У функції F я використовую> замість <=, як abs (F (a) -F (b)) === abs ((1-F (a)) - (1-F (b)))

У цьому останньому редагуванні більше немає визначення функції як параметр за замовчуванням.

Як я вже казав, це просто. Функція F - це функція F, функція D - це неназвана функція, що використовується у рядку 2. Оцінюється за допомогою .map для кожного значення, присутнього у двох масивах, оскільки максимальне значення для allдійсних даних повинно бути одним із них. Нарешті, оператор розповсюдження (...) використовується для передачі масиву значень D як списку параметрів до функції max.

K=(a,b)=>Math.max(...a.concat(b).map(x=>
  Math.abs((F=a=>a.filter(v=>v>x).length/a.length)(a)-F(b))
))

Тест в консолі FireFox / FireBug

;[[[0],[0]], [[0],[1]],
[[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]],
[[3, 3, 3, 3, 3],[5, 4, 3, 2, 1]],
[[1, 2, 1, 4, 3, 6],[3, 4, 5, 4]],
[[8, 9, 9, 5, 5, 0, 3],[4, 9, 0, 5, 5, 0, 4, 6, 9, 10, 4, 0, 9]],
[[2, 10, 10, 10, 1, 6, 7, 2, 10, 4, 7],[7, 7, 9, 9, 6, 6, 5, 2, 7, 2, 8]]]
.forEach(x=>console.log(x[0],x[1],K(x[0],x[1]).toFixed(6)))

Вихідні дані

[0] [0] 0.000000
[0] [1] 1.000000
[1, 2, 3, 4, 5] [2, 3, 4, 5, 6] 0.200000
[3, 3, 3, 3, 3] [5, 4, 3, 2, 1] 0.400000
[1, 2, 1, 4, 3, 6] [3, 4, 5, 4] 0.500000
[8, 9, 9, 5, 5, 0, 3] [4, 9, 0, 5, 5, 0, 4, 6, 9, 10, 4, 0, 9] 0.175824
[2, 10, 10, 10, 1, 6, 7, 2, 10, 4, 7] [7, 7, 9, 9, 6, 6, 5, 2, 7, 2, 8] 0.363636

Я впевнений у вашій функції K: чи правильно ви визначаєте інші функції F,Dу списку аргументів? Це поводиться як деякі необов'язкові аргументи чи так?
недолік

@flawr так, це необов'язкові аргументи зі значенням за замовчуванням. Тож уникайте забруднення глобального мінливого простору (це не проблема кодового гольфу, але все одно ...)
edc65

1
Плюс, оскільки функція вже вимагала 2 змінних (таким чином, дужки), було б 2 зайвих байти для переміщення цих змінних зі списку параметрів var всередину тіла функції.
Оптимізатор


2

Матлаб (121) (119)

Це програма, яка бере два списки через stdin і друкує результат для stdout. Це strightfwd затвердження, і я намагався якомога більше пограти в гольф. K(a)повертає функцію, яка обчислює x -> F(a,x). Потім анонімна функція, @(x)abs(g(x)-h(x))яка відповідає функції D, застосовується до кожного можливого цілого числа 0:max([a,b])та відображається максимум результатів. ( arrayfunробить те саме, що і mapв інших мовах: вона застосовує функцію до кожного елемента масиву)

a=input('');b=input('');
K=@(a)@(x)sum(a<=x)/numel(a);
g=K(a);h=K(b);
disp(max(arrayfun(@(x)abs(g(x)-h(x)),0:max([a,b]))))

2

Ерланг, 96 байт

Рішення JavaScript edc65 перенесено на Erlang.

f(A,B)->F=fun(A,X)->length([V||V<-A,V>X])/length(A)end,lists:max([abs(F(A,X)-F(B,X))||X<-A++B]).

Тест:

lists:foreach(fun ([H,T] = L) -> io:format("~p ~p~n", [L, w:f(H, T)]) end, [[[0],[0]], [[0],[1]],
        [[1, 2, 3, 4, 5],[2, 3, 4, 5, 6]],
        [[3, 3, 3, 3, 3],[5, 4, 3, 2, 1]],
        [[1, 2, 1, 4, 3, 6],[3, 4, 5, 4]],
        [[8, 9, 9, 5, 5, 0, 3],[4, 9, 0, 5, 5, 0, 4, 6, 9, 10, 4, 0, 9]],
        [[2, 10, 10, 10, 1, 6, 7, 2, 10, 4, 7],[7, 7, 9, 9, 6, 6, 5, 2, 7, 2, 8]]]).

Вихід:

[[0],[0]] 0.0
[[0],[1]] 1.0
[[1,2,3,4,5],[2,3,4,5,6]] 0.20000000000000007
[[3,3,3,3,3],[5,4,3,2,1]] 0.4
[[1,2,1,4,3,6],[3,4,5,4]] 0.5
[[8,9,9,5,5,0,3],[4,9,0,5,5,0,4,6,9,10,4,0,9]] 0.17582417582417587
[[2,10,10,10,1,6,7,2,10,4,7],[7,7,9,9,6,6,5,2,7,2,8]] 0.36363636363636365

2

СТАТА 215

Це на 90% отримує вхід у формат, який можна використовувати, оскільки STATA вже має команду ksmirnov.

di _r(a)
di _r(b)
file open q using "b.c",w
forv x=1/wordcount($a){
file w q "1,"(word($a,`x'))_n
}
forv x=1/wordcount($b){
file w q "2,"(word($b,`x'))_n
}
file close q
insheet using "b.c"
ksmirnov v2,by(v1)
di r(D)

О, уау, я не думав, що мови для цього мають вбудований ... Я просто провів деякі дослідження, і я вирішив, що найкраще відтепер вводити вбудовані файли, але ви можете зберегти це, оскільки це було розміщено перед правилом зміна :)
Sp3000

2

R, 65 байт

f=function(a,b){d=c(a,b);e=ecdf(a);g=ecdf(b);max(abs(e(d)-g(d)))}

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

Якщо вбудовані дозволені, це зменшиться до всього 12 байт:

ks.test(a,b)

1

Математика, 76 73 63

Mathematica має вбудовану функцію KolmogorovSmirnovTest, але я не буду її використовувати тут.

k=N@MaxValue[Abs[#-#2]&@@(Tr@UnitStep[x-#]/Length@#&/@{##}),x]&

Використання:

k[{1, 2, 1, 4, 3, 6}, {3, 4, 5, 4}]

0,5


0

Швидка реалізація в Python 3.4.2 (79 байт):

F=lambda A,x:len([n for n in A if n<=x])/len(A)
D=lambda x:abs(F(A1,x)-F(A2,x))

Приклад:

>>> A1 = [-5, 10, 8, -2, 9, 2, -3, -4, -4, 9]
>>> A2 = [-5, -3, -10, 8, -4, 1, -7, 6, 9, 5, -7]
>>> D(0)
0.045454545454545414

1
Вимога полягає у знаходженні максимального значення D (x) для всіх цілих значень x. Будь ласка, дотримуйтесь специфікації проблеми.
Оптимізатор

1
Ласкаво просимо! Як каже оптимізатор, завдання полягає в тому, щоб знайти максимальне значення D, а не просто реалізувати Dяк функцію. Також пробачте, якщо мені не було зрозуміло, але ви цього не можете припуститиA1 і A2вже визначені змінні (ви можете помістити їх у лямбда, хоча - наприклад lambda x,A1,A2:, це нормально)
Sp3000

Також я додав підкреслення синтаксису - я думаю, що це виглядає красивіше :)
Sp3000

Вибачте з цього приводу, я тут новий.
Каптен

Немає проблем :) Якщо щось незрозуміле, можете запитати у коментарях. Але ще раз, ласкаво просимо!
Sp3000

0

Java - 633 622 байти

Гаразд, спершу, намагаючись вийти в java так, ось чому я спробував це в Java, я знаю, що я ніколи не зроблю добре, але так, його задоволення. по-друге, я, чесно кажучи, подумав, що можу зробити це набагато менше, тоді я дістався до етапу, де скрізь були дублі, а декларація методу означала, що використання методів врятувало всього 4-5 символів. коротше кажучи, я поганий гольфіст.

редагувати: формат використання> java K "2,10,10,10,1,6,7,2,10,4,7" "7,7,9,9,6,6,5,2,7,2 , 8 "

import java.lang.*;
class K{public static void main(String[]a){double[]s1=m(a[0]);double[]s2=m(a[1]);
int h=0;if(H(s1)<H(s2))h=(int)H(s2);else h=(int)H(s1);double[]D=new double[h];
for(int i=0;i<h;i++){D[i]=Math.abs(F(s1,i)-F(s2,i));}System.out.println(H(D));}
static double[]m(String S){String[]b=S.split(",");double[]i=new double[b.length];
for(int j=0;j<b.length;j++){i[j]=new Integer(b[j]);}return i;}
static double H(double[]i){double t=0;for(int j=0;j<i.length;j++)
{if(i[j]>t)t=i[j];}return t;}
static double F(double[]A,int x){double t=0;double l=A.length;
for(int i=0;i<l;i++){if(A[i]<=x)t++;}return t/l;}}

Ви були праві. оновлення.
Брайан Девані

0

Haskell 96 83

l=fromIntegral.length
a%x=l(filter(<=x)a)/l a
a!b=maximum$map(\x->abs$a%x-b%x)$a++b

(!) - це функція колмогорова-смирнова, яка займає два списки


1
кілька швидких гольфів: mapскоріше використовувати fmap; використовувати, maximumа не foldr1 max; визначте, l=fromIntegral.lengthі ви можете позбутися i, а потім можете скоротити %до l(filter(<=x)a)/l a. Зменшує його до 84!
MtnViewMark

0

R, 107 байт

Різний підхід

f=function(a,b){e=0
d=sort(unique(c(a,b)))
for(i in d-min(diff(d))*0.8)e=max(abs(mean(a<i)-mean(b<i)),e)
e}

Безумовно

f=function(a,b){
    e=0
    d=sort(unique(c(a,b)))
    d=d-min(diff(d))*0.8
    for(i in d) {
        f=mean(a<i)-mean(b<i)
        e=max(e,abs(f))
    }
    e
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.