Lineare Regression an einer Zeichenkette

25

Diese Herausforderung ist etwas knifflig, aber angesichts einer Zeichenfolge ziemlich einfach s:

meta.codegolf.stackexchange.com

Verwenden Sie die Position des Zeichens in der Zeichenfolge als xKoordinate und den ASCII-Wert als yKoordinate. Für die obige Zeichenfolge wäre der resultierende Satz von Koordinaten:

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

Als nächstes müssen Sie sowohl die Steigung als auch den y-Achsenabschnitt der Menge berechnen, die Sie mit der linearen Regression erhalten haben.

Handlung

Was zu einer Best-Fit-Linie von (0-indexiert) führt:

y = 0.014516129032258x + 99.266129032258

Hier ist die 1-indizierte Best-Fit-Linie:

y = 0.014516129032258x + 99.251612903226

So würde Ihr Programm zurückkehren:

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

Oder (jedes andere sinnvolle Format):

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

Oder (jedes andere sinnvolle Format):

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

Oder (jedes andere sinnvolle Format):

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

Erklären Sie einfach, warum es in diesem Format zurückgegeben wird, wenn es nicht offensichtlich ist.


Einige klärende Regeln:

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

Dies ist niedrigsten Anzahl an Bytes.

Magische Kraken-Urne
quelle
3
Haben Sie einen Link / eine Formel, um die Steigung und den y-Achsenabschnitt zu berechnen?
Rod
16
Sehr geehrte Unklarwähler, obwohl ich der Meinung bin, dass es schön ist, die Formel zu haben, ist dies keineswegs notwendig. Die lineare Regression ist in der mathematischen Welt eine gut definierte Sache, und das OP möchte es möglicherweise dem Leser überlassen, die Gleichung zu finden.
Nathan Merrill
2
Ist es in Ordnung, die tatsächliche Gleichung der bestangepassten Linie zurückzugeben, z 0.014516129032258x + 99.266129032258.
Greg Martin
2
Der Titel dieser Herausforderung hat mir für den Rest des Tages dieses wundervolle Lied in den Kopf gesetzt
Luis Mendo

Antworten:

2

MATL , 8 Bytes

n:G3$1ZQ

1-basierte Zeichenfolgenindizierung wird verwendet.

Probieren Sie es online!

Erläuterung

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

Oktave, 29 26 24 20 Bytes

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

Probieren Sie es online!

Wir haben das Modell

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

Hier yist der ASCII-Wert von strings

Um die Parameter Schnittpunkt und Steigung zu finden, können wir die folgende Gleichung bilden:

s = [intercept slope] * [1 X]

so

[intercept slope] = s/[1 x]

!!swandelt eine Zeichenkette in einen Vektor mit der gleichen Länge wie die Zeichenkette um.
Der Vektor von Einsen wird zur Abschätzung des Abschnitts verwendet.
1:nnz(s)Der Wertebereich von 1 bis zur Anzahl der Elemente der Zeichenfolge, die als verwendet wird x.

Vorherige Antwort

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

Fügen Sie zum Testen den folgenden Code in Octave Online ein

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

Eine Funktion, die eine Zeichenfolge als Eingabe akzeptiert und die gewöhnliche Schätzung der kleinsten Quadrate des Modells anwendet y = x*b + e

Das erste Argument von ols ist, ydass wir dafür den String transponieren sund mit der Zahl 0 addieren, um seinen ASCII-Code zu erhalten.

rahnema1
quelle
/, großartige Idee!
Luis Mendo
6

TI-Basic, 51 (+ 141) Bytes

Strings sind in TI-Basic 1-basiert.

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)

Wie im anderen Beispiel wird hiermit die Gleichung der Best-Fit-Linie in Bezug auf X ausgegeben. Außerdem muss in Str2 diese Zeichenfolge vorhanden sein, die in TI-Basic 141 Byte beträgt:

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

Der Grund, warum dies nicht Teil des Programms sein kann, ist, dass zwei Zeichen in TI-Basic nicht automatisch zu einer Zeichenfolge hinzugefügt werden können. Einer ist der STO->Pfeil, aber dies ist kein Problem, da er nicht Teil von ASCII ist. Das andere ist das Zeichenfolgenliteral ( "), das nur durch Eingeben Y=und Verwenden einer Gleichung angegeben werden kann Equ>String(.

Timtech
quelle
Ich habe mich ernsthaft gefragt, ob jemand seine alten Taschenrechner dafür rausschmeißen würde :). Ich dachte an meinen alten TI-83, als ich mir das überlegte.
Magic Octopus Urn
@carusocomputing Hey, schön! Ich mag die Programmiersprache TI-Basic sehr und benutze sie für viele meiner Code-Golfs. Wenn es nur ASCII unterstützt ...
Timtech
Zwei Kommentare: 1, Sie können die Zeichenfolge festlegen, "indem Sie sie auch als Benutzereingabe in einem Programm eingeben. Dies hilft Ihnen hier nicht weiter, aber ich wollte nur darauf hinweisen. 2, ich erkenne einige dieser Zeichen nicht als auf dem Taschenrechner vorhanden. Ich könnte mich irren, aber woher bekommst du zum Beispiel @und ~? Sowie #, $und &.
Patrick Roberts
Danke für den Kommentar, @PatrickRoberts. Dies sind Zwei-Byte-Token, die mit 0xBB beginnen. Schauen Sie in Spalte D von tibasicdev.wikidot.com/miscellaneous-tokens
Timtech
6

R 46 45 Bytes

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

Liest die Eingabe von stdin und gibt für den angegebenen Testfall Folgendes zurück (einsindiziert):

(Intercept)           x 
99.25161290  0.01451613 
Billywob
quelle
Etwas kürzer (aber ungetestet, möglicherweise einige Bewertungsprobleme beim Parsen der Formel):lm(utf8ToInt(y<-scan(,""))~1:nchar(y))$co
rturnbull
@rturnbull Ich habe es zuerst versucht, aber es scheint, dass die xVariable vordefiniert sein muss, damit lmsie funktioniert.
Billywob
@rturnbull Ich bekomme einen variablen Längenunterschiedsfehler dazu. Wir bekommen salso ein x=1:nchar(s);lm(charToRaw(s)~x)$copaar Bytes gespart. Ich weiß auch nicht, ob das $cotechnisch notwendig ist, da Sie immer noch den Achsenabschnitt + Koeffizienten ohne ihn erhalten
Chris
@ Chris Ziemlich sicher, dass das keine brauchbare Antwort ist. Es sollte eine Eingabe von stdin oder als Funktionsargument geben.
Billywob
Fair genug, nur meine Lektüre der Frage - es gibt auch einen faireren Vergleich zu den Antworten auf Python + Oktave
Chris
5

Python, 82 bis 80 Bytes

-2 Bytes dank @Mego

Verwenden von scipy:

import scipy
lambda s:scipy.stats.linregress(range(len(s)),list(map(ord,s)))[:2]
dfernan
quelle
Unbenannte Lambdas sind erlaubt, so dass Sie die fallen lassen können f=.
Mego
@DigitalTrauma numpy.linalg.lstsqunterscheidet sich anscheinend in Argumenten scipy.stats.linregressund ist komplexer.
dfernan
4

Mathematica, 31 Bytes

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

Unbenannte Funktion, die eine Zeichenfolge als Eingabe verwendet und die tatsächliche Gleichung der betreffenden Best-Fit-Linie zurückgibt. Zum Beispiel f=Fit[ToCharacterCode@#,{1,x},x]&; f["meta.codegolf.stackexchange.com"]kehrt zurück 99.2516 + 0.0145161 x.

ToCharacterCodekonvertiert eine ASCII-Zeichenfolge in eine Liste der entsprechenden ASCII-Werte; In der Tat ist UTF-8 der Standard. (In diesem Zusammenhang ist es ein bisschen traurig, dass ein Funktionsname mehr als 48% der Codelänge ausmacht ....) Und Fit[...,{1,x},x]ist die integrierte Funktion zur Berechnung der linearen Regression.

Greg Martin
quelle
1
Danke für das Beispiel der 1-indizierten Zeile, musste es nicht wegen dir berechnen haha.
Magic Octopus Urn
4

Node.js, 84 Bytes

Verwenden von regression:

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

Demo

// 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
quelle
3

Salbei, 76 Bytes

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

Kaum ein Golfspiel, wahrscheinlich länger als eine Python-Antwort, aber ja ...

busukxuan
quelle
2

J , 11 Bytes

3&u:%.1,.#\

Dies verwendet eine einseitige Indizierung.

Probieren Sie es online!

Erläuterung

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
Meilen
quelle
2

JavaScript, 151.148 Bytes

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

Besser lesbar:

Markus Jarderot
quelle
Sie können ein Byte speichern, indem Sie 0aus entfernen c.charCodeAt(0), und weitere 2 Bytes, indem Sie die k=...Kommagruppe verschieben und sie direkt in den ersten Index des zurückgegebenen Arrays einfügen, z. B.[k=...,(d-k*b)/a]
Patrick Roberts
2

Javascript (ES6), 112 Bytes

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
quelle
2

Haskell, 154 142 Bytes

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

Es ist viel zu lang für meinen Geschmack wegen der Importe und langen Funktionsnamen, aber gut. Ich konnte mir keine andere Golfmethode vorstellen, obwohl ich kein Experte auf dem Gebiet der Golfimporte bin.

12 Bytes entfernt durch Ersetzen ordund den Import von Data.Charvon Enum dank Nimi.

Renzeee
quelle
1
Sie können ersetzen ordmit fromEnumund loszuwerden import Data.Char.
nimi
1

SAS-Makrosprache, 180 Byte

Verwendet 1-basierte Indizierung. Die Lösung wird ziemlich wortreich, wenn es sich bei der Ausgabe nur um die Steigung und den Achsenabschnitt handelt.

%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
quelle
1

Clojure, 160 Bytes

Keine integrierten Funktionen, verwendet den im Artikel von Perceptron beschriebenen iterativen Algorithmus . Konvergieren Sie 2e-4möglicherweise nicht mit anderen Eingaben. Verringern Sie in diesem Fall die Lernrate und erhöhen Sie möglicherweise die Iterationszahl 1e5. Ich bin nicht sicher, ob die Implementierung des nicht-iterativen Algorithmus kürzer gewesen wäre.

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

Beispiel:

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

[99.26612903225386 0.014516129032464659]
NikoNyrh
quelle
1

Ahorn, 65 Bytes

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

Verwendung:

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

Kehrt zurück:

99.2516129032259+0.0145161290322573*x

Hinweise: Diese verwendet das Fit - Befehl ein Polynom der Form a * x + b auf die Daten passen. Die ASCII-Werte für den String werden durch Konvertieren in Bytes ermittelt.

DSkoog
quelle