Kolmogorov sem complexidade (-Smirnov)


12

Nas estatísticas, às vezes é útil saber se duas amostras de dados são da mesma distribuição subjacente. Uma maneira de fazer isso é usar o teste de duas amostras de Kolmogorov-Smirnov .

Sua tarefa será escrever um programa que leia duas matrizes inteiras não-negativas não classificadas e calcule a principal estatística usada no teste.


Dada uma matriz Ae um número real x, defina a função de distribuição Fpor

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

Dadas duas matrizes A1e A2, defina

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

A estatística Kolmogorov-Smirnov de duas amostras é o valor máximo de Dtodo o real x.

Exemplo

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

Então:

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

A estatística KS para as duas matrizes é 1/2o valor máximo de D.

Casos de teste

[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

Regras

  • Você pode escrever uma função ou um programa completo. A entrada pode ser via STDIN ou argumento de função e a saída pode ser via STDOUT ou valor de retorno.
  • Você pode assumir qualquer formato inequívoco de lista ou string para a entrada, desde que seja consistente para ambas as matrizes
  • Se você não tiver um idioma embutido para isso, não poderá usá-lo.
  • As respostas precisam estar corretas para pelo menos 3 números significativos
  • Isso é , então o programa com o menor número de bytes ganha

Todas as entradas serão matrizes inteiras ou podem conter pontos flutuantes?
Kennytm

@KennyTM Apenas números inteiros não negativos. Eu pensei em manter as coisas simples.
Sp3000 02/02

Existe um valor máximo que podemos assumir para matrizes? (Por exemplo, todas as entradas de Asão abaixo length(A)?)
flawr

@flawr Não, você não pode assumir um valor máximo #
Sp3000 02/02

Eu gosto do título. Eu ainda estou mirando na complexidade kolmogorov, mas não desta vez.
Edc65

Respostas:


10

APL ( 29 24)

(Obrigado a Zgarb pela inspiração extra.)

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

Essa é uma função que aceita as matrizes como argumentos esquerdo e direito.

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

Explicação:

{⌈/                                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
                          }

Eu não sabia que você poderia fazer ⍺⍵! Isso é útil.
Zgarb 02/02

1
Além disso, acho ⍳⌈/desnecessário, pois o máximo é obtido exatamente em um dos valores da matriz.
Zgarb 02/02

@ Zgarb: você está certo, é claro, eu apenas tenho que testar cada valor possível de matriz. Isso significa que eu também posso me livrar 0,disso, pois ele testará isso se a matriz o contiver. Obrigado! (E isso vai me ensinar, como geralmente se você tem que adicionar em um caso especial, significa que o algoritmo não é suficiente simples.)
marinus

2
Isso é verdadeira feitiçaria, bem aqui.
Steven Lu

@ Sp3000: você escreveu as matrizes de um elemento corretamente? Você não pode simplesmente escrever 1, pois isso seria um escalar. Você deve escrever em seu (,1)lugar. Se você fizer isso, funciona.
marinus

4

J - 39

Tenho certeza que pode ser encurtar muito mais

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

Uso

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

Isso cria uma função ou usa stdin / stdout? O que a segunda parte faz exatamente? (Parece um pouco longo para uma chamada de função?)
flawr

@flawr Uma função, semelhante à APL
abanada

Eu acho que você poderia evitar definir explicitamente fse usar algo como, >./@:|@({.-{:)f"1@,mas não tenho certeza.
FUZxxl

4

Python 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)

A entrada são 2 listas para a função g

Graças a: Sp3000, xnor, undergroundmonorail

Linha 2, primeira chamada para fleituras como "fax". Eu achei isso levemente divertido


2
Para contar o número de elementos de uma lista que satisfazem uma propriedade, é mais curto sum(n>x for n in a). Além disso, parece que você não está usando s=filter. E max, na verdade, você não precisa dos colchetes da lista; O Python permite que a função pareça o dobro da compreensão.
xnor 02/02

Obrigado! Eu usei filterem uma versão anterior, esqueci de removê-lo. Infelizmente não consigo remover o primeiro par de colchetes desde então, será um gerador que não possui len.
Kroltan 2/02

você não precisa len, leia o comentário novamente: P
undergroundmonorail

3

JavaScript (ES6) 99 119 128

Implementação de JavaScript mais ou menos direta , provavelmente mais fácil de jogar . Na função F eu uso> em vez de <=, como abs (F (a) -F (b)) === abs ((1-F (a)) - (1-F (b)))

Não há mais definição de função como parâmetro padrão nesta última edição.

Como eu disse, é direto. A função F é a função F, a função D é a função sem nome usada na linha 2. É avaliada usando .map para cada valor presente nas duas matrizes, pois o valor máximo para allreais deve ser um deles. Por fim, o operador de spread (...) é usado para passar a matriz de valores D como uma lista de parâmetros para a função 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))
))

Teste no console do 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)))

Resultado

[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

Estou curioso sobre sua função K: é correto que você defina outras funções F,Dna lista de argumentos? Isso se comporta como alguns argumentos opcionais ou algo assim?
flawr

@ flawr sim, são argumentos opcionais com um valor padrão. Evitando assim a poluição do espaço variável global (que não é um problema no golfe código, mas de qualquer maneira ...)
edc65

1
Além disso, como a função já requeria 2 variáveis ​​(portanto, os colchetes), seriam 2 bytes extras para mover essas variáveis ​​da lista de opções var para dentro do corpo da função.
Optimizer

2

CJam, 33 31 bytes

q~_:+f{\f{f<_:+\,d/}}z{~-z}%$W=

Entrada é uma matriz de estilos CJam das duas matrizes.

Exemplo:

[[8 9 9 5 5 0 3] [4 9 0 5 5 0 4 6 9 10 4 0 9]]

Resultado:

0.17582417582417587

Experimente online aqui


2

Matlab (121) (119)

Este é um programa que pega duas listas através de stdin e imprime o resultado em stdout. É uma abordagem direta e tentei jogar golfe o máximo possível. K(a)retorna uma função que calcula x -> F(a,x). Em seguida, a função anônima @(x)abs(g(x)-h(x))que corresponde à função Dé aplicada a todo número inteiro possível 0:max([a,b])e o máximo dos resultados é exibido. ( arrayfunfaz o mesmo que mapem outros idiomas: aplica uma função a todos os elementos de uma matriz)

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

Erlang, 96 bytes

A solução JavaScript do edc65 foi portada para 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]).

Teste:

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]]]).

Resultado:

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

Isso significa 90% da entrada do arquivo em um formato que pode ser usado porque o STATA já possui um comando 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)

Oh, uau, eu não achei que as linguagens tivessem um construtor para isso ... Acabei de fazer uma pesquisa e decidi que seria melhor desabilitar os construtores a partir de agora, mas você pode manter isso porque foi publicado antes da regra alteração :)
Sp3000 02/02

2

R, 65 bytes

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

Essa função aceita dois vetores como argumentos e retorna a diferença máxima de suas funções de distribuição cumulativa empírica.

Se os embutidos fossem permitidos, reduziria para meros 12 bytes:

ks.test(a,b)

1

Mathematica, 76 73 63

O Mathematica possui a função interna KolmogorovSmirnovTest, mas não a utilizarei aqui.

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

Uso:

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

0,5


0

Implementação rápida no Python 3.4.2 (79 bytes):

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

Exemplo:

>>> 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
O requisito é encontrar o valor máximo de D (x) para todos os valores inteiros de x. Por favor, cumpra as especificações do problema.
Optimizer

1
Bem-vinda! Como o Optimizer diz, a tarefa é encontrar o valor máximo de D, não apenas implementar Dcomo uma função. Além disso, me desculpe se eu não estava claro, mas você não pode assumir que A1e A2já estão variáveis definidas (você pode colocá-los no lambda embora, por exemplo lambda x,A1,A2:- que está tudo bem)
SP3000

Também eu adicionei algumas destaque de sintaxe - Acho que faz com que pareça mais bonito :)
SP3000

Desculpe por isso, eu sou novo aqui.
Kapten 02/02

Sem problemas :) Se algo não estiver claro, você pode perguntar nos comentários. Mas mais uma vez, seja bem-vindo!
Sp3000 02/02

0

Java - 633 622 bytes

Ok, primeiro, tentando melhorar em java, por isso tentei em java, sei que nunca vou me sair bem, mas é divertido. segundo, sinceramente pensei que poderia fazer isso de uma maneira menos, depois cheguei ao estágio em que havia duplas em todos os lugares, e as declarações do método significavam que o uso de métodos salvava apenas 4-5 caracteres no total. em resumo, sou um mau jogador de golfe.

editar: formato de uso> 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;}}

você estava certo. atualização.
Bryan Devaney

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

(!) é a função kolmogorov-smirnov que leva duas listas


1
alguns golfe rápidos: use em mapvez de fmap; use em maximumvez de foldr1 max; defina l=fromIntegral.lengthe você poderá se livrar ie, em seguida, poderá abreviá %-lo l(filter(<=x)a)/l a. Reduz para 84!
MtnViewMark

0

R, 107 bytes

Abordagem diferente

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
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.