Regressione lineare su una stringa


25

Questa sfida è un po 'complicata, ma piuttosto semplice, data una stringa s:

meta.codegolf.stackexchange.com

Utilizzare la posizione del carattere nella stringa come xcoordinata e il valore ASCII come ycoordinata. Per la stringa sopra, l'insieme risultante di coordinate sarebbe:

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

Successivamente, devi calcolare sia la pendenza che l'intercetta y dell'insieme che hai ottenuto usando la regressione lineare , ecco l'insieme sopra tracciato:

Tracciare

Il che si traduce in una linea di adattamento ottimale di (indicizzata 0):

y = 0.014516129032258x + 99.266129032258

Ecco la linea più adatta 1 indicizzata :

y = 0.014516129032258x + 99.251612903226

Quindi il tuo programma ritornerebbe:

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

Oppure (qualsiasi altro formato sensibile):

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

Oppure (qualsiasi altro formato sensibile):

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

Oppure (qualsiasi altro formato sensibile):

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

Spiega semplicemente perché sta tornando in quel formato se non è ovvio.


Alcune regole di chiarimento:

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

Si tratta delle vittorie con il numero di byte più basso di .


3
Hai qualche link / formula per calcolare la pendenza e l'intercetta y?
Rod

16
Cari elettori poco chiari: anche se concordo sul fatto che è bello avere la formula, non è assolutamente necessario. La regressione lineare è una cosa ben definita nel mondo matematico e l'OP potrebbe voler lasciare la ricerca dell'equazione al lettore.
Nathan Merrill,


2
Va bene restituire l'equazione effettiva della linea più adatta, come 0.014516129032258x + 99.266129032258?
Greg Martin,

2
Il titolo di questa sfida mi ha messo in testa questa meravigliosa canzone per il resto della giornata
Luis Mendo,

Risposte:


2

MATL , 8 byte

n:G3$1ZQ

Viene utilizzata l'indicizzazione di stringa basata su 1.

Provalo online!

Spiegazione

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

7

Ottava, 29 26 24 20 byte

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

Provalo online!

Abbiamo il modello

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

Ecco yil valore ASCII della stringas

Per trovare i parametri intercetta e inclinazione possiamo formare la seguente equazione:

s = [intercept slope] * [1 X]

così

[intercept slope] = s/[1 x]

!!sconverte una stringa in un vettore di quelli con la stessa lunghezza della stringa.
Il vettore di quelli viene utilizzato per la stima dell'intercetta.
1:nnz(s)è un intervallo di valori compreso tra 1 e il numero di elementi della stringa utilizzata come x.

Risposta precedente

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

Per il test incollare il seguente codice in Octave Online

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

Una funzione che accetta una stringa come input e applica la stima ordinaria dei minimi quadrati del modello y = x*b + e

Il primo argomento di ols è yche per esso trasponiamo la stringa se aggiungiamo con il numero 0 per ottenere il suo codice ASCII.


/, grande idea!
Luis Mendo,

6

TI-Basic, 51 (+ 141) byte

Le stringhe sono basate su 1 in 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)

Come l'altro esempio, questo genera l'equazione della linea più adatta, in termini di X. Inoltre, in Str2 devi avere questa stringa, che è 141 byte in TI-Basic:

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

Il motivo per cui questo non può far parte del programma è perché due caratteri in TI-Basic non possono essere aggiunti automaticamente a una stringa. Uno è la STO->freccia, ma questo non è un problema perché non fa parte di ASCII. L'altra è la stringa letterale ( "), che può essere limitata solo digitando Y=un'equazione e usando Equ>String(.


Mi chiedevo seriamente se qualcuno avrebbe eliminato i loro vecchi calcolatori per questo :). Avevo in mente la mia vecchia TI-83 quando ho pensato a questo.
Magic Octopus Urn

@carusocomputing Ehi, bello! Mi piace molto il linguaggio di programmazione TI-Basic e lo uso per molti dei miei golf di codice. Se solo supportasse ASCII ...
Timtech,

Due commenti: 1, puoi precisare "richiedendolo anche come input dell'utente in un programma, il che non ti aiuta qui, ma volevo solo sottolineare questo fatto. 2, non riconosco alcuni di quei personaggi come esistenti sulla calcolatrice. Potrei sbagliarmi, ma per esempio, dove prendi @e ~? Così come #, $e &.
Patrick Roberts,

Grazie per il commento, @PatrickRoberts. Questi sono token a due byte che iniziano con 0xBB. Guarda nella colonna D di tibasicdev.wikidot.com/miscellaneous-tokens
Timtech,

6

R, 46 45 byte

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

Legge l'input da stdin e per i ritorni del test case indicati (uno indicizzato):

(Intercept)           x 
99.25161290  0.01451613 

Leggermente più breve (ma non testato, forse alcuni problemi di valutazione lm(utf8ToInt(y<-scan(,""))~1:nchar(y))$co
nell'analisi

@rturnbull All'inizio ho provato questo, ma sembra che la xvariabile debba essere predefinita per lmfunzionare.
Billywob,

@rturnbull Ottengo un errore di lunghezza variabile diverso. Ci viene dato in smodo da x=1:nchar(s);lm(charToRaw(s)~x)$corisparmiare alcuni byte. Inoltre non so se $cosia tecnicamente necessario, dato che ottieni ancora il coefficiente intercetta + senza di esso
Chris

@Chris Abbastanza sicuro che non sia una risposta praticabile. Ci dovrebbe essere qualche input da stdin o come argomento di funzione.
Billywob,

Abbastanza giusto, solo la mia lettura della domanda - offre un confronto più equo anche con le risposte di pitone + ottava
Chris

5

Python, 82 80 byte

-2 byte grazie a @Mego

Utilizzando scipy:

import scipy
lambda s:scipy.stats.linregress(range(len(s)),list(map(ord,s)))[:2]

Sono consentiti lambda senza nome, quindi è possibile eliminare f=.
Mego

@DigitalTrauma numpy.linalg.lstsqapparentemente differisce negli argomenti scipy.stats.linregressed è più complesso.
Dfernan,

4

Mathematica, 31 byte

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

Funzione senza nome che accetta una stringa come input e restituisce l'equazione effettiva della riga più adatta in questione. Ad esempio, f=Fit[ToCharacterCode@#,{1,x},x]&; f["meta.codegolf.stackexchange.com"]restituisce 99.2516 + 0.0145161 x.

ToCharacterCodeconverte una stringa ASCII in un elenco dei corrispondenti valori ASCII; in effetti, per impostazione predefinita è UTF-8 più in generale. (Kinda triste, in questo contesto, che un nome di funzione comprende oltre il 48% della lunghezza del codice ....) Ed Fit[...,{1,x},x]è integrato per il calcolo della regressione lineare.


1
Grazie per l'esempio della linea 1-indicizzata, non è stato necessario calcolarla a causa tua haha.
Magic Octopus Urn

4

Node.js, 84 byte

Utilizzando regression:

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

dimostrazione

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


3

Sage, 76 byte

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

Quasi nessun golf, probabilmente più lungo di una risposta Python golf, ma sì ...


2

J , 11 byte

3&u:%.1,.#\

Questo utilizza l'indicizzazione su una base.

Provalo online!

Spiegazione

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

2

JavaScript, 151 148 byte

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

Più leggibile:


È possibile salvare un byte rimuovendo 0da c.charCodeAt(0)e altri 2 byte spostando il k=...gruppo virgola e inserendolo direttamente nel primo indice dell'array restituito come[k=...,(d-k*b)/a]
Patrick Roberts

2

Javascript (ES6), 112 byte

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>


2

Haskell, 154 142 byte

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

È troppo lungo per i miei gusti a causa delle importazioni e dei nomi di funzioni lunghe, ma bene. Non riuscivo a pensare a nessun altro metodo di golf rimasto, anche se non sono esperto nel campo delle importazioni di golf.

Spogliato di 12 byte sostituendo orde importando Data.Charda fromEnum grazie a nimi.


1
È possibile sostituire ordcon fromEnume sbarazzarsi di import Data.Char.
nimi,

1

SAS Macro Language, 180 byte

Utilizza l'indicizzazione basata su 1. La soluzione diventa piuttosto prolissa quando l'output è solo la pendenza e l'intercettazione.

%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;

1

Clojure, 160 byte

Nessun built-in, utilizza l'algoritmo iterativo descritto nell'articolo di Perceptron . Potrebbe non convergere su altri input, in tal caso abbassare il tasso di apprendimento 2e-4e forse aumentare il conteggio delle iterazioni 1e5. Non sono sicuro se l'algoritmo non iterativo sarebbe stato più breve da implementare.

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

Esempio:

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

[99.26612903225386 0.014516129032464659]

1

Acero, 65 byte

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

Uso:

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

Ritorna:

99.2516129032259+0.0145161290322573*x

Note: utilizza il comando Adatta per adattare un polinomio del modulo a * x + b ai dati. I valori ASCII per la stringa vengono rilevati convertendoli in byte.

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.