Лінійна регресія на струні


25

Це завдання є дещо складним, але досить простим, з огляду на рядок s:

meta.codegolf.stackexchange.com

Використовуйте положення символу в рядку як xкоординату, а значення ascii - як yкоординату. Для наведеного рядка результуючим набором координат буде:

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

Далі слід обчислити як нахил, так і y-перехоплення набору, який ви отримали за допомогою лінійної регресії , ось наведений вище набір:

Сюжет

У результаті чого найкраще підходить рядок (0-індексований):

y = 0.014516129032258x + 99.266129032258

Ось 1-індексований рядок найкращого підходу:

y = 0.014516129032258x + 99.251612903226

Отже, ваша програма повернеться:

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

Або (будь-який інший розумний формат):

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

Або (будь-який інший розумний формат):

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

Або (будь-який інший розумний формат):

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

Просто поясніть, чому він повертається в такому форматі, якщо це не очевидно.


Деякі уточнюючі правила:

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

Це найнижчою кількістю виграшів.


3
Чи є у вас посилання / формула для обчислення нахилу та перехрестя?
Прут

16
Шановні незрозумілі виборці: Хоча я згоден, що приємно мати формулу, це ні в якому разі не потрібно. Лінійна регресія - це добре визначена річ у математичному світі, і ОП може захотіти залишити пошук рівняння читачеві.
Натан Меррілл


2
Чи добре повернути фактичне рівняння найкращої лінії, наприклад 0.014516129032258x + 99.266129032258?
Грег Мартін

2
Назва цього виклику поклала цю чудову пісню в мою голову на весь день
Луїс Мендо

Відповіді:


2

MATL , 8 байт

n:G3$1ZQ

Використовується індексація рядків на основі 1.

Спробуйте в Інтернеті!

Пояснення

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

Октава, 29 26 24 20 байт

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

Спробуйте в Інтернеті!

У нас є модель

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

Ось yзначення ASCII рядкаs

Щоб знайти параметри перехоплення та нахилу, ми можемо сформувати таке рівняння:

s = [intercept slope] * [1 X]

так

[intercept slope] = s/[1 x]

!!sперетворює рядок у вектор одиниць такої ж довжини, що і рядок.
Вектор одиниць використовується для оцінки перехоплення.
1:nnz(s)- діапазон значень від 1 до кількості елементів рядка, використовуваних як x.

Попередня відповідь

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

Для тестування вставте наступний код в Octave Online

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

Функція, яка приймає рядок як вхідний і застосовує звичайну оцінку найменших квадратів моделі y = x*b + e

Перший аргумент ols полягає в yтому, що для нього ми транспонируем рядок sі додаємо цифрою 0, щоб отримати його ASCII код.


/, чудова ідея!
Луїс Мендо

6

TI-Basic, 51 (+ 141) байт

Струни базуються на 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)

Як і в іншому прикладі, це виводить рівняння найкращої лінії, що відповідає розміру, з точки зору X. Також у Str2 потрібно мати цей рядок, який становить 141 байт у TI-Basic:

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

Причина, по якій це не може бути частиною програми, полягає в тому, що два символи TI-Basic не можуть бути автоматично додані до рядка. Один - це STO->стрілка, але це не проблема, оскільки вона не є частиною ASCII. Інший - це літеральний рядок ( "), який можна підкреслити лише введенням Y=рівняння та використанням Equ>String(.


Мені серйозно було цікаво, чи хтось вирве за це свої старі калькулятори :). Я мав на увазі свій старий TI-83, коли я придумав це.
Чарівний восьминога Урна

@carusocomputing Ей, приємно! Мені дуже подобається мова програмування TI-Basic, і я використовую її для багатьох гольфів з кодом. Якби він підтримував ASCII ...
Timtech

Два коментарі: 1, ви можете впорядкувати ", запропонувавши це як введення користувача в програму, що вам тут не допоможе, але я просто хотів зазначити цей факт. 2, я не визнаю деякі з цих символів як наявні на калькуляторі. Я можу помилитися, але, наприклад, де ти береш @і ~? Так само як #, $і &.
Патрік Робертс

Дякуємо за коментар, @PatrickRoberts. Це двобайтові жетони, що починаються з 0xBB. Подивіться у стовпчик D від tibasicdev.wikidot.com/miscellaneous-tokens
Timtech

6

R, 46 45 байт

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

Читає дані від stdin і для даного тестового випадку повертає (одноіндексований):

(Intercept)           x 
99.25161290  0.01451613 

Трохи коротший (але неперевірений, можливо, деякі проблеми з оцінкою при аналізі формули):lm(utf8ToInt(y<-scan(,""))~1:nchar(y))$co
rturnbull

@rturnbull Я спробував це спочатку, але здається, що xзмінна повинна бути заздалегідь визначена для lmроботи.
Billywob

@rturnbull Я отримую змінну довжину, що відрізняється помилкою на цьому. Нам дано sтак x=1:nchar(s);lm(charToRaw(s)~x)$coекономить кілька байт. Я також не знаю, чи $coтехнічно це потрібно, так як ви все одно отримаєте без нього перехоплення + коефіцієнт
Кріс

@Chris Досить впевнений, що це не відповідна відповідь. Має бути якийсь вхід із stdin або як аргумент функції.
Billywob

Досить справедливо, лише моє прочитання питання - воно дає більш справедливе порівняння з відповідями також пітона + октави
Кріс

5

Пітон, 82 80 байт

-2 байти завдяки @Mego

Використання scipy:

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

Безіменні лямбдахи дозволені, тому ви можете кинути їх f=.
Мего

@DigitalTrauma, numpy.linalg.lstsqмабуть, відрізняється аргументами scipy.stats.linregressта є більш складним.
dfernan

4

Математика, 31 байт

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

Безіменна функція, що приймає рядок як вхідний і повертає фактичне рівняння найкращого відповідного рядка. Наприклад, f=Fit[ToCharacterCode@#,{1,x},x]&; f["meta.codegolf.stackexchange.com"]повертає 99.2516 + 0.0145161 x.

ToCharacterCodeперетворює рядок ASCII у список відповідних значень ASCII; Дійсно, це UFF-8 більш за замовчуванням. (Як не сумно, в цьому контексті, що одна назва функції містить понад 48% довжини коду ....) І Fit[...,{1,x},x]є вбудованою для обчислення лінійної регресії.


1
Дякуємо за приклад 1-індексованого рядка, не потрібно було його обчислювати через те, що ти ха-ха.
Magic Octopus Urn

4

Node.js, 84 байти

Використання regression:

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

Демо

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

Шавлія, 76 байт

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

Навряд чи будь-який гольф, мабуть, довший, ніж відповідь на гольф Python, але так ...


2

J , 11 байт

3&u:%.1,.#\

Для цього використовується одноосновна індексація.

Спробуйте в Інтернеті!

Пояснення

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 байт

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

Більше читати:


Ви можете зберегти байт, видаливши 0з c.charCodeAt(0)та ще 2 байти, перемістивши k=...групу комами та ввівши її безпосередньо в перший індекс повернутого масиву, наприклад[k=...,(d-k*b)/a]
Патрік Робертс

2

Javascript (ES6), 112 байт

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 байти

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

Дуже довго мені не подобається через імпорт та довгі назви функцій, але добре. Я не міг придумати жодного іншого способу гольфу, хоча я не знаю в галузі імпорту гольфу.

Зняли 12 байт шляхом заміни ordта імпорту Data.Charна відEnum завдяки nimi.


1
Ви можете замінити ordз fromEnumі позбутися import Data.Char.
німі

1

Мова макросів SAS, 180 байт

Використовує індексацію на основі 1. Рішення стає досить багатослівним, коли вихід є лише нахилом та перехопленням.

%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 байт

Не вбудовані, використовує ітеративний алгоритм, описаний у статті Perceptron . Можливо, не збігатися з іншими вхідними даними, у цьому випадку знизити рівень навчання 2e-4і, можливо, збільшити кількість ітерацій 1e5. Не впевнений, чи не ітераційний алгоритм був би коротшим за реалізацію.

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

Приклад:

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

[99.26612903225386 0.014516129032464659]

1

Клен, 65 байт

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

Використання:

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

Повернення:

99.2516129032259+0.0145161290322573*x

Примітки. Для цього використовується команда Fit для встановлення полінома форми a * x + b до даних. Значення ASCII для рядка знаходять шляхом перетворення ing в байти.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.