¿Quien dijo que? Elección presidencial de 2016

16

En este desafío, su tarea es hacer escribir un programa con menos de 300 caracteres que tome un párrafo corto o unas pocas oraciones que haya dicho un candidato y genere quién lo dijo.

Entrada : puede tomarse como parámetro de una función, entrada a un programa, etc. Será un párrafo corto, puntuado correctamente.

Salida : El candidato que crees que es. Este podría ser uno de

Ben Carson (1)
Ted Cruz (2)
John Kasich (3)
Marco Rubio (4)
Donald Trump (5)
Hillary Clinton (6)
Bernie Sanders (7)

Dejé los nombres de las personas que abandonaron el 1 de marzo. Puede generar el nombre mismo o, más convenientemente, el número que corresponde al nombre.

Puntuación: su puntuación es el porcentaje de casos de prueba que obtiene correctamente. La puntuación más alta gana. Los empates (o puntajes perfectos) se dividen por la longitud del código como en un código de golf.

Los casos de prueba se pueden extraer de:

http://www.presidency.ucsb.edu/debates.php

Haga clic en cada debate, tanto demócrata como republicano que haya sucedido hasta ahora (antes del 1 de marzo). Cada párrafo es un caso de prueba, a menos que el "párrafo" tenga menos de 20 caracteres de longitud.

Aquí hay un código que extrae los casos de prueba de una página en particular:

var t = $(".tools").parentNode.querySelectorAll("p");
var categ = {}, cur = 0;
for (var i = 0; i < t.length; ++i) {
  var p = t[i], str = p.innerText;
  if (p.querySelector("b")) {
    cur = p.querySelector("b").innerText.replace(':', '');
    str = str.replace(/^.*?:\s/, '');
  }
  str = str.replace(/\[applause\]/g, '')
  if (str.length < 20) continue;
  if (categ[cur] == null) categ[cur] = [];
  categ[cur].push(str);
}

Entonces puedes hacer categ.SANDERS para obtener una lista de todos los párrafos que ha dicho el senador Sanders.

Puede descartar cualquier cosa que no haya dicho los candidatos mencionados anteriormente (p. Ej. categ.BUSHOcateg.CHRISTIE ).

Aquí está el archivo con todos los casos de prueba: https://drive.google.com/file/d/0BxMn8--P71I-bDZBS2VZMDdmQ28/view?usp=sharing

El archivo está organizado por candidato

CANDIDATE CANDIDATE_LAST_NAME
(empty line)
Series of statements. Each paragraph is separated by (NEW PARAGRAPH)-
(empty line)
CANDIDATE NEXT_CANDIDATE_LAST_NAME
(empty line)
etc.

Un ejemplo de envío parcial sería:

if (/ win | wall | great | beautiful/.test(p)) return 5;
if (/ percent | top one | rigged /.test(p)) return 7;
// etc. for all candidates

o

var words = p.split(' ');
// majority of words have less than 5 characters
if (words.length - words.filter(a => a.length < 5).length < 4) evidence[5]++;
// at the end
return /* index with the most evidence */ 

Aquí hay un lugar donde puede probar las soluciones de JavaScript: https://jsfiddle.net/prankol57/abfuhxrh/

El código usa el parámetro ppara representar la frase a clasificar. Código de ejemplo que obtiene un puntaje de alrededor del 20% (adivinar obtendría alrededor del 11%):

if (/ rigged | top | percent | Wall Street /.test(p)) return 'Sanders';
return 'Trump';

Exactamente lo que estoy preguntando: escriba un programa / función en menos de 300 caracteres que tome como entrada una frase que un candidato ha dicho y devuelva como salida qué candidato lo dijo. Su puntaje es el porcentaje de casos de prueba que obtiene correctamente. La puntuación más alta gana.

Sí, sé que muchas líneas tienen [laughter]o [cheering]en ellas. Estos no serán eliminados. En el peor de los casos, son información adicional que puede ignorar; en el mejor de los casos, son información adicional que puede usar (por ejemplo, inventé esto, pero tal vez la risa de la gente es evidencia de que Marco Rubio está hablando). Los casos de prueba son como aparecen en el archivo de texto.

soktinpk
fuente
1
Tengo una sugerencia. ¿Qué tal si lo haces en código golf, pero tienes que obtener todas las citas correctas? Además, es posible que desee hacer las citas mucho más cortas, ya que es un poco ridículo resolverlo tal cual.
Cyoce
2
@Cyoce acertar todas las citas sería ridículo (creo) teniendo en cuenta la gran cantidad de citas.
soktinpk
1
Idea de desafío inteligente, aunque puede necesitar un poco de refinamiento. ¿Has considerado publicar en Sandbox para recibir comentarios?
Ashwin Gupta
1
¿Cuál es el criterio ganador? (¿Y por qué crees que nadie obtendrá una puntuación perfecta?)
Peter Taylor
2
La fuente de datos que proporcionó es un poco desordenada (difícil de analizar automáticamente), lo que creo que elimina parte del espíritu del desafío. He creado una versión limpia que utiliza una línea por cita, con una línea en blanco que separa el siguiente nombre de candidato. Esto es mucho más fácil de analizar en la mayoría de los idiomas. Lo he subido aquí: drive.google.com/file/d/0B3uyVnkMpqbVSnVrZkVwTUhDODg (aparte de cambiar las nuevas líneas, he dejado los datos intactos. Eso incluye lo que parece un problema de codificación para)
Dave

Respuestas:

14

Políglota, ~ 18.6%

Esto funciona en: Cjam, Pyth, TeaScript, Japt, Seriously, 05AB1E, GolfScript, Jelly y probablemente muchos más.

6

Esto genera Hillary para todas las entradas. Esto se debe a que Hillary dijo más. Si bien no es la forma más ingeniosa de hacer esto. Funciona ¯ \ _ (ツ) _ / ¯

Downgoat
fuente
Me gusta cómo esto se marca como publicación de baja calidad. : P
Denker
1
@DenkerAffe probablemente por ser bajo
Downgoat
1
¿Alguna razón para usar JavaScript? Podrías haber reducido a un personaje en otro idioma: P
ghosts_in_the_code
@ghosts_in_the_code fijo
Downgoat
9

Pyth, 34.16% (297 bytes)

FNc"7creta
6enato
3ohio
2donal
7 major 
6o try t
5tot
5se me
7nai
4m pres
2he ob
3 bala
5jeb
6e aff
5mendous 
2mnest
5. we'r
7ave got to
2c ter
4ntur
7 campaign 
2flat
5obo
4is pre
4-here'
2note
2m el
4 issue 
5, very
6o af
1fact o
6en's
5pany
6he republicans
7 -- 
4meon
5bea
4ory o
7"bI}tNrzZhNB

(tenga en cuenta que algunas líneas terminan en espacios)

Elegí la opción más simple que se me ocurrió: verifique una lista de patrones y, tan pronto como encuentre una coincidencia, envíe el candidato correspondiente. Si todo lo demás falla, muestre el candidato más probable del resto. Después de eso, se trata de agrupar tantos datos en 300 bytes como sea posible.

FNc"<data>"bI}tNrzZhNB

Descompostura:

FN                      for N in ...
   "<data>"              the hard-coded data (newline separated)
  c                      split using...
           b             '\n' constant,
            I           if
              tN         tail (all but first char) of current item
             }           is contained within
                rzZ      the input (lowercased),
                        then:
                   hN    print the head (first char) of the current item
                     B   and break out of the loop.

Entonces, ¿de dónde provienen esos datos? Bueno, la estructura es simplemente:

<candidate_number><phrase>
<candidate_number><phrase>
<etc.>

(con una entrada al final sin frase para actuar como el último recurso)

¿Pero por qué esos artículos en particular? Escribí un programa en C ++ para analizar el conjunto de datos proporcionado (primero con una limpieza manual de las nuevas líneas para que la estructura sea coherente). Examina todas las subcadenas ("tokens") en cada cita (1-16 caracteres), luego verifica repetidamente el token que brinda el mayor beneficio para ir a continuación en la lista. Una vez que un patrón está en la lista, elimine las comillas que coincidan y repita (se vuelve un poco más complicado mantenerlo rápido, pero eso es lo básico). El código es probablemente demasiado largo para incluirlo aquí, pero podría ponerlo en github más tarde (cuando lo haya limpiado un poco).

Probé un par de sistemas de puntuación. Al final fui con este:

score = (
    + matching_quote_count_for_most_likely_author * 10
    - matching_quote_count_for_other_authors * 7
    - token_length
)

Un enfoque más estricto de permitir solo nuevos elementos que no introducen respuestas incorrectas pareció atorarse en aproximadamente 20-25%, necesitando muchos patrones para ser más altos. Este enfoque más difuso funciona mucho mejor y aún puede alcanzar una precisión de ~ 80% (con 550 elementos). El puntaje presentado tiene 38 elementos, que fue lo máximo que pude en el límite de 300 caracteres.

El resultado del 34% en realidad proviene de un programa de prueba C ++ que realiza los mismos pasos. Debería coincidir, pero no tengo un arnés de prueba Pyth para verificarlo.

Esta es la primera vez que utilizo Pyth, así que imagino que se podrían reducir algunos bytes más, permitiendo un poco más de datos.

Dave
fuente
44
También sé que a Sanders le encanta hablar de la secretaria Clinton, que Clinton está obsesionado con el senador Sanders, Kasich ama a Ohio, Cruz siempre menciona a Donald Trump, Rubio está obsesionado con los siglos, Carson tiene todos los "hechos" del asunto, y A Trump le encanta decir "totalmente". Esto se siente como el comienzo de un generador de bingo político. Tendré que probarlo en algunas personalidades del Reino Unido ...
Dave
Creo que podría guardar algunos bytes aquí al empaquetar la cadena .".
lirtosiast
8

Javascript, 32.87%

299 caracteres:

function Q(a,b){return p.toLowerCase().split(' ').join('').includes(a)<<b}z=Q('ink',0)+Q('int',1)+Q('ona',2)+Q('rica',3)+Q('twe',4)+Q("we'",5)+Q('youkn',6);return '55472726464727446676664676767676563641233643334456364233336141745116222136477126111113361611262316263122216111673336225611363276'[z]*1

Estrategia:

Hice una búsqueda de fuerza bruta en qué segmentos de palabras incluir en un "hash". Luego, se realiza una búsqueda de cadena con ese hash de tal manera que elige al candidato más probable para ese hash.

El código en sí:

// The Q function checks if a string is present.
// Then left-shifts the true/false result up to e.g. 64,32,16,8,4,2,1
// This way we can combine results into any number 0 to 127.
function Q(a,b){return p.toLowerCase().split(' ').join('').includes(a)<<b}

// Now we check for key string occurrences:
z=Q('ink',0)+Q('int',1)+Q('ona',2)+Q('rica',3)+Q('twe',4)+Q("we'",5)+Q('youkn',6)

// Finally, use this as an index into the lookup string. (Multiply by 1 to convert char to int.)
return '55472726464727446676664676767676563641233643334456364233336141745116222136477126111113361611262316263122216111673336225611363276'[z]*1

Esta es mi primera presentación de código de golf, por lo que las sugerencias son bienvenidas :)

Ru Hasha
fuente
5

Mathematica, 23.7775%

(l=ToLowerCase@#;Ordering[-StringCount[l,#]&/@{"fact","donald"|"obama","done"|"ohio","issue"|"united"|"why"|"world","great"|"many","senator","american"|"believe"|"campaign"|"secretary"|"street"|"wall"},1])[[1]]&

Cuenta las ocurrencias de palabras clave comunes únicas para cada candidato y genera el número del candidato con la puntuación más alta.

Básicamente, encontré las palabras más comunes de todos los candidatos.

t = Import["~/Documents/candidate quotes.txt"];
ts = DeleteCases[StringSplit[t, "\n\n"], ""];
tss = Split[ts, StringLength[#2] > 20 &][[{3, 4, 5, 6, 7, 1, 2}]];
names = StringSplit[#][[2]] & /@ tss[[All, 1]];
quotes = StringSplit[#, "(NEXT PARAGRAPH)"] & /@ StringJoin /@ tss[[All, 2 ;;]];
(* remove the 100 commonest english words *)
wd = WikipediaData["Most common words in English", "ArticleWikicode"];
Flatten[StringSplit[StringCases[wd, 
  Shortest["{| class=\"wikitable\"" ~~ w__ ~~ "}"] -> w], "\n"]];
common100 = 
Alternatives @@ ToLowerCase@DeleteDuplicates@Flatten[StringSplit /@ 
     StringCases[#, 
      "|| " ~~ ("[[" | "") ~~ w : ((WordCharacter | " ") ..) -> 
       w] & /@ %];
commonest = 
  Commonest[
Flatten[StringSplit[
    StringDelete[ToLowerCase[#], 
     PunctuationCharacter | (WordBoundary ~~ (common100) ~~ 
        WordBoundary)]] & /@ #], 20] & /@ quotes;

y elija las palabras clave comunes que son únicas para cada candidato.

keywords = 
 Alternatives @@@ 
  Table[Complement[commonest[[n]], 
    Union[Flatten[Delete[commonest, n]]]], {n, Length[names]}];

Después de eliminar manualmente algunas de las palabras clave, esta es la tabla final:

Carson    fact
Cruz      donald|obama
Kasich    done|ohio
Rubio     issue|united|why|world
Trump     great|many
Clinton   senator
Sanders   american|believe|campaign|secretary|street|wall

Con estas palabras clave, la longitud total de la función es de 211 caracteres. Probé la función sobre todas las citas:

pairs = Flatten[MapThread[Table[q -> #1, {q, #2}] &, {names, quotes}]];
test[q_ -> n_] := Boole[n === names[[p@q]]] (* here p is my function that outputs the predicted candidate's number *)
Total[ParallelMap[test, pairs]]/Length[pairs] // N

lo que da una precisión del 23.7775%.

shrx
fuente
3

Python, 25.677868%

Elegido arbitrariamente cuatro personajes diferentes que se utilizarían para identificar a los candidatos. A cada candidato se le asigna un factor de puntuación por personaje basado en una búsqueda de escalada que realicé durante unos minutos para terminar en 25.68%.

Supongo que esto al menos demuestra que el concepto es mejor que elegir un candidato con los ojos vendados o simplemente elegir a Clinton, pero me interesaría ver a alguien aplicar un mejor algoritmo de búsqueda, tanto por los factores como por los caracteres utilizados.

w=dict(zip("hr?.",((.847,.491,.821,.54,.744,.765,.234),(.494,.777,.202,.587,.7,.852,.484),(.915,.187,.161,.559,.748,.244,.43),(.11,.013,.628,.974,1.037,.484,.302))))
def f(t,r=(0,0,0,0,0,0,0)):
 s=r
 for c in t:s=map(lambda a,b:a+b,s,w.get(c,r))
 return s.index(max(s))+1
boomlinde
fuente
1

Javascript, TBD

a=[...p].reduce((a,b)=>(a<<5)-a+b.charCodeAt(0)|0,0)%1000,alert(a>0?0:1000,a<79?1:a<226?2:a<333?3:a<497?4:a<697?5:a<849?6:7)

Convierte cada cadena en un código hash, luego usa métodos probabilísticos para determinar el hablante. Sería bueno si alguien con una buena configuración pudiera probar esto por mí.

LegionMammal978
fuente
Cuento alrededor del 16.1%, pero no estoy realmente seguro de lo que hace. ¿Qué hace el a + = a? 0: 1000? (Tuve que reemplazar la alerta con un retorno, así que no estaba seguro de qué hacer exactamente)
soktinpk
@soktinpk Lo siento, a+=debe haber sido un error tipográfico.
LegionMammal978