Без сложностей Колмогоров (-Смирнов)


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

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

Мне нравится название. Я все еще нацеливаюсь на колмогоровскую сложность багде, но не в этот раз.
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
                          }

Я не знал, что ты мог сделать ⍺⍵! Это удобно
Згарб

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

@Zgarb: конечно, вы правы, мне просто нужно проверить каждое возможное значение массива. Это означает, что я могу избавиться и от этого 0,, так как он проверит это, если массив содержит его. Благодарность! (И это научит меня, как обычно, если вам нужно добавить в особом случае, это означает, что алгоритм не достаточно прост.)
marinus

2
Это настоящее колдовство, прямо здесь.
Стивен Лу

@ Sp3000: правильно ли вы написали одноэлементные массивы? Вы не можете просто написать 1, так как это будет скаляр. Вы должны написать (,1)вместо этого. Если вы это сделаете, это работает.
Marinus

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

@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.
Kroltan

Вам не нужно 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

@flawr да, это необязательные аргументы со значением по умолчанию. Таким образом, избегая загрязнения пространства глобальных переменных (это не проблема в коде гольф, но в любом случае ...)
edc65

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


2

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

Это программа, которая принимает два списка через стандартный вывод и выводит результат в стандартный вывод. Это верный подход, и я старался играть в него как можно больше. 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

STATA 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

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

Ява - 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}

Ungolfed

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.