Giudichiamo alcuni libri dalle loro copertine


47

Tutti sanno che il contenuto pone la domanda. Ma anche un buon titolo aiuta, ed è la prima cosa che vediamo. È tempo di trasformare quella prima impressione in un programma e capire quali tipi di titoli ottengono più voti.

Sei invitato a scrivere un programma o una funzione che prende il titolo di una domanda PPCG come input e restituisca una previsione del suo punteggio.

Ad esempio, potresti ricevere Counting Grains of Riceun input e 59in questo caso dovresti provare a restituire qualcosa vicino al punteggio . Le ipotesi non intere vanno bene, ma non le ipotesi su o sotto -20.

Ecco i dati, per i test e il punteggio:

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

Punteggio: il tuo programma verrà eseguito su ogni domanda nella storia di questo sito (PPCG), senza contare le domande chiuse. La funzione ln(score + 20)verrà quindi applicata a ciascun punteggio e ad ogni ipotesi. L'errore di radice quadrata media tra i due insiemi di valori risultanti è il tuo punteggio. È meglio più basso.

Ad esempio, un programma che ha indovinato 0 ogni volta ha segnato 0,577, mentre uno che ha indovinato 11 ogni volta ha segnato 0,362.

Calcola il tuo punteggio e includilo nel titolo della tua risposta. Includi anche la previsione del tuo programma per quanti voti riceverà questa domanda.

restrizioni:

  • Per evitare l'eccessiva codifica hardware, non più di 1000 caratteri.

  • Deve essere eseguito sull'intero set di dati sopra in meno di un minuto su una macchina ragionevole.

  • Le feritoie standard sono chiuse.


Ecco un tester scritto in Python, per il tuo uso e / o per chiarire le ambiguità:

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
Bella idea, ma è un peccato che il set di dati non sia stabile, quindi i punteggi diventeranno non validi dopo un po '. C'è anche una piccola possibilità di voto strategico: chiunque risponda a questa domanda e ottenga un badge vox-populi nella stessa settimana dovrebbe essere visto con sospetto! ;-)
Level River St

1
Il titolo includerà o escluderà cose come [closed]e [on hold], ove applicabile?
es1024

4
@steveverrill Bene, il rovescio della medaglia è che col passare del tempo, saremo in grado di vedere se i programmi funzionano bene sia sui post futuri che su quelli passati.
isaacg,

6
È difficile sconfiggere l'hard-coding. Ogni domanda con il voto più alto in codice può ridurre fino a 0,4 punti. E sembra che non ci sia anche un modello molto comune, ahah. Sto prevedendo che le risposte competeranno solo su come adattare il maggior numero di risultati codificati in 1000 byte.
solo l'

5
Non dovresti usare l'intero corpus di domande come set di test. Dovresti preselezionare un certo numero (10% -20%) a caso e definirli come set di test (ma non dire a nessuno di cosa si tratta). È molto più facile creare un algoritmo che predice la storia passata, piuttosto che uno che abbia un valore predittivo futuro (cioè, uno che funziona bene su un dato sottoinsieme). (Sarebbe anche meglio rimuovere quel 10% da quello che possiamo vedere, ma non funzionerebbe davvero bene.)
Joe

Risposte:


9

Python 2, 991 caratteri, punteggio 0,221854834221, previsione 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)

Spiegazione:

Questo è un hardcoding senza vergogna, ma cercare di farlo in modo efficiente.

pre-elaborazione:

In un codice separato, ho eseguito l'hashing di ciascun titolo su un valore compreso tra 0 e 256 ^ 2-1. Chiamiamo questi valori bin. Per ogni cestino, ho calcolato il punteggio medio. (La media è necessaria perché per una piccola frazione dei contenitori, ci sono collisioni - più di 1 hash dei titoli nello stesso cestino. Ma per la stragrande maggioranza ogni titolo è mappato su un cestino a sé stante).

L'idea alla base del codice a 2 byte per ogni titolo è che 1 byte non è sufficiente: abbiamo troppe collisioni, quindi non sappiamo davvero quale punteggio assegnare a ciascun contenitore da 1 byte. Ma con i bin a 2 byte, non ci sono quasi collisioni e otteniamo effettivamente una rappresentazione a 2 byte di ciascun titolo.

Quindi classifica i bin - calcola il guadagno in punteggio se assegniamo a questo bin il suo valore calcolato, invece di indovinare 11. Prendi i bin N superiori e codificali in una stringa (che è d nel codice effettivo).

La codifica: la chiave del cestino è codificata come 2 byte. il valore è codificato usando 1 byte. Ho trovato valori compresi tra -8 e 300 + qualcosa, quindi ho dovuto comprimerlo un po 'per inserirlo in 1 byte: x -> (x + 8) / 2.

Codice reale:

leggi d come triplette di byte, decodifica la codifica spiegata sopra. Quando viene assegnato un titolo, calcola il suo hash (modulo 256 ^ 2) e se quella chiave si trova nel dict, restituisci il valore su cui è mappato. Altrimenti, ritorna 11.


3
Un suggerimento: il punteggio medio non è così buono. Guarda la funzione di valutazione delle sfide, non è lineare.
Deduplicatore,

1
@Deduplicator Grazie, mi sono reso conto che dopo aver finito. Il fatto è che per il 99% dei bin non ci sono collisioni, quindi la media è in realtà solo il punteggio del singolo titolo che viene mappato su quel cestino.
Ofri Raviv,

16

Javascript ES6

Punteggio: 0,245663
Lunghezza: 1000 byte
Previsioni: 5

(Immagino che la domanda sia dovuta a una valanga inattesa di downvotes.: P)

minified

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

allargato

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

La funzione Saccetta una stringa (titolo) e restituisce il suo punteggio.

Note sul comportamento:

  • ≤ 70 titoli di voto sono gestiti separatamente da> 70 titoli di voto
  • ≤ 70 titoli di voto sono ordinati in bin usando un algoritmo di ottimizzazione potenziale di tracciamento di parole chiave olonomico altamente sofisticato che non assomiglia in alcun modo a una funzione di hash di stringa
  • dopo un po 'di felice calcolo si scopre che l'ipotesi ottimale per ogni cestino è semplicemente la media geometrica dei (voti + 20) per tutti i titoli nel cestino, meno 20
  • le ipotesi ottimali per tutti i 479 bin vengono quindi codificate come una stringa base-70 di 479 caratteri
  • per> 70 titoli di voto, ai titoli vengono assegnati codici univoci di base 36 a 3 cifre generati utilizzando una tecnica di hashing all'avanguardia che garantisce l'assenza di collisioni con altri titoli di voto> 70 e nessun rilevamento falso di ≤ 70 titoli di voto. Questa tecnica all'avanguardia non assomiglia in alcun modo al conteggio casuale dei bin fino a quando non si producono collisioni.
  • i codici del titolo con> 70 voti e il loro conteggio dei voti sono codificati in una stringa (6 byte per titolo), che viene convertita in una semplice tabella di ricerca. Pertanto, la routine ha zero errori per tutti i> 70 voti.

10

Python 2, Punteggio = 0,335027, 999 caratteri, prevedere 11.34828 per questa domanda

Solo per far rotolare la palla. Questo non è ottimale.

La fantasia di SVM è solo una mia idea casuale e mi è venuta voglia di implementarla, quindi eccola qui. Migliora la linea di base di 0,02 punti, quindi ne sono abbastanza contento. Ma per dimostrare che l'hard-coding dell'input è da dove proviene la maggior parte del miglioramento, sto anche programmando una risposta.

Senza l'hard-coding il punteggio è 0,360 (e in realtà tutte le previsioni sono circa 11, ahah)

Sto usando scikit-learn e 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

Non sono sicuro di aver capito - hai letto i punteggi da un file esterno? Quindi perché non prevedere semplicemente sd [t]? Ciò darebbe un punteggio di 0 ...
Ofri Raviv,

2
Perché non sarebbe divertente = p
solo l'

4

Python 2, 986 caratteri, punteggio 0,3480188, previsione 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]

La funzione rilevante è J.

Il programma è essenzialmente Naive Bayes che utilizza le parole del titolo come funzionalità, ma è estremamente limitato grazie al limite del carattere. Quanto limitato? Bene...

  • Per ogni titolo convertiamo in minuscolo e guardiamo solo le parole lunghe almeno 4 lettere. Quindi prendiamo le prime tre lettere di ciascuna di quelle parole come caratteristiche. Saltiamo la punteggiatura di stripping per risparmiare sui caratteri.
  • Scegliamo solo triplette di lettere che sono all'inizio di almeno 19 parole (queste sono memorizzate wsopra). La compressione viene eseguita riorganizzando le terzine in modo che siano presenti quante più lettere raddoppiate possibile e queste coppie vengono sostituite con la corrispondente maiuscola ASCII (ad esempio fiLoNoN ... → fil, lon, non, ...)
  • Per ogni tripletta, esaminiamo i punteggi dei titoli in cui appare e calcoliamo la media e la deviazione standard dei punteggi. Quindi li convertiamo in numeri interi e li memorizziamo m, ssopra, usando il fatto che media / sd sono al massimo 90 (consentendo una codifica ASCII diretta, poiché ci sono 95 ASCII stampabili)
  • G è la normale funzione di distribuzione - arrotondiamo e a 2dp e la radice quadrata inversa di 2 pi a 1 dp per risparmiare sui caratteri.

Nel complesso, il limite estremo di caratteri ha reso questa una delle peggiori idee che abbia mai avuto, ma sono abbastanza contento di quanto sono riuscito a stipare (anche se non funziona molto bene). Se qualcuno ha idee migliori per la compressione, per favore fatemi sapere :)

(Grazie a KennyTM per aver sottolineato la mia inutile compressione)


A meno che non abbia eseguito il codice in modo errato, il tuo codice di compressione è persino più lungo del risultato decompresso ... w='grge…scse';w=[w[i:i+2]for i in range(0,len(w),2)]è di 165 byte mentre il tuo C=lambda:…;w=C('…')è di 179 byte.
kennytm,

@KennyTM Oh grazie - Ho fatto così tanto casino con il codice, cercando di adattare il limite di caratteri che avevo perso traccia di tutto il processo di compressione. : P
Sp3000,

4

Python 2, 535 caratteri, punteggio 0,330910, previsione 11,35

Calcola la media del punteggio per i titoli contenenti ciascuna parola, quindi usa le 50 parole in alto e in basso per modificare eventualmente il punteggio BASE nella guess(title)funzione.

Codice 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

C

Punteggio: sconosciuto
Lunghezza: 5 byte
Previsioni: 5

golfed:

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

Ungolfed:

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

Una query dei punteggi dà un punteggio medio di 5.

Non ho la possibilità di provarlo al momento, altri sono invitati a eseguire / modificare.


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

"Sei sfidato a scrivere un programma o una funzione che prende il titolo di una domanda PPCG come input e restituisce una previsione del suo punteggio." - Scusa ma
no

Ho visto una piattaforma con la quale se hai dimenticato main (), la tua prima funzione era main (). Forse dipende da quello.
Giosuè,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.