Qui est cette distribution de probabilité?

16

introduction

Dans ce défi, vous obtenez une liste de nombres à virgule flottante non négatifs tirés indépendamment d'une certaine distribution de probabilité. Votre tâche consiste à déduire cette distribution à partir des chiffres. Pour que le défi soit réalisable, vous n'avez que cinq distributions parmi lesquelles choisir.

Notez que toutes les distributions ci-dessus ont une moyenne exacte de 1/2.

La tâche

Votre entrée est un tableau de nombres à virgule flottante non négatifs, d'une longueur comprise entre 75 et 100 inclus. Votre sortie doit être l'une des lettres UTBEG, en fonction de laquelle des distributions ci-dessus vous pensez que les nombres sont tirés.

Règles et notation

Vous pouvez donner soit un programme complet soit une fonction. Les failles standard ne sont pas autorisées.

Dans ce référentiel , il y a cinq fichiers texte, un pour chaque distribution, chacun d'une longueur exacte de 100 lignes. Chaque ligne contient une liste délimitée par des virgules de 75 à 100 flottants dessinés indépendamment de la distribution et tronqués à 7 chiffres après la virgule décimale. Vous pouvez modifier les délimiteurs pour qu'ils correspondent au format de tableau natif de votre langue. Pour être considéré comme une réponse, votre programme doit classer correctement au moins 50 listes de chaque fichier . Le score d'une réponse valide est le nombre d'octets + le nombre total de listes mal classées . Le score le plus bas l'emporte.

Zgarb
la source
J'aurais probablement dû demander plus tôt, mais quelle optimisation est attendue pour les cas de test? Je suis à un point où je peux améliorer mon score en modifiant quelques paramètres, mais l'impact sur le score dépendra probablement des cas de test donnés.
Dennis
2
@Dennis Vous pouvez optimiser autant que vous le souhaitez, les cas de test sont une partie fixe du défi.
Zgarb
OUI NON Distribution de Student-t? = (
N3buchadnezzar

Réponses:

6

Julia, 60 62 octets + 25 2 erreurs = 82 64

k->"EGTBU"[(V=std(k);any(k.>1)?V>.34?1:2:V<.236?3:V>.315?4:5)]

C'est assez simple. La variance pour les distributions est généralement différente - c'est 1/4 pour exponentielle, 1/8 pour beta, 1/12 pour gamma et uniforme, et 1/24 pour triangulaire. En tant que tel, si nous utilisons la variance (ici fait en utilisant stdpour l'écart type, la racine carrée de la variance) pour déterminer la distribution probable, nous n'avons qu'à faire plus pour distinguer le gamma de l'uniforme; pour cela, nous recherchons une valeur supérieure à 1 (en utilisant any(k.>1)) - cela dit, nous vérifions à la fois l'exponentielle et le gamma, car cela améliore les performances globales.

Pour enregistrer un octet, l'indexation de la chaîne "EGTBU"est effectuée au lieu d'évaluer directement une chaîne dans les conditions.

Pour les tests, enregistrez les fichiers txt dans un répertoire (en conservant les noms tels quels) et exécutez Julia REPL dans ce répertoire. Ensuite, associez la fonction à un nom comme

f=k->"EGTBU"[(V=std(k);any(k.>1)?V>.34?1:2:V<.236?3:V>.315?4:5)]

et utilisez le code suivant pour automatiser le test (il lira le fichier, le convertira en un tableau de tableaux, utilisera la fonction et affichera pour chaque incompatibilité):

m=0;for S=["B","E","G","T","U"] K=open(S*".txt");F=readcsv(K);
M=Array{Float64,1}[];for i=1:100 push!(M,filter(j->j!="",F[i,:]))end;
close(K);n=0;
for i=1:100 f(M[i])!=S[1]&&(n+=1;println(i," "S,"->",f(M[i])," ",std(M[i])))end;
println(n);m+=n;end;println(m)

La sortie consistera en lignes contenant le cas qui ne correspond pas, la distribution correcte -> la distribution déterminée et la variance calculée (par exemple, 13 G->E 0.35008999281668357signifie que la 13e ligne dans G.txt, qui devrait être une distribution gamma, est déterminée comme étant exponentielle distribution, l'écart-type étant de 0,35008999 ...)

Après chaque fichier, il affiche également le nombre de non-correspondances pour ce fichier, puis à la fin, il affiche également le total des non-correspondances (et il devrait lire 2 s'il est exécuté comme ci-dessus). Soit dit en passant, il devrait avoir 1 non-correspondance pour G.txt et 1 non-correspondance pour U.txt

Glen O
la source
7

R, 202192184182162154154 octets + 0 erreur

function(x)c("U","T","B","E","G")[which.max(lapply(list(dunif(x),sapply(x,function(y)max(0,2-4*abs(.5-y))),dbeta(x,.5,.5),dexp(x,2),dgamma(x,3,6)),prod))]

Ceci est basé sur la formule bayésienne P (D = d | X = x) = P (X = x | D = d) * P (D = d) / P (X = x), où D est la distribution et X est l'échantillon aléatoire. Nous prenons le d tel que P (D = d | X = x) est le plus grand des 5.

Je suppose un a priori plat (c'est-à-dire P (D = di) = 1/5 pour i dans [1,5]), ce qui signifie que P (D = d) dans le numérateur est le même dans tous les cas (et le dénominateur serait être le même dans tous les cas de toute façon), donc nous pouvons tout jouer au golf sauf le P (x = X | D = d), qui (à l'exception de la distribution triangulaire) se simplifie en fonctions natives dans R.

non golfé:

function(x){
  u=prod(dunif(x))
  r=prod(sapply(x,function(y)max(0,2-4*abs(.5-y))))
  b=prod(dbeta(x,.5,.5))
  e=prod(dexp(x,2))
  g=prod(dgamma(x,3,6))
  den=.2*u+.2*r+.2*b+.2*e+.2*g
  c("U","T","B","E","G")[which.max(c(u*.2/den,r*.2/den,b*.2/den,e*.2/den,g*.2/den))]
}

Notez que la version non golfée n'est pas exactement équivalente à la version golfée car se débarrasser du dénominateur évite le cas d'Inf / Inf qui se produit si vous autorisez la distribution bêta à dépasser l'intervalle fermé [0,1] au lieu de (0, 1) - comme le font les données de l'échantillon. Une instruction if supplémentaire gérerait cela, mais comme c'est à des fins d'illustration uniquement, cela ne vaut probablement pas la peine d'ajouter la complexité qui n'est pas au cœur de l'algorithme.

Merci @Alex A. pour les réductions de code supplémentaires. Surtout pour quel.max!

njnnja
la source
1
Vous pouvez obtenir cela à 190 octets en supprimant le saut de ligne après l'ouverture {et celui avant la fermeture }, et l'aliasing prod, par exemple P=prod, puis le faire P(dunif(x)), etc. La fonction n'a pas besoin d'un nom pour être une soumission valide, vous pouvez donc supprimer p=. Aussi, excellent travail. :)
Alex A.
2
Vous pouvez l'obtenir à 182 en utilisant les suggestions ci-dessus et en utilisant which.max(c(u,r,b,e,g))à la place de c(u,r,b,e,g)==max(c(u,r,b,e,g)).
Alex A.
156:function(x){c("U","T","B","E","G")[which.max(lapply(list(dunif(x),sapply(x,function(y)max(0,2-4*abs(.5-y))),dbeta(x,.5,.5),dexp(x,2),dgamma(x,3,6)),prod))]}
Alex A.
Comment osez-vous utiliser R pour un défi impliquant des statistiques !!
flawr
6

CJam, 76

{2f*__{(z.4<},,%,4e<"UBT"="EG"\*\$-2=i3e<=}

Le code source fait 43 octets de long et classe mal 33 listes.

Vérification

$ count()(sort | uniq -c | sort -nr)
$ cat score.cjam
qN%{',' er[~]
  {2f*__{(z.4<},,%,4e<"UBT"="EG"\*\$-2=i3e<=}
~N}/
$ for list in U T B E G; { echo $list; cjam score.cjam < $list.txt | count; }
U
     92 U
      6 B
      2 T
T
    100 T
B
     93 B
      7 U
E
     92 E
      8 G
G
     90 G
      6 E
      3 T
      1 U

Idée

Il est facile de différencier la distribution exponentielle et gamma des autres, car ce sont les seules distributions qui prennent des valeurs supérieures à 1 .

Pour décider entre gamma , exponentielle et autres, nous examinons la deuxième valeur la plus élevée de l'échantillon.

  • Si elle se situe dans [1.5, ∞) , on devine gamma .

  • Si elle se situe dans [1, 1.5) , nous supposons exponentielle .

  • S'il se situe dans [0, 1) , il nous reste trois possibilités.

    Les distributions restantes peuvent être différenciées par le pourcentage de valeurs d'échantillon proches de la moyenne ( 0,5 ).

    Nous divisons la longueur de l'échantillon par le nombre de valeurs qui tombent dans (0,3, 0,7) et examinons le quotient résultant.

    • S'il se trouve dans (1, 2] , nous devinons triangulaire .

    • Si elle se trouve dans (2, 3] , on devine uniforme .

    • Si elle se trouve dans (3, ∞) , nous devinons beta .

Code

2f*    e# Multiply all sample values by 2.
__     e# Push to copies of the sample.
{      e# Filter; for each (doubled) value in the sample:
  (z   e#   Subtract 1 and apply absolute value.
  .4<  e#   Check if the result is smaller than 0.4.
},     e# If it is, keep the value.
,/     e# Count the kept values (K).
%      e# Select every Kth value form the sample, starting with the first.
,      e# Compute the length of the resulting array.
       e# This performs ceiled division of the sample length by K.
4e<    e# Truncate the quotient at 4.
"UBT"= e# Select 'T' for 2, 'U' for 3 and 'B' for 4.
"EG"\* e# Place the selected character between 'E' and 'G'.
\$     e# Sort the remaining sample.
-2=i   e# Extract the second-highest (doubled) value and cast to integer.
3e<    e# Truncate the result at 3.
=      e# Select 'E' for 3, 'G' for 2 and the character from before for 1.
Dennis
la source
3

Matlab, 428 328 octets + 33 mal classés

Ce programme compare essentiellement le CDF réel avec un estimé compte tenu des données, puis calcule la distance moyenne entre ces deux: je pense que l'image explique plus:

entrez la description de l'image ici

Les données montrées dans cette image ici montrent assez clairement qu'elle appartient à la distribution turquoise, car elle est assez proche de celle-ci, c'est donc essentiellement ce que fait mon programme. Il peut probablement être joué un peu plus. Pour moi, c'était d'abord un défi conceptuel, pas très golfique.

Cette approche est également indépendante des fichiers PDF choisis, elle fonctionnerait pour n'importe quel ensemble de distributions.

Le code (non golfé) suivant devrait montrer comment cela est fait. La version golfée est ci-dessous.

function r=p(x);
data=sort(x(1:75));
%% cumulative probability distributiosn
fu=@(x)(0<x&x<1).*x+(1<=x).*1;
ft=@(x)(0<x&x< 0.5).* 2.*x.^2+(1-2*(1-x).^2).*(0.5<=x&x<1)+(1<=x);
fb=@(x)(0<x&x<1).*2.*asin(sqrt(x))/pi+(1<=x);
fe=@(x)(0<x).*(1-exp(-2*x));
fg=@(x)(0<x).*(1-exp(-x*6).*(1+x*6+1/2*(6*x).^2));
fdata = @(x)sum(bsxfun(@le,data,x.'),2).'/length(data);
f = {fe,fg,fu,ft,fb};
str='EGUTB';
%calculate distance to the different cdfs at each datapoint
for k=1:numel(f);
dist(k) = max(abs(f{k}(x)-fdata(x)));
end;
[~,i]=min(dist);
r=str(i);
end

Version entièrement golfée:

function r=p(x);f={@(x)(0<x).*(1-exp(-2*x)),@(x)(0<x).*(1-exp(-x*6).*(1+x*6+18*x.^2)),@(x)(0<x&x<1).*x+(1<=x),@(x)(0<x&x<.5).*2.*x.^2+(1-2*(1-x).^2).*(.5<=x&x<1)+(1<=x),@(x)(0<x&x<1).*2.*asin(sqrt(x))/pi+(1<=x)};s='EGUTB';for k=1:5;d(k)=max(abs(f{k}(x)-sum(bsxfun(@le,x,x.'),2).'/nnz(x)));end;[~,i]=min(d(1:5-3*any(x>1)));r=s(i)
flawr
la source
2

Perl, 119 octets + 8 erreurs de classification = 127

J'ai fait un petit arbre de décision sur trois fonctionnalités:

  • $ o: booléen: si des échantillons> 1.0
  • $ t: count: 0-th moins 6-th 13-ile coupé dans la plage 0-1,
  • $ h: count: 0-th moins 6-th plus 12-th 13-ile coupé dans la plage 0-1

Appelé avec perl -F, -lane -e '...'. Je ne sais pas si je devrais ajouter une pénalité pour les paramètres non standard. Si les virgules étaient des espaces, je suppose que j'aurais pu m'enfuir sans le -F,

pour (@F) {$ b [$ _ * 13] ++; $ o ++ si $ _> 1}
$ h = ($ t = $ b [0] - $ b [6]) + $ b [12];
imprimer $ o? ($ t> -2? "e": "g"): ($ h = 19? "b": "u"));
$ o = @ b = ()

La sortie légèrement formatée (sans l'indicateur -l) est:

bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    bbbbbbbbbbbbbbbbbbbbbbbbubbbbbbbbbbbbbbbbbbbbbbb
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
    eeegeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
gggggggegggggggggggggggggggggggggggggggggggggggggggg
    gggggggggggggggggggggggggggggggggggggggggggggggg
tttttttttttttttttttttttttttttttttttttttttttttttttttt
    ttttttttttttttttttttttttttttuttttttttttttutttttt
uuuuuuuuuuuuuuuuuuuuuuuuuuutuuuuuuuuuuuuuuuubuuuuuuuu
    uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutuuuu
Dale Johnson
la source
0

Python, 318 octets + 35 erreurs de classification

from scipy.stats import*
from numpy import*
def f(l):
    r={'U':kstest(l,'uniform')[1],'T':kstest(l,'triang',args=(.5,))[1],'B':kstest(l,'beta',args=(.5,.5))[1],'E':kstest(l,'expon',args=(0,.5,))[1],'G':kstest(l,'gamma',args=(3,0,1/6.0))[1]}
    if sum([x>1 for x in l]): r['U'],r['T'],r['B']=0,0,0
    return max(r,key=r.get)

Idée: la distribution est supposée basée sur la valeur de p du test de Kolmogorov-Smirnov.

Tester

from scipy.stats import*
from numpy import*
import os
from io import StringIO
dir=os.path.dirname(os.path.abspath(__file__))+"/random-data-master/"

def f(l):
    r={'U':kstest(l,'uniform')[1],'T':kstest(l,'triang',args=(.5,))[1],'B':kstest(l,'beta',args=(.5,.5))[1],'E':kstest(l,'expon',args=(0,.5,))[1],'G':kstest(l,'gamma',args=(3,0,1/6.0))[1]}
    if sum([x>1 for x in l]): r['U'],r['T'],r['B']=0,0,0
    return max(r,key=r.get)

U=[line.rstrip('\n').split(',') for line in open(dir+'U.txt')]
U=[[float(x) for x in r] for r in U]
T=[line.rstrip('\n').split(',') for line in open(dir+'T.txt')]
T=[[float(x) for x in r] for r in T]
B=[line.rstrip('\n').split(',') for line in open(dir+'B.txt')]
B=[[float(x) for x in r] for r in B]
E=[line.rstrip('\n').split(',') for line in open(dir+'E.txt')]
E=[[float(x) for x in r] for r in E]
G=[line.rstrip('\n').split(',') for line in open(dir+'G.txt')]
G=[[float(x) for x in r] for r in G]

i,_u,_t,_b,_e,_g=0,0,0,0,0,0
for u,t,b,e,g in zip(U,T,B,E,G):
    _u+=1 if f(u)=='U' else 0
    _t+=1 if f(t)=='T' else 0
    _b+=1 if f(b)=='B' else 0
    _e+=1 if f(e)=='E' else 0
    _g+=1 if f(g)=='G' else 0
    print f(u),f(t),f(b),f(e),f(g)
print _u,_t,_b,_e,_g,100*5-_u-_t-_b-_e-_g
Aetienne Sardon
la source