Kolmogorov (-Smirnov) senza complessità


12

In statistica, a volte è utile sapere se due campioni di dati provengono dalla stessa distribuzione sottostante. Un modo per farlo è utilizzare il test di Kolmogorov-Smirnov a due campioni .

Il tuo compito sarà quello di scrivere un programma che legge in due array di numeri interi non negativi non ordinati e calcola la statistica principale utilizzata nel test.


Dato un array Ae un numero reale x, definire la funzione di distribuzione Fda

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

Dati due array A1e A2, definire

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

La statistica a due campioni di Kolmogorov-Smirnov è il valore massimo di Dtutto il reale x.

Esempio

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

Poi:

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 statistica KS per i due array è 1/2il valore massimo di D.

Casi test

[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

Regole

  • È possibile scrivere una funzione o un programma completo. L'ingresso può essere tramite STDIN o argomento della funzione e l'output può essere tramite STDOUT o valore di ritorno.
  • È possibile assumere qualsiasi elenco o formato di stringa non ambiguo per l'input, purché sia ​​coerente per entrambi gli array
  • Nel caso in cui la tua lingua sia integrata per questo, non puoi usarla.
  • Le risposte devono essere corrette per almeno 3 cifre significative
  • Questo è , quindi vince il programma nel minor numero di byte

Tutti gli input saranno array interi o possono contenere punti mobili?
kennytm,

@KennyTM Solo numeri interi non negativi. Ho pensato di mantenere le cose semplici.
Sp3000,

Esiste un valore massimo che possiamo assumere per le matrici? (Ad esempio tutte le voci di Asono sotto length(A)?)
flawr

@flawr No, non puoi assumere un valore massimo
Sp3000,

Mi piace il titolo. Sto progettando come target la complessità kolmogorov, ma non questa volta.
edc65,

Risposte:


10

APL ( 29 24)

(Grazie a Zgarb per l'ispirazione extra.)

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

Questa è una funzione che prende le matrici come argomenti sinistro e destro.

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

Spiegazione:

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

Non sapevo che potessi fare ⍺⍵! È utile.
Zgarb,

1
Inoltre, penso che ⍳⌈/non sia necessario, poiché il massimo si ottiene esattamente con uno dei valori dell'array.
Zgarb,

@Zgarb: hai ragione ovviamente, devo solo provare per ogni possibile valore di array. Ciò significa che posso liberarmene 0,anch'io, poiché lo verificherà se l'array lo contiene. Grazie! (E questo mi insegnerà, come al solito se devi aggiungere un caso speciale, significa che l'algoritmo non è abbastanza semplice.)
marinus

2
Questa è vera stregoneria, proprio qui.
Steven Lu

@ Sp3000: hai scritto correttamente gli array a un elemento? Non puoi semplicemente scrivere 1, poiché sarebbe uno scalare. Dovresti (,1)invece scrivere . Se lo fai, funziona.
Marin

4

J - 39

Sono sicuro che può essere abbreviato molto di più

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

Questo crea una funzione o usa stdin / stdout? Cosa fa esattamente la seconda parte? (Sembra un po 'lungo per una chiamata di funzione?)
flawr

@flawr Una funzione, simile a APL
swish

Penso che potresti evitare di definire esplicitamente fse usi qualcosa del genere >./@:|@({.-{:)f"1@,ma non ne sono del tutto sicuro.
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)

Gli input sono 2 elenchi per la funzione g

Grazie a: Sp3000, xnor, undergroundmonorail

Linea 2, prima chiamata a f"fax". L'ho trovato leggermente divertente


2
Per contare il numero di elementi di un elenco che soddisfano una proprietà, è più breve da fare sum(n>x for n in a). Inoltre, sembra che tu non stia usando s=filter. E per max, in realtà non hai bisogno delle parentesi di elenco; Python fa raddoppiare la funzione parentesi come parentesi di comprensione.
xnor

Grazie! Ho usato filterin una versione precedente, ho dimenticato di rimuoverlo. Purtroppo non riesco a rimuovere la prima coppia di parentesi quadre da allora sarà un generatore, che non ha len.
Kroltan,

non hai bisogno len, leggi di nuovo il commento: P
undergroundmonorail

3

JavaScript (ES6) 99 119 128

Implementazione JavaScript più o meno semplice , probabilmente più giocabile . Nella funzione F uso> invece di <=, come abs (F (a) -F (b)) === abs ((1-F (a)) - (1-F (b)))

Niente più definizione di funzione come parametro predefinito in quest'ultima modifica.

Come ho già detto, è semplice. La funzione F è la funzione F, la funzione D è la funzione senza nome utilizzata nella riga 2. Viene valutata utilizzando .map per ciascun valore presente nei due array, poiché il valore massimo per i allreali deve essere uno di questi. Alla fine, l'operatore spread (...) viene utilizzato per passare l'array dei valori D come elenco di parametri alla funzione 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))
))

Test nella console 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)))

Produzione

[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

Sono curioso della tua funzione K: è corretto definire altre funzioni F,Dnell'elenco degli argomenti? Questo si comporta come qualche argomento opzionale o giù di lì?
Flawr

@flawr sì, sono argomenti opzionali con un valore predefinito. Quindi, evitando l'inquinamento dello spazio variabile globale (non è un problema nel golf del codice, ma comunque ...)
edc65,

1
Inoltre, poiché la funzione richiede già 2 variabili (quindi le parentesi), sarebbero 2 byte in più per spostare quelle variabili dall'elenco var di opzioni all'interno del corpo della funzione.
Ottimizzatore

2

CJam, 33 31 byte

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

Input è un array di stili CJam dei due array.

Esempio:

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

Produzione:

0.17582417582417587

Provalo online qui


2

Matlab (121) (119)

Questo è un programma che prende due elenchi tramite stdin e stampa il risultato su stdout. È un approccio rigoroso e ho provato a giocarlo il più possibile. K(a)restituisce una funzione che calcola x -> F(a,x). Quindi la funzione anonima @(x)abs(g(x)-h(x))che corrisponde alla funzione Dviene applicata a tutti i possibili numeri interi 0:max([a,b])e viene visualizzato il massimo dei risultati. ( arrayfunfa lo stesso che mapin altre lingue: applica una funzione a ogni elemento di un array)

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 byte

La soluzione JavaScript di edc65 è stata portata su 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]).

Test:

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

Produzione:

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

Questo è il 90% che ottiene l'input in un formato che può essere utilizzato perché STATA ha già 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)

Oh wow, non pensavo che le lingue avrebbero avuto un riscontro per questo ... Ho appena fatto qualche ricerca e ho deciso che sarebbe meglio non consentire i builtin d'ora in poi, ma puoi tenerlo perché è stato pubblicato prima della regola cambia :)
Sp3000,

2

R, 65 byte

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

Questa funzione accetta due vettori come argomenti e restituisce la massima differenza delle loro funzioni di distribuzione cumulativa empirica.

Se gli incorporamenti fossero consentiti, si ridurrebbe a soli 12 byte:

ks.test(a,b)

1

Mathematica, 76 73 63

Mathematica ha la funzione integrata KolmogorovSmirnovTest, ma non la userò qui.

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

Implementazione rapida in Python 3.4.2 (79 byte):

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

Esempio:

>>> 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
Il requisito è trovare il valore massimo di D (x) per tutti i valori interi di x. Si prega di rispettare le specifiche del problema.
Ottimizzatore

1
Benvenuto! Come dice Optimizer, il compito è quello di trovare il valore massimo di D, non solo implementarlo Dcome funzione. Inoltre, mi dispiace se non sono stato chiaro, ma non puoi presumere che A1e A2siano già variabili definite (puoi comunque inserirle nella lambda, ad esempio lambda x,A1,A2:- va bene)
Sp3000

Inoltre ho aggiunto un po 'di evidenziazione della sintassi - penso che lo faccia sembrare più bello :)
Sp3000

Mi dispiace, sono nuovo qui.
Kapten,

Nessun problema :) Se qualcosa non è chiaro, puoi chiedere nei commenti. Ma ancora una volta, benvenuto!
Sp3000,

0

Java - 633 622 byte

Ok, prima di tutto, provando a migliorare a java, ecco perché l'ho provato a java, so che non farò mai bene, ma eh, è ​​divertente. secondo, onestamente pensavo di poterlo fare in modo molto meno, poi sono arrivato al punto in cui c'erano doppi ovunque, e le dichiarazioni dei metodi significavano che usando i metodi ho salvato solo 4-5 caratteri in totale. insomma, sono un cattivo giocatore di golf.

modifica: formato utilizzo> 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;}}

avevi ragione. in aggiornamento.
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

(!) è la funzione kolmogorov-smirnov che accetta due elenchi


1
alcuni campi da golf veloci: usare mappiuttosto che fmap; usare maximumpiuttosto che foldr1 max; definire l=fromIntegral.lengthe si può sbarazzarsi di i, e poi si può ridurre %a l(filter(<=x)a)/l a. Ritorna a 84!
MtnViewMark

0

R, 107 byte

Approccio diverso

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
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.