Давайте судимо про деякі книги за їх обкладинками


47

Всім відомо, що зміст ставить питання. Але хороший заголовок теж допомагає, і це перше, що ми бачимо. Настав час перетворити це перше враження на програму і з'ясувати, які типи заголовків отримують більше відгуків.

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

Наприклад, ви можете отримати Counting Grains of Riceвведення, і 59в цьому випадку ви намагаєтесь повернути щось близьке до оцінки . Нецілі здогадки - це нормально, але здогади в і нижче -20- ні.

Ось дані для тестування та оцінки:

http://data.stackexchange.com/codegolf/query/244871/names-and-upvotes

Оцінка балів: Ваша програма працюватиме з кожним питанням в історії цього сайту (PPCG), не враховуючи закритих питань. Функція ln(score + 20)буде застосована до кожної оцінки та до кожної здогадки. Помилка кореня середнього та середнього квадрата між двома результуючими наборами значень - це ваша оцінка. Нижній краще.

Наприклад, програма, яка щоразу здогадувалась 0, набирала б 0,577, тоді як програма, яка здогадувалась 11, набирала 0,362.

Будь ласка, обчисліть свій бал і включіть його в заголовок вашої відповіді. Будь ласка, включіть передбачення вашої програми щодо кількості отриманих результатів цього питання.

Обмеження:

  • Щоб запобігти надмірному жорсткому кодуванню, не більше 1000 символів.

  • Потрібно виконати весь набір даних вище, ніж протягом хвилини на розумній машині.

  • Стандартні лазівки закриті.


Ось тестер, написаний на Python, для вашого використання та / або для усунення неясностей:

import sys
import math
import csv

scores_dict = {}

with open(sys.argv[1], 'r') as csv_file:
    score_reader = csv.reader(csv_file)
    for score, title in score_reader:
        if score == 'Score':
            continue
        scores_dict[title] = int(score)

def rate_guesses(guesser):
    def transform(score):
        return math.log(score + 20) if score > -20 else 0
    off_by_total = 0
    lines_count = 0
    for title in scores_dict:
        guessed_score = guesser(title)
        real_score = scores_dict[title]
        off_by_total += (transform(real_score) - transform(guessed_score)) ** 2
    return (off_by_total/len(scores_dict)) ** .5

def constant11(title):
    return 11

print(rate_guesses(constant11))

19
Хороша ідея, але прикро, що набір даних не стабільний, тому результати через деякий час стануть недійсними. Існує також незначна можливість стратегічного голосування: на кожного, хто відповість на це запитання та отримав значок Vox-populi за той же тиждень, слід дивитися з підозрою! ;-)
Рівень Рівер Св.

1
Чи буде в заголовку включені чи виключені такі речі, як [closed]і [on hold], де це застосовно?
es1024

4
@steveverrill Добре, що з часом прогресує, ми зможемо побачити, чи добре працюють програми на майбутніх посадах, а також на минулих.
isaacg

6
Перемогти важко кодування важко. Кожне чітко зафіксоване запитання, яке має найвищий голос, може знизити на 0,4 балів. І, мабуть, не так часто зустрічається схема, ха-ха. Я прогнозую, що відповіді будуть просто конкурувати за те, як вмістити стільки жорстко закодованих результатів в 1000 байт.
justhalf

5
Ви не повинні використовувати повний комплекс питань як тестовий набір. Вам слід попередньо вибрати певну кількість (10% -20%) навмання та визначити їх як свій тестовий набір (але нікому не говорити, що це таке). Набагато простіше скласти алгоритм, який прогнозує минулу історію, ніж той, який має майбутнє прогнозне значення (тобто такий, який добре працює на будь-якому даному підмножині). (Ще краще було б зняти ті 10% із того, що ми можемо бачити взагалі, але це не справді спрацює.)
Джо

Відповіді:


9

Python 2, 991 символів, оцінка 0,221854834221, прогноз 11

import base64
e={}
d=base64.decodestring('vgAcRAEVDAIsqgQYalYaggcjQKwVXAoZWAsYQg0Ckg4VlWEX9hEDRhMe0hckCBkeuhsW3CAWQiEm\nSiMZMiwgTDAZZjIcSLMZfDQDnjwCe2AVaEQCYWEBIEgnDEoXzk0e3lQb5FYVKlkVZlwB+F0XwmI/\nGmRcuGUXWmYdVGkbzmwafG8eaHMdInkggHonRn5sKoMXgIkpbowVOI4cNJAubpQdYpcydJgVypkA\nZpweMp8ZsqEcRKMghKQYkKVPPXEWMqkWHKwbjrEdzLIBNLMf1LQivrYC99UV9rxNRsABNMEiPzob\npc0ActAhn3gcrNUZYNcWYNov/t8VgOEXAuMYqOUWsqUiCPIefPWNbvtKevwWvP0Cl9UsjQMdWwQb\nfQdpJQgWYwkCZRLBjxMWWdkqHRkWNxwB6x8p2SEZyyICSyYcgysaOS0CUy8hezAaGeEVpTRQ3zUz\nZzkZRzohizwwST4c8UAdF0OqG9AXIuEYYRN6208nU1AktVEVJ1IVWeMkIVQXdY4D2VYYD/cYb1om\nG1xA0zoY3uUaRWAhWpBSHWUXQTxGe+cad20CO3AZX3EBw3IiMXcef3gecXsVGXwhw30VbX4W24BD\n6qyQ45YaYYgZ4YobbYwauY4bMY82HZEdO5YmQ5cV35sVxaMbY6gYNas576ws+bADO7QpN7hdLJ8B\n4Eoks8EYX8VU68cYWfcar82QOdAaxdEfQ9UiW/kXL9k2ddwCW90m694enqUCkeEBE+IYWvsfA1FC\nJ+spMVIjhe4WEP0fAfYax/c3MfgbgfkqP/0DLf4V\n')
for i in range(0,600,3):
 e[ord(d[i])*256+ord(d[i+1])]=ord(d[i+2])*2-8
def p(t):
 return e.get(hash(t)%256**2,11)

Пояснення:

Це безсоромне тверде кодування, але намагаються зробити це ефективно.

Попередня обробка:

В окремому коді я хеширував кожну назву зі значенням від 0 до 256 ^ 2-1. Назвемо ці значення бункерами. За кожну кошик я підрахував середній бал. (Середній потрібен, тому що для невеликої частки бункерів виникають зіткнення - більше одного заголовка хешується до того ж біна. Але для переважної більшості кожен заголовок відображає власну скриньку).

Ідея 2-байтового коду для кожного заголовка полягає в тому, що 1 байт недостатньо - у нас надто багато зіткнень, тому ми не знаємо, який бал присвоювати кожному 1-байтовому біну. Але з двобайтовими бінами зіткнень майже немає, і ми фактично отримуємо 2-байтове подання кожного заголовка.

Потім ранжируйте бункери - обчисліть коефіцієнт посилення, якщо ми присвоїмо цьому біну його обчислене значення, а не просто здогадуємось 11. Візьміть верхню N бункерів і зашифруйте їх у рядок (який d є фактичним кодом).

Кодування: ключ кошика кодується як 2 байти. значення кодується за допомогою 1 байта. Я знайшов значення між -8 і 300 + щось, тому довелося трохи стиснути, щоб отримати його в 1 байт: x -> (x + 8) / 2.

Фактичний код:

читати d як трійні байти, розшифровуючи кодування, пояснене вище. Коли дано заголовок, обчисліть його хеш (модуль 256 ^ 2), і якщо цей ключ знайдений у диктаті, поверніть значення, яке воно відображає. В іншому випадку поверніть 11.


3
Пропозиція: Середній бал не так добре. Подивіться на функцію оцінки викликів, вона нелінійна.
Дедуплікатор

1
@Deduplicator Спасибі, я зрозумів, що після того, як я закінчив. Річ у тім, що для 99% бункерів зіткнень немає, тому середній показник - це фактично лише оцінка одного заголовка, який відображається до цього кошика.
Офрі Равів

16

Javascript ES6

Оцінка: 0,245663
Довжина: 1000 байт
Прогнози: 5

(Напевно, питання пов'язане з несподіваною лавиною канатів.: P)

Укорочений

E="ABCDEFGHIJKLMNOPQRSTUVWXYZ";E=E+E.toLowerCase()+"0123456789!@#$%;*()";P="RCRHIFMGPGIDQKHMJLLRMLFJGKHEqHPOgJNKGPCHPJNUPOSGJQKKKMELMIJHLKIKNcKDOfSJLFHDILGKIOUKLMLLKMKIHGHJGIIJDGJKIHIIFIGMTIHFJMIKDJGQJKGMKJHPRJPLMGIOPIIIIPBYFMGLEIKIMMRUKFLFGJFKFTHPFODEQTGTHKIJDHNJGDGiHKNYLHHDLJHGILOEViKNEKGQZfHJMIISIJFRHKLJMLPIFJILKKKJKKJESHNLLIKIGKGJJJHKJRGULLSLRONJNEeLKIQGGPQIHPLEIHHIDXjQHNBKOGWWIENRbYoHINHNMKTNKHTGMIPXFJLLMLIHPPLDJJKFUMIQMOKJLJJKIJKNLHRILJIAIbJEZOGIELGHGLOINDPJMJeJWRIIJHSOZDOsOFRRIOIOTIJSGGJKFUIDOINGOcLQEJFEITLMNIIGIGIMG7LPSNLKVOKIFGHJITGOFUJIIRN";K={};"99r1501vz076mip077myv0733it280exx081gt9118i1g279dyx102uho203ejd07433z087uje097kdg1567ft2088rk275dmu1203ez106lih1763ei126f6q101aax084owh088aid161i9y179gvn236ptn3338vf132i55080fke101l4z3789ai281ulm081blm124euz074o5m07513z14117l095qdn092gl30757n5153".replace(/(...)(...)/g,(_,a,b)=>K[a]=1*b);D=40655;N=479;H=(s,T)=>(h=7,[...s].map(c=>h=~~(h*T+c.charCodeAt(0))),h);S=s=>(y=H(s,31),K[((y%D+D)%D).toString(36)]||E.indexOf(P[(H(s,48)%N+N)%N]));

Розширено

E = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
E = E + E.toLowerCase() + "0123456789!@#$%;*()";
K = {};
P = "RCRHIFMGPGIDQKHMJLLRMLFJGKHEqHPOgJNKGPCHPJNUPOSGJQKKKMELMIJHLKIKNcKDOfSJL" +
    "FHDILGKIOUKLMLLKMKIHGHJGIIJDGJKIHIIFIGMTIHFJMIKDJGQJKGMKJHPRJPLMGIOPIIIIP" +
    "BYFMGLEIKIMMRUKFLFGJFKFTHPFODEQTGTHKIJDHNJGDGiHKNYLHHDLJHGILOEViKNEKGQZfH" +
    "JMIISIJFRHKLJMLPIFJILKKKJKKJESHNLLIKIGKGJJJHKJRGULLSLRONJNEeLKIQGGPQIHPLE" +
    "IHHIDXjQHNBKOGWWIENRbYoHINHNMKTNKHTGMIPXFJLLMLIHPPLDJJKFUMIQMOKJLJJKIJKNL" +
    "HRILJIAIbJEZOGIELGHGLOINDPJMJeJWRIIJHSOZDOsOFRRIOIOTIJSGGJKFUIDOINGOcLQEJ" +
    "FEITLMNIIGIGIMG7LPSNLKVOKIFGHJITGOFUJIIRN";

   ("99r1501vz076mip077myv0733it280exx081gt9118i1g279dyx102uho203ejd07433z087u" +
    "je097kdg1567ft2088rk275dmu1203ez106lih1763ei126f6q101aax084owh088aid161i9" +
    "y179gvn236ptn3338vf132i55080fke101l4z3789ai281ulm081blm124euz074o5m07513z" +
    "14117l095qdn092gl30757n5153").
        replace( /(...)(...)/g, (_,a,b) => K[a] = 1*b );

D = 40655;
N = 479;
H = (s,T) => (
    h = 7,
    [...s].map( c => h = ~~(h*T + c.charCodeAt(0)) ),
    h
);

S = s => (
    y = H( s, 31 ),
    K[((y%D + D)%D).toString( 36 )] || E.indexOf( P[(H( s, 48 )%N + N)%N] )
);

Функція Sприймає рядок (заголовок) і повертає її бал.

Примітки щодо поведінки:

  • ≤ 70 найменувань голосів обробляються окремо від> 70 назв голосів
  • ≤ 70 найменувань голосів відсортовані в скриньки за допомогою високоточного алгоритму оптимізації потенційного відстеження ключових слів голономічного ключового слова, який жодним чином не нагадує функцію хеш-рядка
  • після трохи щасливого обчислення виявляється, що оптимальною здогадкою для кожного сміття є просто геометричне середнє значення (голосів + 20) для всіх заголовків у бункері мінус 20
  • оптимальні здогадки для всіх 479 бункерів потім кодуються як рядок 479 символів base-70
  • для> 70 заголовків голосів, заголовкам присвоюються унікальні 3-значні коди базової 36, згенеровані за допомогою найсучаснішої технології хешування, що гарантує не зіткнення з іншими> 70 заголовків голосів і неправдивих виявлень ≤ 70 назв голосів. Ця найсучасніша методика жодним чином не нагадує спробу випадкових підрахунків смітників, доки не виникне зіткнення.
  • > 70 кодів заголовків і їх підрахунок голосів кодуються в рядку (6 байт за назву), який перетворюється на просту таблицю пошуку. Таким чином, звичайна процедура має нульову помилку для всіх> 70 назв голосів.

10

Python 2, оцінка = 0,335027, 999 знаків, прогнозуйте для цього питання 11,34828

Тільки, щоб куля котилася. Це ніде оптимально.

Фантастична річ SVM - це лише моя випадкова ідея, і мені здалося, що я її втілюю, тому ось вона. Це покращує базовий рівень на 0,02 бала, тому я досить задоволений цим. Але щоб показати, що жорстке кодування вводу - це те, де відбувається більшість удосконалень, я також важко кодую певну відповідь.

Без жорсткого кодування оцінка становить 0,360 (а насправді всі прогнози складають близько 11, ха-ха)

Я використовую scikit-learn та nltk

import sys
import math
import csv
from sklearn.feature_extraction.text import TfidfVectorizer as TV
from sklearn.svm import SVR
from nltk.stem.porter import PorterStemmer as PS
sd = {}
lr = None
tv = None
with open(sys.argv[1], 'r') as cf:
    sr = csv.reader(cf)
    for sc, t in sr:
        if sc == 'Score':
            continue
        sd[t] = int(sc)
ts,scs = zip(*sd.items())
s = PS()
def analyzer(st):
    r = []
    for word in st.split():
        if word.isdigit():
            r.append('<NUM>')
        elif not word.isalnum():
            r.append('<PUNCT>')
        else:
            r.append(s.stem(word.lower()))
    return r
tv = TV(min_df=25, stop_words='english', analyzer=analyzer)
ti = tv.fit_transform(ts)
lr = SVR()
lr.fit(ti, scs)
d={'4 w':378,'y 42':333,'eeta':280,'an Got':279,'s 2 ':275,"e I'":208,'r CP':203,'? No':179,'B.O':156}
def c(t):
    for s in d.keys():
        if s in t:
            return d[s]
    t = tv.transform([t])
    r = lr.predict(t)[0]+1.5
    return r

Я не впевнений, що розумію - ви читали партитури із зовнішнього файлу? То чому б не просто передбачити sd [t]? Це дало б оцінку 0 ...
Офрі Равів

2
Тому що це не було б весело = p
justhalf

4

Python 2, 986 символів, оцінка 0,3480188, прогнозуйте 12

M,S=14.29,23.02
D=lambda x:[ord(y)-32 for y in x]
w='fiLoNoNuMiNoTiMoShOnLoGoLeThRantexgensuBaSqUnInPeReGaMuLinprOuThInThEvEnClOpExPyThADdiSoLiSiMaTrEqUsImAsCoManstARrePoWoReawhapoLandradeTyPaLOsoReCreprediVeReSpebeTiPrImPladaTrihelmakwhicolpaReValpaTrafoROsoumovfinfunpuzyoufaSeQuiwhecoDeChagivcouchehanpoStrdiGraconjavwricalfrowitbinbrafrabuipoi'
for i in range(26):w=w.replace(chr(65+i),chr(97+i)*2)
w=[w[i:i+3]for i in range(0,372,3)]
m=D("(+),+)+=*...+..++'(*)5)/2)*43++16+0,+33*4*/(0.'+>-)+13+(2?8+6;,3;43+4(+.('(,.*.*+56+6)0((++(B,))+E0,-7/)/*++),+***)2+(3(.*)'")
s=D("))'B)'*j+:51(*3+0')+)^'/<-+MG,-1=),-0:A+T&J&K1%,O*()4Y-%:_A.=A*C]MJ-N%)5(%%-0+).*3Q(M&0'%(+$p*)()a8:-T?%5(-*'/.'+)+@,'J&1'&&")
def G(x,m,s):s=s or 1e-9;return(.4/s)*(2.78**(-(x-m)**2./(2*s*s)))
d={w[i]:(m[i],s[i])for i in range(124)}
def Z(t,c):
 p=1
 for W in t.split():
  if len(W)>3:
   W=W[:3].lower()
   if W in d:p*=G(c,*d[W])
 return p*G(c,M,S)
def J(t):return max([(Z(t,r),r)for r in range(-9,99)])[1]

Відповідна функція є J.

Програма по суті є наївними байесами, використовуючи заголовні слова як функції, але це надзвичайно обмежено завдяки межі char. Як обмежено? Ну...

  • Для кожного заголовка ми перетворюємо на малі регістри і дивимося лише на слова довжиною не менше 4 букв. Тоді ми беремо перші три букви кожного з цих слів як особливості. Ми пропускаємо зачистки розділових знаків, щоб заощадити на символах.
  • Ми вибираємо лише трійні літери, які містять на початку принаймні 19 слів (вони зберігаються wвгорі). Стиснення виконується шляхом перестановки триплетів таким чином, щоб було якомога більше подвоєних літер, і ці пари замінюються відповідними великими літерами ASCII (наприклад, fiLoNoN ... → fil, lon, non, ...)
  • Для кожної триплети ми дивимося на бали заголовків, у яких вона фігурує, та обчислюємо середнє та стандартне відхилення балів. Тоді перетворення тих цілих чисел і зберігати їх в m, sвище, використовуючи той факт , що середні / сд є не більше ніж на 90 ( що дозволяє пряме кодування ASCII, так як є 95 версія для друку ASCII)
  • G є нормальною функцією розподілу - ми заокруглюємо e до 2dp, а зворотний квадратний корінь від 2 pi до 1 dp, щоб заощадити на символах.

Загалом, гранична межа обмеження зробила цю найгіршу ідею, яку я коли-небудь придумував, але я дуже задоволений тим, наскільки мені вдалося забитися (хоча це не дуже добре працює). Якщо хтось має кращі ідеї для стиснення, будь ласка, повідомте мене :)

(Дякую KennyTM за вказівку мого безглуздого стиснення)


Якщо я неправильно виконав код, ваш код стиснення навіть довший, ніж декомпресований результат ... w='grge…scse';w=[w[i:i+2]for i in range(0,len(w),2)]становить 165 байт, а ваш C=lambda:…;w=C('…')- 179 байт.
kennytm

@KennyTM О, дякую - я так сильно возився з кодом, намагаючись відповідати межі char, що я втратив сліди всього стискання. : P
Sp3000

4

Python 2, 535 символів, оцінка 0,330910, прогнозує 11,35

Середнє значення балів за титрами, що містять кожне слово, а потім використовуйте верхнє та нижнє 50 слів, щоб можливо змінити бальну базу у guess(title)функції.

Код Python:

BASE = 11.35
word={}
for sc,ti in csv.reader(open(sys.argv[1])):
    if sc == 'Score': continue
    parts = re.findall(r"[-a-zA-Z']+", ti.lower())
    for p in parts:
        a, c = word.get(p, (0.0,0))
        word[p] = (a+int(sc), c+1)

rank = sorted([(sc/ct,wd) for wd,(sc,ct) in word.items() if ct > 2])
adjust = rank[:50] + rank[-50:]

def guess(title):
    score = BASE
    parts = re.findall(r"[-a-zA-Z']+", title.lower())
    for sc,wd in adjust:
        if wd in parts:
            score *= 0.7 + 0.3*sc/BASE
    return score

3

С

Оцінка: Невідома
Довжина: 5 байт
Прогнози: 5

Гольф:

int s(char *p){return 5;}

Безголівки:

int s(char *p)
{
   return 5;
}

Запит на бали дає середню оцінку 5.

Наразі я не маю можливості перевірити це, інші можуть запустити / редагувати.


Далі затоплено: int s () {return 5;}
Джошуа

"Вам спрощено написати програму або функцію, яка приймає заголовок питання PPCG як вхідний і повертає передбачення його балу." - Вибачте, але немає: 0
Joshpbarron

Я бачив платформу, за допомогою якої, якщо ви забули main (), ваша перша функція була main (). Можливо, він залежить від цього.
Джошуа
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.