Kolmogorov libre de complejidades (-Smirnov)

12

En estadística, a veces es útil saber si dos muestras de datos provienen de la misma distribución subyacente. Una forma de hacerlo es usar la prueba de Kolmogorov-Smirnov de dos muestras .

Su tarea será escribir un programa que lea en dos conjuntos enteros no negativos no clasificados y calcule la estadística principal utilizada en la prueba.


Dada una matriz Ay un número real x, defina la función de distribución Fpor

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

Dadas dos matrices A1y A2, definir

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

La estadística de Kolmogorov-Smirnov de dos muestras es el valor máximo de Dtodo real x.

Ejemplo

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

Luego:

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

La estadística KS para las dos matrices es 1/2el valor máximo de D.

Casos de prueba

[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

Reglas

  • Puede escribir una función o un programa completo. La entrada puede ser a través de STDIN o argumento de función, y la salida puede ser a través de STDOUT o valor de retorno.
  • Puede asumir cualquier formato de lista o cadena inequívoco para la entrada, siempre que sea coherente para ambas matrices
  • En caso de que su idioma tenga algo incorporado para esto, no puede usarlo.
  • Las respuestas deben ser correctas para al menos 3 cifras significativas
  • Este es el , por lo que el programa en la menor cantidad de bytes gana
Sp3000
fuente
¿Todas las entradas serán matrices enteras o pueden contener puntos flotantes?
kennytm
@KennyTM Solo enteros no negativos. Pensé en mantener las cosas simples.
Sp3000
¿Existe un valor máximo que podamos asumir para las matrices? (Por ejemplo, ¿todas las entradas Aestán debajo length(A)?)
error
@flawr No, no puede asumir un valor máximo
Sp3000
Me gusta el titulo Todavía estoy apuntando a la complejidad de kolmogorov, pero esta vez no.
edc65

Respuestas:

10

APL ( 29 24)

(Gracias a Zgarb por la inspiración extra).

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

Esta es una función que toma las matrices como sus argumentos izquierdo y derecho.

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

Explicación:

{⌈/                                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
                          }
marinus
fuente
¡No sabía que podías hacer ⍺⍵! Eso es útil.
Zgarb
1
Además, creo que ⍳⌈/es innecesario, ya que el máximo se obtiene exactamente en uno de los valores de la matriz.
Zgarb
@ Zgarb: tienes razón, por supuesto, solo tengo que probar cada valor de matriz posible. Eso significa que también puedo deshacerme de él 0,, ya que lo probará si la matriz lo contiene. ¡Gracias! (Y eso me enseñará, como generalmente si tiene que agregar un caso especial, eso significa que el algoritmo no es lo suficientemente simple)
Marinus
2
Esta es la verdadera brujería, aquí mismo.
Steven Lu
@ Sp3000: ¿escribió correctamente las matrices de un elemento? No puedes simplemente escribir 1, ya que sería un escalar. Deberías escribir en su (,1)lugar. Si haces eso, funciona.
marinus
4

J - 39

Estoy seguro de que se puede acortar mucho más

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
silbido
fuente
¿Esto crea una función o usa stdin / stdout? ¿Qué hace exactamente la segunda parte? (¿Parece un poco largo para una llamada a función?)
error
@flawr Una función, similar a APL
swish
Creo que podría evitar definir explícitamente fsi usa algo como, >./@:|@({.-{:)f"1@,pero no estoy muy seguro.
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)

La entrada son 2 listas para la función g

Gracias a: Sp3000, xnor, undergroundmonorail

Línea 2, primera llamada a flecturas como "fax". Eso me pareció un poco divertido

Kroltan
fuente
2
Para contar el número de elementos de una lista que satisfacen una propiedad, es más corto sum(n>x for n in a). Además, parece que no estás usando s=filter. Y para max, en realidad no necesita los corchetes de la lista; Python permite que la función parens se duplique como comprensión parens.
xnor
¡Gracias! Utilicé filteren una versión anterior, olvidé eliminarlo. Lamentablemente, no puedo eliminar el primer par de corchetes, ya que será un generador, que no tiene len.
Kroltan
no necesita len, lea el comentario nuevamente: P
undergroundmonorail
3

JavaScript (ES6) 99 119 128

Implementación de JavaScript más o menos sencilla , probablemente más fácil de jugar . En la función F uso> en lugar de <=, como abs (F (a) -F (b)) === abs ((1-F (a)) - (1-F (b)))

No más definición de función como parámetro predeterminado en esta última edición.

Como dije, es sencillo. La función F es la función F, la función D es la función sin nombre utilizada en la línea 2. Se evalúa usando .map para cada valor presente en las dos matrices, ya que el valor máximo para allreales debe ser uno de estos. Por último, el operador de propagación (...) se utiliza para pasar la matriz de valores D como una lista de parámetros a la función máxima.

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

Prueba en la consola 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)))

Salida

[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
edc65
fuente
Soy curioso acerca de su función K: ¿es correcto que defina otras funciones F,Den la lista de argumentos? ¿Esto se comporta como algunos argumentos opcionales más o menos?
falla
@flawr sí, son argumentos opcionales con un valor predeterminado. Entonces, evitar la contaminación del espacio variable global (eso no es un problema en el golf de código, pero de todos modos ...)
edc65
1
Además, dado que la función ya requería 2 variables (por lo tanto, los corchetes), serían 2 bytes adicionales para mover esas variables fuera de la lista var de opciones al interior del cuerpo de la función.
Optimizador del
2

CJam, 33 31 bytes

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

La entrada es una matriz de estilos CJam de las dos matrices.

Ejemplo:

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

Salida:

0.17582417582417587

Pruébalo en línea aquí

Optimizador
fuente
2

Matlab (121) (119)

Este es un programa que toma dos listas a través de stdin e imprime el resultado en stdout. Es un enfoque perfecto y traté de jugar al golf lo más posible. K(a)devuelve una función que calcula x -> F(a,x). Luego, la función anónima @(x)abs(g(x)-h(x))que corresponde a la función Dse aplica a cada entero posible 0:max([a,b])y se muestra el máximo de los resultados. ( arrayfunhace lo mismo que mapen otros idiomas: aplica una función a cada elemento de una 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]))))
falla
fuente
2

Erlang, 96 bytes

La solución JavaScript de edc65 portada a 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]).

Prueba:

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

Salida:

[[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
cPu1
fuente
2

STATA 215

Esto es 90% obteniendo la entrada en un formato que puede usarse porque STATA ya tiene un 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)
comentarios
fuente
Oh, wow, no pensé que los idiomas tendrían un valor incorporado para esto ... Solo investigué un poco y decidí que sería mejor no permitirlo de ahora en adelante, pero puedes guardar esto porque fue publicado antes de la regla cambio :)
Sp3000
2

R, 65 bytes

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

Esta función toma dos vectores como argumentos y devuelve la diferencia máxima de sus funciones de distribución acumulativa empírica.

Si se permitieran las incorporaciones, se reduciría a solo 12 bytes:

ks.test(a,b)
Andreï Kostyrka
fuente
1

Mathematica, 76 73 63

Mathematica tiene la función incorporada KolmogorovSmirnovTest, pero no la usaré aquí.

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

alephalpha
fuente
0

Implementación rápida en 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))

Ejemplo:

>>> 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
Kapten
fuente
1
El requisito es encontrar el valor máximo de D (x) para todos los valores enteros de x. Por favor, cumpla con las especificaciones del problema.
Optimizador del
1
¡Bienvenido! Como dice Optimizer, la tarea es encontrar el valor máximo de D, no solo implementarlo Dcomo una función. Además, lo siento si no estaba claro, pero no puede asumir eso A1y A2ya son variables definidas (aunque puede ponerlas en el lambda, por ejemplo lambda x,A1,A2:, está bien)
Sp3000
También he agregado un poco de resaltado de sintaxis - Creo que lo hace ver más bonito :)
Sp3000
Lo siento, soy nuevo aquí.
Kapten
No hay problemas :) Si algo no está claro, puede preguntar en los comentarios. Pero una vez más, ¡bienvenido!
Sp3000
0

Java - 633 622 Bytes

Ok, primero, tratando de mejorar en Java, así que por eso lo intenté en Java, sé que nunca lo haré bien, pero eh, es divertido. segundo, honestamente pensé que podía hacer esto de una manera menos, luego llegué al escenario donde había dobles en todas partes, y las declaraciones de métodos significaban que usar métodos solo guardaba 4-5 caracteres en total. En resumen, soy un mal golfista.

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;}}
Bryan Devaney
fuente
usted tenía razón. actualización
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

(!) es la función kolmogorov-smirnov que toma dos listas

Jmac
fuente
1
algunos campos de golf rápidos: use en maplugar de fmap; usar en maximumlugar de foldr1 max; definir l=fromIntegral.lengthy puede deshacerse de i, y luego puede acortar %a l(filter(<=x)a)/l a. ¡Se reduce a 84!
MtnViewMark
0

R, 107 bytes

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

Sin golf

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
}
usuario5957401
fuente