Régression linéaire sur une chaîne

25

Ce défi est un peu délicat, mais plutôt simple, étant donné une chaîne s:

meta.codegolf.stackexchange.com

Utilisez la position du caractère dans la chaîne comme xcoordonnée et la valeur ascii comme ycoordonnée. Pour la chaîne ci-dessus, l'ensemble de coordonnées résultant serait:

0, 109
1, 101
2, 116
3, 97
4, 46
5, 99
6, 111
7, 100
8, 101
9, 103
10,111
11,108
12,102
13,46
14,115
15,116
16,97
17,99
18,107
19,101
20,120
21,99
22,104
23,97
24,110
25,103
26,101
27,46
28,99
29,111
30,109

Ensuite, vous devez calculer la pente et l'ordonnée à l'origine de l'ensemble que vous avez obtenu en utilisant la régression linéaire , voici l'ensemble ci-dessus tracé:

Terrain

Ce qui donne une ligne de meilleur ajustement (indexée sur 0):

y = 0.014516129032258x + 99.266129032258

Voici la ligne la mieux ajustée indexée 1 :

y = 0.014516129032258x + 99.251612903226

Votre programme reviendrait donc:

f("meta.codegolf.stackexchange.com") = [0.014516129032258, 99.266129032258]

Ou (tout autre format raisonnable):

f("meta.codegolf.stackexchange.com") = "0.014516129032258x + 99.266129032258"

Ou (tout autre format raisonnable):

f("meta.codegolf.stackexchange.com") = "0.014516129032258\n99.266129032258"

Ou (tout autre format raisonnable):

f("meta.codegolf.stackexchange.com") = "0.014516129032258 99.266129032258"

Expliquez simplement pourquoi il revient dans ce format s'il n'est pas évident.


Quelques règles de clarification:

- Strings are 0-indexed or 1 indexed both are acceptable.
- Output may be on new lines, as a tuple, as an array or any other format.
- Precision of the output is arbitrary but should be enough to verify validity (min 5).

Il s'agit du nombre de victoires par nombre d'octets le plus bas du .

Urne de poulpe magique
la source
3
Avez-vous un lien / une formule pour calculer la pente et l'ordonnée à l'origine?
Rod
16
Chers électeurs peu clairs: Bien que je convienne qu'il est agréable d'avoir la formule, elle n'est en aucun cas nécessaire. La régression linéaire est une chose bien définie dans le monde mathématique, et l'OP peut vouloir laisser la recherche de l'équation au lecteur.
Nathan Merrill
2
Est-il correct de renvoyer l'équation réelle de la ligne la mieux ajustée, comme 0.014516129032258x + 99.266129032258?
Greg Martin
2
Le titre de ce défi a mis cette merveilleuse chanson dans ma tête pour le reste de la journée
Luis Mendo

Réponses:

2

MATL , 8 octets

n:G3$1ZQ

L'indexation de chaînes basée sur 1 est utilisée.

Essayez-le en ligne!

Explication

n:     % Input string implicitly. Push [1 2 ... n] where n is string length.
       % These are the x values
G      % Push the input string. A string is an array of chars, which is
       % equivalent to an array of ASCII codes. These are the y values
3$     % The next function will use 3 inputs
1      % Push 1
ZQ     % Fit polynomial of degree 1 to those x, y data. The result is an
       % array with the polynomial coefficients. Implicitly display
Luis Mendo
la source
7

Octave, 29 26 24 20 octets

@(s)s/[!!s;1:nnz(s)]

Essayez-le en ligne!

Nous avons le modèle

y= intercept *x^0 + slope * x
 = intercept * 1  + slope * x

Ici y la valeur ASCII de la chaînes

Pour trouver les paramètres d'interception et de pente, nous pouvons former l'équation suivante:

s = [intercept slope] * [1 X]

alors

[intercept slope] = s/[1 x]

!!sconvertit une chaîne en un vecteur de même longueur que la chaîne.
Le vecteur des uns est utilisé pour l'estimation de l'ordonnée à l'origine.
1:nnz(s)est une plage de valeurs de 1 au nombre d'éléments de la chaîne utilisée comme x.

Réponse précédente

@(s)ols(s'+0,[!!s;1:nnz(s)]')

Pour tester, collez le code suivant dans Octave Online

(@(s)ols(s'+0,[!!s;1:nnz(s)]'))('meta.codegolf.stackexchange.com')

Une fonction qui accepte une chaîne en entrée et applique une estimation des moindres carrés ordinaires du modèle y = x*b + e

Le premier argument de ols est yque pour cela nous transposons la chaîne set ajoutons avec le numéro 0 pour obtenir son code ASCII.

rahnema1
la source
/, bonne idée!
Luis Mendo
6

TI-Basic, 51 (+ 141) octets

Les chaînes sont basées sur 1 dans TI-Basic.

Input Str1
seq(I,I,1,length(Str1->L1
32+seq(inString(Str2,sub(Str1,I,1)),I,1,length(Str1->L2
LinReg(ax+b)

Comme l'autre exemple, cela génère l'équation de la ligne la mieux ajustée, en termes de X. En outre, dans Str2, vous devez avoir cette chaîne, qui est de 141 octets dans TI-Basic:

! "# $% & '() * +, -. / 0123456789:; <=>? @ ABCDEFGHIJKLMNOPQRSTUVWXYZ [] ^ _abcdefghijklmnopqrstuvwxyz{|}~

La raison pour laquelle cela ne peut pas faire partie du programme est que deux caractères dans TI-Basic ne peuvent pas être automatiquement ajoutés à une chaîne. L'un est la STO->flèche, mais ce n'est pas un problème car il ne fait pas partie de l'ASCII. L'autre est la chaîne literal ( "), qui ne peut être stringifiée qu'en tapant dans une Y=équation et en utilisant Equ>String(.

Timtech
la source
Je me demandais sérieusement si quelqu'un sortirait ses vieilles calculatrices pour ça :). J'avais en tête ma vieille TI-83 quand j'ai pensé à ça.
Magic Octopus Urn
@carusocomputing Hé, bien! J'aime beaucoup le langage de programmation TI-Basic et je l'utilise pour beaucoup de mes golfs à code. Si seulement il supportait ASCII ...
Timtech
Deux commentaires: 1, vous pouvez le filtrer "en le demandant également comme entrée utilisateur dans un programme, ce qui ne vous aide pas ici, mais je voulais simplement souligner ce fait. 2, je ne reconnais pas certains de ces caractères comme existant sur la calculatrice. Je peux me tromper, mais par exemple, où obtenez-vous @et ~? En plus #, $et &.
Patrick Roberts
Merci pour le commentaire, @PatrickRoberts. Ce sont des jetons de deux octets commençant par 0xBB. Regardez dans la colonne D de tibasicdev.wikidot.com/miscivers-tokens
Timtech
6

R, 46 45 octets

x=1:nchar(y<-scan(,""));lm(utf8ToInt(y)~x)$co

Lit l'entrée de stdin et pour les retours de cas de test donnés (un indexé):

(Intercept)           x 
99.25161290  0.01451613 
Billywob
la source
Légèrement plus court (mais non testé, peut-être quelques problèmes d'évaluation lors de l'analyse de la formule):lm(utf8ToInt(y<-scan(,""))~1:nchar(y))$co
rturnbull
@rturnbull J'ai essayé cela au début, mais il semble que la xvariable doit être prédéfinie pour lmfonctionner.
Billywob
@rturnbull J'obtiens une erreur de longueur variable à ce sujet. On nous donne sdonc x=1:nchar(s);lm(charToRaw(s)~x)$cosauve quelques octets. Je ne sais pas non plus si $coc'est techniquement nécessaire, car vous obtenez toujours l'interception + le coefficient sans cela
Chris
@Chris Assez sûr que ce n'est pas une réponse viable. Il devrait y avoir une entrée de stdin ou comme argument de fonction.
Billywob
Assez juste, juste ma lecture de la question - cela donne une comparaison plus juste avec les réponses python + octave également
Chris
5

Python, 82 80 octets

-2 octets grâce à @Mego

En utilisant scipy:

import scipy
lambda s:scipy.stats.linregress(range(len(s)),list(map(ord,s)))[:2]
dfernan
la source
Les lambdas sans nom sont autorisés, vous pouvez donc supprimer le f=.
Mego
@DigitalTrauma numpy.linalg.lstsqdiffère apparemment des arguments scipy.stats.linregresset est plus complexe.
dfernan
4

Mathematica, 31 octets

Fit[ToCharacterCode@#,{1,x},x]&

Fonction sans nom prenant une chaîne en entrée et renvoyant l'équation réelle de la ligne la mieux adaptée en question. Par exemple, f=Fit[ToCharacterCode@#,{1,x},x]&; f["meta.codegolf.stackexchange.com"]renvoie 99.2516 + 0.0145161 x.

ToCharacterCodeconvertit une chaîne ASCII en une liste des valeurs ASCII correspondantes; en effet, il utilise par défaut l'UTF-8 plus généralement. (Un peu triste, dans ce contexte, qu'un nom de fonction comprend plus de 48% de la longueur du code ....) Et Fit[...,{1,x},x]est le intégré pour le calcul de la régression linéaire.

Greg Martin
la source
1
Merci pour l'exemple de la ligne indexée 1, je n'ai pas eu à la calculer à cause de vous haha.
Magic Octopus Urn
4

Node.js, 84 octets

En utilisant regression:

s=>require('regression')('linear',s.split``.map((c,i)=>[i,c.charCodeAt()])).equation

Démo

// polyfill, since this is clearly not Node.js
function require(module) {
  return window[module];
}
// test
["meta.codegolf.stackexchange.com"].forEach(function test(string) {
  console.log(string);
  console.log(this(string));
},
// submission
s=>require('regression')('linear',s.split``.map((c,i)=>[i,c.charCodeAt()])).equation
);
<script src="https://cdn.rawgit.com/Tom-Alexander/regression-js/master/src/regression.js"></script>

Patrick Roberts
la source
3

Sauge, 76 octets

var('m','c')
y(x)=m*x+c
f=lambda x:find_fit(zip(range(len(x)),map(ord,x)),y)

Presque aucun golf, probablement plus long qu'une réponse Python au golf, mais oui ...

busukxuan
la source
2

J , 11 octets

3&u:%.1,.#\

Cela utilise une indexation à base unique.

Essayez-le en ligne!

Explication

3&u:%.1,.#\  Input: string S
         #\  Get the length of each prefix of S
             Forms the range [1, 2, ..., len(S)]
      1,.    Pair each with 1
3&u:         Get the ASCII value of each char in S
    %.       Matrix divide
miles
la source
2

JavaScript, 151 148 octets

s=>([a,b,c,d,e]=[].map.call(s,c=>c.charCodeAt()).reduce(([a,b,c,d,e],y,x)=>[a+1,b+x,c+x*x,d+y,e+x*y],[0,0,0,0,0]),[k=(e*a-b*d)/(c*a-b*b),(d-k*b)/a])

Plus lisible:

Markus Jarderot
la source
Vous pouvez enregistrer un octet en le supprimant 0de c.charCodeAt(0), et 2 autres octets en déplaçant le k=...groupe de virgules et en le plaçant directement dans le premier index du tableau renvoyé comme[k=...,(d-k*b)/a]
Patrick Roberts
2

Javascript (ES6), 112 octets

s=>[m=(a=b=c=d=0,([...s].map((u,x)=>{a+=n=x,b+=y=u.charCodeAt(),c+=x*x,d+=x*y}),++n)*d-a*b)/(n*c-a*a),b/n-m*a/n]

F=s=>[m=(a=b=c=d=0,([...s].map((u,x)=>{a+=n=x,b+=y=u.charCodeAt(),c+=x*x,d+=x*y}),++n)*d-a*b)/(n*c-a*a),b/n-m*a/n]

const update = () => {
  console.clear();
  console.log(F(input.value));
};
input.oninput = update;
update();
#input {
  width: 100%;
  box-sizing: border-box;
}
<input id="input" type="text" value="meta.codegolf.stackexchange.com" length=99/>
<div id="output"></div>

George Reith
la source
2

Haskell, 154 142 octets

import Statistics.LinearRegression
import Data.Vector
g x=linearRegression(generate(Prelude.length x)i)$i.fromEnum<$>fromList x
i=fromIntegral

C'est beaucoup trop long à mon goût à cause des importations et des longs noms de fonction, mais bon. Je ne pouvais penser à aucune autre méthode de golf, bien que je ne sois pas expert dans le domaine des importations de golf.

Dépouillé de 12 octets par remplacement ordet importation de Data.Charby fromEnum grâce à nimi.

Renzeee
la source
1
Vous pouvez remplacer ordavec fromEnumet de se débarrasser de import Data.Char.
nimi
1

SAS Macro Language, 180 octets

Utilise l'indexation basée sur 1. La solution devient assez verbeuse lorsque la sortie n'est que la pente et l'interception.

%macro t(a);data w;%do i=1 %to %length(&a);x=&i;y=%sysfunc(rank(%substr(&a,&i,1)));output;%end;run;proc reg outtest=m;model y=x/noprint;run;proc print data=m;var x intercept;%mend;
J_Lard
la source
1

Clojure, 160 octets

Pas de fonction intégrée, utilise l'algorithme itératif décrit dans l' article Perceptron . Peut ne pas converger vers d'autres entrées, dans ce cas, réduire le taux d'apprentissage 2e-4et peut-être augmenter le nombre d'itérations 1e5. Je ne sais pas si l'algorithme non itératif aurait été plus court à implémenter.

#(nth(iterate(fn[p](let[A apply e(for[x(range(count %))](-(int(get % x))(*(p 1)x)(p 0)))](mapv(fn[p e](+(* e 2e-4)p))p[(A + e)(A +(map *(range)e))])))[0 0])1e5)

Exemple:

(def f #( ... ))
(f "meta.codegolf.stackexchange.com")

[99.26612903225386 0.014516129032464659]
NikoNyrh
la source
1

Érable, 65 octets

Statistics:-LinearFit(b*x+a,[$(1..length(s))],convert(s,bytes),x)

Usage:

s := "meta.codegolf.stackexchange.com";
Statistics:-LinearFit(b*x+a,[$(1..length(s))],convert(s,bytes),x);

Résultats:

99.2516129032259+0.0145161290322573*x

Remarques: Cela utilise la commande Ajuster pour ajuster un polynôme de la forme a * x + b aux données. Les valeurs ASCII de la chaîne sont trouvées en les convertissant en octets.

DSkoog
la source