Hồi quy tuyến tính trên một chuỗi


25

Thử thách này hơi khó, nhưng khá đơn giản, được đưa ra một chuỗi s:

meta.codegolf.stackexchange.com

Sử dụng vị trí của ký tự trong chuỗi làm xtọa độ và giá trị ascii làm ytọa độ. Đối với chuỗi trên, tập hợp tọa độ tổng hợp sẽ là:

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

Tiếp theo, bạn phải tính toán cả độ dốc và độ chặn y của tập hợp bạn đã thu được bằng cách sử dụng hồi quy tuyến tính , đây là tập hợp được vẽ ở trên:

Âm mưu

Kết quả nào phù hợp nhất với dòng (0-index):

y = 0.014516129032258x + 99.266129032258

Đây là dòng phù hợp nhất 1 chỉ mục :

y = 0.014516129032258x + 99.251612903226

Vì vậy, chương trình của bạn sẽ trở lại:

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

Hoặc (Bất kỳ định dạng hợp lý nào khác):

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

Hoặc (Bất kỳ định dạng hợp lý nào khác):

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

Hoặc (Bất kỳ định dạng hợp lý nào khác):

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

Chỉ cần giải thích lý do tại sao nó trở lại ở định dạng đó nếu nó không rõ ràng.


Một số quy tắc làm rõ:

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

Đây là chiến thắng đếm byte thấp nhất trong .


3
Bạn có bất kỳ liên kết / công thức để tính độ dốc và chặn y không?
Rod

16
Kính gửi các cử tri không rõ ràng: Mặc dù tôi đồng ý rằng thật tuyệt khi có công thức, nhưng không có nghĩa là cần thiết. Hồi quy tuyến tính là một điều được xác định rõ trong thế giới toán học và OP có thể muốn rời khỏi việc tìm phương trình cho người đọc.
Nathan Merrill


2
Có thể trả lại phương trình thực tế của dòng phù hợp nhất, chẳng hạn như 0.014516129032258x + 99.266129032258?
Greg Martin

2
Tiêu đề của thử thách này đã đưa bài hát tuyệt vời này vào đầu tôi trong phần còn lại của ngày
Luis Mendo

Câu trả lời:


2

MATL , 8 byte

n:G3$1ZQ

Lập chỉ mục chuỗi dựa trên 1 được sử dụng.

Hãy thử trực tuyến!

Giải trình

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

Octave, 29 26 24 20 byte

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

Hãy thử trực tuyến!

Chúng tôi có mô hình

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

Đây ylà giá trị ASCII của chuỗis

Để tìm tham số chặn và độ dốc, chúng ta có thể tạo phương trình sau:

s = [intercept slope] * [1 X]

vì thế

[intercept slope] = s/[1 x]

!!schuyển đổi một chuỗi thành một vectơ của những chuỗi có cùng độ dài với chuỗi.
Vectơ của những cái được sử dụng để ước tính đánh chặn.
1:nnz(s)là phạm vi của các giá trị từ 1 đến số phần tử của chuỗi được sử dụng như x.

Câu trả lời trước

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

Để kiểm tra, dán đoạn mã sau vào Octave Online

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

Hàm chấp nhận một chuỗi làm đầu vào và áp dụng ước lượng bình phương nhỏ nhất của mô hình y = x*b + e

Đối số đầu tiên của ols là yđối với nó, chúng ta hoán vị chuỗi svà thêm số 0 để lấy mã ASCII.


/, ý tưởng tuyệt vời!
Luis Mendo

6

TI-Basic, 51 (+ 141) byte

Chuỗi là 1 dựa trên 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)

Giống như ví dụ khác, điều này đưa ra phương trình của dòng phù hợp nhất, theo X. Ngoài ra, trong Str2, bạn cần phải có chuỗi này, là 141 byte trong TI-Basic:

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

Lý do đây không thể là một phần của chương trình là vì hai ký tự trong TI-Basic không thể tự động được thêm vào chuỗi. Một là STO->mũi tên, nhưng đây không phải là vấn đề vì nó không phải là một phần của ASCII. Cái còn lại là chuỗi ký tự ( "), chỉ có thể được xâu chuỗi bằng cách nhập vào một Y=phương trình và sử dụng Equ>String(.


Tôi đã thực sự tự hỏi liệu có ai sẽ phá vỡ các máy tính cũ của họ cho việc này không :). Tôi đã nghĩ đến TI-83 cũ khi nghĩ đến điều này.
Bạch tuộc ma thuật Urn

@carusocomputing Này, tốt quá! Tôi thích ngôn ngữ lập trình TI-Basic rất nhiều và tôi sử dụng nó cho nhiều môn đánh gôn. Nếu chỉ có nó hỗ trợ ASCII ...
Timtech

Hai bình luận: 1, bạn có thể xâu chuỗi "bằng cách nhắc nó là đầu vào của người dùng trong một chương trình, điều này không giúp ích gì cho bạn ở đây, nhưng tôi chỉ muốn chỉ ra thực tế đó. 2, Tôi không nhận ra một số ký tự đó tồn tại trên máy tính. Tôi có thể sai, nhưng ví dụ, bạn nhận được ở đâu @~? Cũng như #, $, và &.
Patrick Roberts

Cảm ơn vì nhận xét, @PatrickRoberts. Đó là các mã thông báo hai byte bắt đầu bằng 0xBB. Tìm trong Cột D của tibasicdev.wikidot.com/misiverse-tokens
Timtech

6

R, 46 45 byte

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

Đọc đầu vào từ stdin và cho trường hợp kiểm tra trả về đã trả về (một chỉ mục):

(Intercept)           x 
99.25161290  0.01451613 

Hơi ngắn hơn một chút (nhưng chưa được kiểm tra, có thể là một số vấn đề đánh giá khi phân tích công thức):lm(utf8ToInt(y<-scan(,""))~1:nchar(y))$co
rturnbull

@rturnbull Tôi đã thử điều này lúc đầu nhưng có vẻ như xbiến phải được xác định trước lmđể hoạt động.
Billywob

@rturnbull Tôi nhận được một lỗi độ dài khác nhau về điều đó. Chúng tôi được cung cấp sđể x=1:nchar(s);lm(charToRaw(s)~x)$cotiết kiệm một số byte. Tôi cũng không biết có $cocần thiết về mặt kỹ thuật không, vì bạn vẫn có được hệ số chặn + mà không có nó
Chris

@Chris Khá chắc chắn rằng đó không phải là một câu trả lời khả thi. Cần có một số đầu vào từ stdin hoặc như là một đối số chức năng.
Billywob

Đủ công bằng, chỉ cần tôi đọc câu hỏi - nó cũng cho một so sánh công bằng hơn với câu trả lời của con trăn + quãng tám
Chris

5

Python, 82 80 byte

-2 byte nhờ @Mego

Sử dụng scipy:

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

Lambdas không tên được cho phép, vì vậy bạn có thể thả f=.
Mego

@DigitalTrauma numpy.linalg.lstsqrõ ràng khác nhau trong các đối số scipy.stats.linregressvà phức tạp hơn.
dfer Nam

4

Toán học, 31 byte

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

Hàm không tên lấy một chuỗi làm đầu vào và trả về phương trình thực tế của dòng phù hợp nhất trong câu hỏi. Ví dụ, f=Fit[ToCharacterCode@#,{1,x},x]&; f["meta.codegolf.stackexchange.com"]trả về 99.2516 + 0.0145161 x.

ToCharacterCodechuyển đổi một chuỗi ASCII thành một danh sách các giá trị ASCII tương ứng; thực tế, nó mặc định là UTF-8 nói chung. (Thật đáng buồn, trong bối cảnh này, một tên hàm bao gồm hơn 48% độ dài mã ....) Và Fit[...,{1,x},x]được tích hợp để tính toán hồi quy tuyến tính.


1
Cảm ơn ví dụ về dòng 1 chỉ mục, đã không phải tính toán nó vì bạn haha.
Bạch tuộc ma thuật Urn

4

Node.js, 84 byte

Sử dụng regression:

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

Bản giới thiệu

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

Hầu như không chơi golf, có lẽ dài hơn câu trả lời của Python, nhưng vâng ...


2

J , 11 byte

3&u:%.1,.#\

Điều này sử dụng lập chỉ mục một dựa trên.

Hãy thử trực tuyến!

Giải trình

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

Dễ đọc hơn:


Bạn có thể lưu một byte bằng cách xóa 0khỏi c.charCodeAt(0)và 2 byte khác bằng cách di chuyển k=...nhóm dấu phẩy và đặt nó trực tiếp vào chỉ mục đầu tiên của mảng được trả về như[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

Nó là quá dài cho sở thích của tôi vì nhập khẩu và tên hàm dài, nhưng tốt. Tôi không thể nghĩ ra bất kỳ phương pháp chơi gôn nào còn lại, mặc dù tôi không phải là chuyên gia về lĩnh vực nhập khẩu golf.

Tước 12 byte bằng cách thay thế ordvà nhập Data.Charbởi fromEnum nhờ vào nimi.


1
Bạn có thể thay thế ordvới fromEnumvà thoát khỏi import Data.Char.
nimi

1

Ngôn ngữ Macro SAS, 180 byte

Sử dụng lập chỉ mục dựa trên 1. Giải pháp trở nên khá dài dòng khi đầu ra chỉ là độ dốc và đánh chặn.

%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

Không tích hợp sẵn, sử dụng thuật toán lặp được mô tả tại bài viết Perceptron . Có thể không hội tụ vào các đầu vào khác, trong trường hợp đó làm giảm tốc độ học tập 2e-4và có thể tăng số lần lặp 1e5. Không chắc chắn nếu thuật toán không lặp sẽ được thực hiện ngắn hơn.

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

Thí dụ:

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

[99.26612903225386 0.014516129032464659]

1

Maple, 65 byte

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

Sử dụng:

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

Trả về:

99.2516129032259+0.0145161290322573*x

Lưu ý: Điều này sử dụng lệnh Fit để khớp một đa thức có dạng a * x + b với dữ liệu. Các giá trị ASCII cho chuỗi được tìm thấy bằng cách chuyển đổi ing thành byte.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.