Линейная регрессия на строке


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
У вас есть какая-нибудь ссылка / формула для расчета наклона и y-точки?
Род

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

Строки основаны на 1 в 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

Читает входные данные из стандартного ввода и возвращает для данного тестового примера (с одним индексом):

(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, технически ли это необходимо, поскольку вы все еще получаете коэффициент перехвата + без него
Крис

@ Крис Я уверен, что это нереальный ответ. Должен быть какой-то ввод из stdin или в качестве аргумента функции.
Billywob

Достаточно справедливо, только мое чтение вопроса - это дает более справедливое сравнение с ответами на python + octave
Крис

5

Python, 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и является более сложным.
17

4

Mathematica, 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; действительно, по умолчанию используется UTF-8 в более общем смысле. (Довольно печально, в этом контексте, что одно имя функции составляет более 48% длины кода ....) И Fit[...,{1,x},x]является встроенным для вычисления линейной регрессии.


1
Спасибо за пример 1-индексированной строки, не нужно было ее вычислять из-за вас, ха-ха.
Волшебная Урна Осьминога

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

Sage, 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.CharfromEnum благодаря 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 для строки находятся путем преобразования в байты.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.