Oceńmy niektóre książki według ich okładek


47

Wszyscy wiedzą, że treść stanowi pytanie. Ale dobry tytuł też pomaga i to pierwsza rzecz, którą widzimy. Czas zamienić to pierwsze wrażenie w program i dowiedzieć się, jakie tytuły zyskują więcej głosów.

Niniejszym zostajesz poproszony o napisanie programu lub funkcji, która pobiera tytuł pytania PPCG jako dane wejściowe i zwraca prognozę jego wyniku.

Na przykład możesz otrzymać Counting Grains of Ricejako dane wejściowe i 59w tym przypadku próbowałbyś zwrócić coś zbliżonego do wyniku . Zgadywanie na liczbach innych niż całkowite jest w porządku, ale zgadywania na poziomie lub poniżej -20nie są.

Oto dane do testowania i oceniania:

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

Punktacja: Twój program będzie uruchamiany na każde pytanie w historii tej witryny (PPCG), nie licząc pytań zamkniętych. Funkcja ln(score + 20)zostanie następnie zastosowana do każdej partytury i do każdego odgadnięcia. Błąd średniej kwadratowej między dwoma wynikowymi zestawami wartości jest wynikiem. Niższe jest lepsze.

Na przykład program, który zgadywał 0 za każdym razem, uzyskałby wynik 0,577, a program, który odgadł 11 za każdym razem, uzyskałby wynik 0,362.

Oblicz swój wynik i umieść go w tytule swojej odpowiedzi. Podaj także prognozę swojego programu dotyczącą liczby głosów pozytywnych na to pytanie.

Ograniczenia:

  • Aby zapobiec nadmiernemu kodowaniu, nie więcej niż 1000 znaków.

  • Musi działać na całym zestawie danych powyżej w niecałą minutę na rozsądnej maszynie.

  • Standardowe luki są zamknięte.


Oto tester napisany w języku Python, do użytku i / lub w celu wyjaśnienia niejasności:

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
Fajny pomysł, ale szkoda, że ​​zestaw danych nie jest stabilny, więc wyniki po pewnym czasie staną się nieważne. Istnieje również niewielka możliwość głosowania strategicznego: każdy, kto odpowie na to pytanie i zdobędzie odznakę vox-populi w tym samym tygodniu, powinien być podejrzany! ;-)
Level River St

1
Czy tytuł będzie zawierał lub wykluczał takie rzeczy, jak [closed]i [on hold], w stosownych przypadkach?
es1024

4
@steveverrill Cóż, drugą stroną tego jest to, że wraz z upływem czasu będziemy mogli sprawdzić, czy programy radzą sobie dobrze na przyszłych i poprzednich postach.
isaacg

6
Trudno pokonać trudne kodowanie. Każde zakodowane najczęściej głosowane pytanie może zmniejszyć nawet 0,4 punktacji. I wydaje się, że nie ma zbyt wielu wspólnych wzorów, haha. Przewiduję, że odpowiedzi będą rywalizować o to, jak dopasować tyle zapisanych wyników w 1000 bajtów.
justhalf

5
Nie należy używać całego zestawu pytań jako zestawu testów. Powinieneś wstępnie wybrać określoną liczbę (10% -20%) losowo i zdefiniować ją jako zestaw testowy (ale nikomu nie mów, co to jest). Znacznie łatwiej jest stworzyć algorytm przewidujący przeszłość niż ten, który ma przyszłą wartość predykcyjną (tj. Taki, który działa dobrze na dowolnym podzbiorze). (Byłoby jeszcze lepiej usunąć te 10% z tego, co w ogóle widzimy, ale to naprawdę nie działałoby dobrze.)
Joe

Odpowiedzi:


9

Python 2, 991 znaków, wynik 0.221854834221, przewidywanie 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)

Wyjaśnienie:

Jest to bezwstydne kodowanie twarde, ale próbuje to zrobić skutecznie.

Wstępne przetwarzanie:

W osobnym kodzie haszowałem każdy tytuł do wartości od 0 do 256 ^ 2-1. Nazwijmy te wartości binami. Dla każdego koszyka obliczyłem średni wynik. (Średnia jest potrzebna, ponieważ dla niewielkiej części pojemników dochodzi do kolizji - więcej niż 1 skrót hashuje do tego samego pojemnika. Ale dla zdecydowanej większości każdy tytuł mapuje się na własny kosz).

Idea 2-bajtowego kodu dla każdego tytułu polega na tym, że 1 bajt to za mało - dostajemy zbyt wiele kolizji, więc tak naprawdę nie wiemy, jaki wynik przypisać do każdego 1-bajtowego pojemnika. Ale w przypadku 2-bajtowych pojemników prawie nie ma kolizji, a my skutecznie uzyskujemy 2-bajtową reprezentację każdego tytułu.

Następnie uszereguj pojemniki - oblicz zysk w wyniku, jeśli przypiszemy temu binowi jego obliczoną wartość, zamiast zgadywania 11. Weź górne N pojemników i zakoduj je w ciąg znaków (który jest w rzeczywistym kodzie).

Kodowanie: klucz pojemnika jest kodowany jako 2 bajty. wartość jest kodowana za pomocą 1 bajtu. Znalazłem wartości od -8 do 300 + coś, więc musiałem trochę wycisnąć, aby uzyskać 1 bajt: x -> (x + 8) / 2.

Rzeczywisty kod:

odczytaj d jako bajty trojaczki, dekodując kodowanie wyjaśnione powyżej. Po nadaniu tytułu oblicz jego skrót (modulo 256 ^ 2), a jeśli ten klucz zostanie znaleziony w nagraniu, zwróć wartość, na którą mapuje. W przeciwnym razie zwróć 11.


3
Sugestia: średni wynik nie jest tak dobry. Spójrz na funkcję punktacji wyzwań, jest ona nieliniowa.
Deduplicator

1
@Deduplicator Dzięki, zdałem sobie sprawę, że po zakończeniu. Chodzi o to, że dla 99% pojemników nie dochodzi do kolizji, więc średnia to tak naprawdę wynik pojedynczego tytułu mapowanego na ten pojemnik.
Ofri Raviv

16

JavaScript ES6

Wynik: 0,245663
Długość: 1000 bajtów
Prognozy: 5

(Myślę, że pytanie jest spowodowane nieoczekiwaną lawiną głosów negatywnych.: P)

Zminimalizowane

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

Rozszerzony

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

Funkcja Sprzyjmuje ciąg (tytuł) i zwraca wynik.

Uwagi na temat zachowania:

  • ≤ 70 tytułów głosowych jest rozpatrywanych oddzielnie od> 70 tytułów głosowych
  • ≤ 70 tytułów głosów jest sortowanych w pojemniki za pomocą wysoce zaawansowanego, holonomicznego algorytmu optymalizacji potencjału śledzenia słów kluczowych, który w żaden sposób nie przypomina funkcji skrótu łańcucha
  • po odrobinie szczęśliwego rachunku różniczkowego okazuje się, że optymalnym trafieniem dla każdego przedziału jest po prostu średnia geometryczna (głosów + 20) dla wszystkich tytułów w zbiorze, minus 20
  • optymalne domysły dla wszystkich 479 przedziałów są następnie kodowane jako 479-znakowy ciąg base-70
  • w przypadku> 70 głosów, tytułom przypisuje się unikalne 3-cyfrowe kody podstawowe 36 wygenerowane przy użyciu najnowocześniejszej techniki mieszania, która gwarantuje brak kolizji z innymi> 70 głosami i fałszywe wykrycie ≤ 70 głosów. Ta najnowocześniejsza technika w żaden sposób nie przypomina prób losowej liczby bin, dopóki nie spowoduje żadnych kolizji.
  • kody tytułów> 70 głosów i ich liczba głosów są kodowane w ciągu (6 bajtów na tytuł), który jest konwertowany na prostą tabelę wyszukiwania. Procedura ma zatem zerowy błąd dla wszystkich> 70 tytułów głosów.

10

Python 2, wynik = 0,335027, 999 znaków, przewiduj 11.34828 dla tego pytania

Tylko po to, żeby piłka się toczyła. To nigdzie nie jest optymalne.

Fantazyjna sprawa z SVM to tylko mój przypadkowy pomysł i chciałem go wdrożyć, więc oto jest. To poprawia linię bazową o 0,02 punktu, więc jestem z tego zadowolony. Ale aby pokazać, że kodowanie danych wejściowych jest źródłem większości ulepszeń, koduję też pewną odpowiedź.

Bez sztywnego kodu wynik wynosi 0,360 (a właściwie wszystkie prognozy to około 11 haha)

Używam scikit-learn i 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

Nie jestem pewien, czy rozumiem - czytasz wyniki z zewnętrznego pliku? Dlaczego więc nie przewidzieć sd [t]? Dałoby to wynik 0 ...
Ofri Raviv

2
Ponieważ to nie byłoby fajne = p
justhalf

4

Python 2, 986 znaków, wynik 0,3480188, przewidywanie 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]

Odpowiednią funkcją jest J.

Program jest zasadniczo naiwny Bayes, używając słów tytułowych jako funkcji, ale jest bardzo ograniczony dzięki limitowi char. Jak ograniczony? Dobrze...

  • Dla każdego tytułu konwertujemy na małe litery i patrzymy tylko na słowa o długości co najmniej 4 liter. Następnie traktujemy pierwsze trzy litery każdego z tych słów jako cechy. Pomijamy usuwanie interpunkcji, aby zaoszczędzić na znakach.
  • Wybieramy tylko trojaczki literowe, które są na początku co najmniej 19 słów (są one zapisane wpowyżej). Kompresja odbywa się przez zmianę kolejności trojaczków, tak aby obecnych było jak najwięcej podwójnych liter, a pary te zostały zastąpione przez odpowiadające im wielkie litery ASCII (np. FiLoNoN ... → fil, lon, non, ...)
  • Dla każdej trojaczki patrzymy na wyniki tytułów, w których się pojawia, i obliczamy średnią i odchylenie standardowe wyników. Potem przekonwertować te do liczb całkowitych i przechowywać je w m, swyżej, wykorzystując fakt, że średnia / SD są co najwyżej 90 (umożliwiający bezpośrednie kodowanie ASCII, ponieważ istnieje 95 druku ASCII)
  • G jest normalną funkcją rozkładu - zaokrąglamy e do 2dp i odwrotny pierwiastek kwadratowy z 2 pi do 1 dp, aby zaoszczędzić na znakach.

Podsumowując, ekstremalny limit znaków sprawił, że był to jeden z najgorszych pomysłów, jakie kiedykolwiek wymyśliłem, ale jestem całkiem zadowolony z tego, jak bardzo udało mi się wcisnąć (choć nie działa to zbyt dobrze). Jeśli ktoś ma lepsze pomysły na kompresję, daj mi znać :)

(Dzięki KennyTM za wskazanie mojej bezsensownej kompresji)


Chyba że źle wykonałem kod, kod kompresji jest nawet dłuższy niż wynik dekompresji ... w='grge…scse';w=[w[i:i+2]for i in range(0,len(w),2)]wynosi 165 bajtów, a twój C=lambda:…;w=C('…')179 bajtów.
kennytm

@KennyTM O dzięki - tak bardzo bałam się kodu, próbując dopasować limit char, że straciłem kontrolę nad kompresowaniem. : P
Sp3000,

4

Python 2, 535 znaków, wynik 0,330910, przewiduje 11,35

Średnia ocena tytułów zawierających każde słowo, a następnie użyj górnego i dolnego 50 słów, aby ewentualnie zmodyfikować wynik BASE w guess(title)funkcji.

Kod 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

do

Wynik: nieznana
Długość: 5 bajtów
Prognozy: 5

Gra w golfa:

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

Nie golfowany:

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

Zapytanie o wyniki daje średni wynik 5.

W tej chwili nie mam możliwości przetestowania, inni mogą uruchamiać / edytować.


Dalej Gulfed: int s () {return 5;}
Joshua

„Niniejszym zostajesz wezwany do napisania programu lub funkcji, która przyjmuje tytuł pytania PPCG jako dane wejściowe i zwraca prognozę jego wyniku”. - Przepraszam, ale nie: 0
Joshpbarron

Widziałem platformę, dzięki której, jeśli zapomniałeś main (), twoją pierwszą funkcją była main (). Może on na tym polega.
Joshua,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.