¿La cebolla, o no la cebolla?

The Onion (advertencia: muchos artículos son NSFW) es una organización de noticias satírica que parodia los medios informativos tradicionales. En 2014, The Onion lanzó ClickHole (advertencia: también con frecuencia NSFW), un sitio web de noticias satíricas que parodia sitios «clickbait» como BuzzFeed. Gracias a la Ley de Poe , es bastante común que las personas lean los titulares de los artículos de The Onion o ClickHole y crean que son ciertos, sin saber que pretenden ser una sátira. Lo contrario también ocurre con las noticias reales que suenan ridículas: la gente suele pensar que son una sátira cuando no lo es.

Esta confusión se presta naturalmente a un juego: dado un titular de noticias, intente adivinar si o no es sátira. Este desafío se trata de hacer exactamente eso con un programa.

Dado un titular de noticias (una cadena que consta solo de caracteres y espacios ASCII imprimibles), la salida 1 si el el título es una sátira, o 0 si no lo es. Su puntuación será el número de resultados correctos dividido por el número total de titulares.

Como de costumbre, lagunas legales (especialmente optimización para los casos de prueba ) no están permitidos. Para hacer cumplir esto, ejecutaré sus programas en un conjunto de 200 casos de prueba ocultos (100 de The Onion, 100 de Not The Onion). Su solución no debe obtener más de 20 puntos porcentuales menos que su puntaje en los casos de prueba públicos para ser válida.

Casos de prueba

Para presentar casos de prueba para este desafío , Elegí 25 títulos de The Onion subreddit (donde se publican los artículos de The Onion y sus sitios secundarios, como ClickHole) y 25 títulos de el subreddit Not The Onion (donde se publican artículos de noticias reales que suenan a sátira). Los únicos cambios que hice en los titulares fueron reemplazar las citas «elegantes» con citas ASCII regulares y estandarizar las mayúsculas; todo lo demás se mantiene sin cambios desde el título del artículo original. Cada título está en su propia línea.

Los titulares de Onion

Trump Warns Removing Confederate Statues Could Be Slippery Slope To Eliminating Racism Entirely "No Way To Prevent This," Says Only Nation Where This Regularly Happens My Doctor Told Me I Should Vaccinate My Children, But Then Someone Much Louder Than My Doctor Told Me I Shouldn"t Man At Park Who Set Up Table Full Of Water Cups Has No Idea How Passing Marathon Runners Got Impression They Can Take Them This Child Would Have Turned 6 Today If His Mother Hadn"t Given Birth To Him In October Incredible Realism: The Campaign In The Next "Call Of Duty" Will Begin At Your Avatar"s High School Cafeteria When He"s Being Tricked Into Joining The Military By A Recruiter "Sometimes Things Have To Get Worse Before They Get Better," Says Man Who Accidentally Turned Shower Knob Wrong Way Report: Uttering Phrase "Easy Does It" Prevents 78% Of Drywall Damage While Moving Furniture Barbara Bush Passes Away Surrounded By Loved Ones, Jeb Family Has Way Too Many Daughters For Them Not To Have Been Trying For Son News: Privacy Win! Facebook Is Adding A "Protect My Data" Button That Does Nothing But Feels Good To Press Dalai Lama Announces Next Life To Be His Last Before Retirement Researchers Find Decline In Facebook Use Could Be Directly Linked To Desire To Be Happy, Fully Functioning Person Manager Of Combination Taco Bell/KFC Secretly Considers It Mostly A Taco Bell Trump: "It"s My Honor To Deliver The First-Ever State Of The Union" Daring To Dream: Jeff Bezos Is Standing Outside A Guitar Center Gazing Longingly At A $200 Billion Guitar Area Dad Looking To Get Average Phone Call With Adult Son Down To 47.5 Seconds Experts Warn Beef Could Act As Gateway Meat To Human Flesh Jeff Bezos Named Amazon Employee Of The Month Dad Suggests Arriving At Airport 14 Hours Early Report: Only 3% Of Conversations Actually Need To Happen Delta Pilot Refuses To Land Until Gun Control Legislation Passed Family Wishes Dad Could Find Healthier Way To Express Emotions Than Bursting Into Full-Blown Musical Number New Honda Commercial Openly Says Your Kids Will Die In A Car Crash If You Buy A Different Brand Teacher Frustrated No One In Beginner Yoga Class Can Focus Chakras Into Energy Blast 

Titulares de Not The Onion

Man Rescued From Taliban Didn"t Believe Donald Trump Was President Nat Geo Hires Jeff Goldblum To Walk Around, Being Professionally Fascinated By Things Mike Pence Once Ratted Out His Fraternity Brothers For Having A Keg Reddit CEO Tells User, "We Are Not The Thought Police," Then Suspends That User Trump Dedicates Golf Trophy To Hurricane Victims Uber"s Search For A Female CEO Has Been Narrowed Down To 3 Men ICE Director: ICE Can"t Be Compared To Nazis Since We"re Just Following Orders Passenger Turned Away From Two Flights After Wearing 10 Layers Of Clothing To Avoid Luggage Fee Somali Militant Group Al-Shabaab Announces Ban On Single-Use Plastic Bags UPS Loses Family"s $846k Inheritance, Offers To Refund $32 Shipping Fee Teen Suspended From High School After Her Anti-Bullying Video Hurts Principal"s Feelings Alabama Lawmaker: We Shouldn"t Arm Teachers Because Most Are Women Cat Named After Notorious B.I.G. Shot Multiple Times - And Survives EPA Head Says He Needs To Fly First Class Because People Are Mean To Him In Coach Apology After Japanese Train Departs 20 Seconds Early Justin Bieber Banned From China In Order To "Purify" Nation Alcohol Level In Air At Fraternity Party Registers On Breathalyzer NPR Tweets The Declaration Of Independence, And People Freak Out About A "Revolution" Man Who Mowed Lawn With Tornado Behind Him Says He "Was Keeping An Eye On It." After Eating Chipotle For 500 Days, An Ohio Man Says He"s Ready For Something New "El Chapo" Promises Not To Kill Any Jurors From Upcoming Federal Trial After 4th DWI, Man Argues Legal Limit Discriminates Against Alcoholics Palestinian Judge Bans Divorce During Ramadan Because "People Make Hasty Decisions When They"re Hungry" Argentinian Officers Fired After Claiming Mice Ate Half A Ton Of Missing Marijuana "Nobody Kill Anybody": Murder-Free Weekend Urged In Baltimore 

Comentarios

  • Your score will be the number of correct outputs divided by the total number of headlines ¿Bytecount es un factor decisivo?
  • Yo ‘ un poquito confundido. ¿Qué tipo de solución espera? Cada solución tendrá que » optimizar para los casos de prueba » algo, barra de escritura de una IA que puede entender inglés y tiene sentido del humor. Por ejemplo, la solución de Arnauld ‘ detecta /ly\b/ que funciona solo porque el 25 Onio Los titulares que elegiste tienen más adverbios, pero por lo que sé, podrías tropezar fácilmente con una batería de prueba diferente. ¿Y quién ‘ puede decir que sus coeficientes no son ‘ t elegidos para optimizar su puntuación? (¿Por qué no ‘ los optimizaría?)
  • Esta batería de prueba parece un poco inusual. Es ‘ como pedir un clasificador que pueda detectar perros en una fotografía, pero tomar sus casos de prueba positivos como fotos de perros y sus casos de prueba negativos de un artículo de Buzzfeed titulado » 25 fotos de objetos que ‘ jurarás que son perros, pero no, resulta que no son ‘ t! (# 11 ¡Te dejará boquiabierto!) » Hace que un problema bastante difícil sea más difícil.
  • El desafío no solo es difícil, sino que ‘ tampoco es obvio (para mí) cuál ‘ es la diferencia. Si no puedo ‘ resolverlo, por supuesto que mi programa no puede ‘ resolverlo (es decir, mientras me convenzo de que no ‘ t hardcode para los casos de prueba)
  • Bueno, pasé más de 36 horas entrenando una red neuronal artificial usando brain.js y LSTM, con muestras en este número y otras 100 muestras de cada tipo de los enlaces proporcionados, pero el resultado no fue ‘ t suficientemente bueno con títulos nuevos que no eran ‘ t presente en conjuntos de entrenamiento. ‘ he terminado: P

Responder

JavaScript ( ES7), 39/50 (78%)

63.5% (127/200) en casos de prueba ocultos

Una heurística simple basada en la longitud del título, el número de espacios y uso del sufijo -ly.

 isOnion = str => str.length ** 0.25 + str.split(" ").length ** 1.25 * 2 + str.split(/ly\b/).length ** 1.75 * 7 > 76  

¡Pruébelo en línea!

Comentarios

  • Esto es absurdamente efectivo por lo simple que es.
  • Esta solución obtuvo un 63.5% en los casos de prueba ocultos, por lo que es válido.
  • No es tan simple como era posible al comienzo de la caja de arena (100%, utilizando diferencias de capitalización antes de que se estandarizara) pero esto es realmente simple.
  • @Mego Solo por curiosidad, ¿esta versión NSFW mejora la puntuación en los casos de prueba ocultos? 🙂
  • @Arnauld 66% con esa versión

Responder

Python 3, 84%

No probado en casos de prueba ocultos.

Esto usa Keras LSTM RNN entrenado en varios titulares. Para ejecutarlo, necesita Keras lo siguiente y el modelo que he puesto a disposición en GitHub: enlace de repositorio . Necesitará el modelo .h5 y las asignaciones de palabra / vector están en .pkl. Las últimas

Las dependencias son:

import numpy as np from pickle import load from keras.preprocessing import sequence, text from keras.models import Sequential from keras.layers import Dense, Embedding, SpatialDropout1D, LSTM, Dropout from keras.regularizers import l2 import re 

La configuración es:

max_headline_length = 70 word_count = 20740 

El modelo es:

model = Sequential() model.add(Embedding(word_count, 32, input_length=max_headline_length)) model.add(SpatialDropout1D(0.4)) model.add(LSTM(64, kernel_regularizer=l2(0.005), dropout=0.3, recurrent_dropout=0.3)) model.add(Dropout(0.5)) model.add(Dense(32, kernel_regularizer=l2(0.005))) model.add(Dropout(0.5)) model.add(Dense(2, kernel_regularizer=l2(0.001), activation="softmax")) 

Ahora para cargar el modelo y la palabra embeddings:

model.load_weights("model.h5") word_to_index = load(open("words.pkl", "rb")) 

Y el código para probar si una cadena es de «NotTheOnion» o «TheOnion «He escrito una función de ayuda rápida que convierte la cadena en las respectivas incrustaciones de palabras:

def get_words(string): words = [] for word in re.finditer("[a-z]+|[\"".;/!?]", string.lower()): words.append(word.group(0)) return words def words_to_indexes(words): return [word_to_index.get(word, 0) for word in words] def format_input(word_indexes): return sequence.pad_sequences([word_indexes], maxlen=max_headline_length)[0] def get_type(string): words = words_to_indexes(get_words(string)) result = model.predict(np.array([format_input(words)]))[0] if result[0] > result[1]: site = "NotTheOnion" else: site = "TheOnion" return site 

Explicación

Este código ejecuta una modelo que analiza las relaciones entre palabras representando las palabras como un «vector». Puede obtener más información sobre la inserción de palabras aquí .

Esto se basa en titulares, pero los casos de prueba están excluidos .

Este proceso se automatiza después de bastante procesamiento. He distribuido la lista final de palabras procesadas como .pkl pero lo que sucede en la incrustación de palabras es que primero analizamos la oración y aislamos las palabras.

Después de ahora tener las palabras, el siguiente paso es poder comprender las diferencias y similitudes entre ciertas palabras, por ejemplo, king y queen versus duke y duchess. Estas incrustaciones no ocurren entre las palabras reales sino entre los números que representan las palabras, que es lo que se almacena en el .pkl archivo. Las palabras que la máquina no entiende se asignan a una palabra especial <UNK> que nos permite entender que hay una palabra allí, pero que no se sabe exactamente cuál es su significado.

Ahora que se pueden entender las palabras, es necesario poder analizar la secuencia de palabras (título). Esto es lo que hace «LSTM», un LTSM es un tipo de celda «RNN» que evita el efecto de degradado que se desvanece. Más simplemente, toma una secuencia de palabras y nos permite encontrar relaciones entre ellas.

Ahora la capa final es Dense lo que básicamente significa que es como una matriz, lo que significa que la salida es como: [probability_is_not_onion, probability_is_onion]. Al encontrar cuál es más grande, podemos elegir cuál es el resultado más confiable para el título dado.

Respuesta

Python 3 + Keras, 41/50 = 82%

83% (166/200) en casos de prueba ocultos

import json import keras import numpy import re from keras import backend as K STRIP_PUNCTUATION = re.compile(r"[^a-z0-9 ]+") class AttentionWeightedAverage(keras.engine.Layer): def __init__(self, return_attention=False, **kwargs): self.init = keras.initializers.get("uniform") self.supports_masking = True self.return_attention = return_attention super(AttentionWeightedAverage, self).__init__(**kwargs) def build(self, input_shape): self.input_spec = [keras.engine.InputSpec(ndim=3)] assert len(input_shape) == 3 self.W = self.add_weight(shape=(input_shape[2], 1), name="{}_W".format(self.name), initializer=self.init) self.trainable_weights = [self.W] super(AttentionWeightedAverage, self).build(input_shape) def call(self, x, mask=None): logits = K.dot(x, self.W) x_shape = K.shape(x) logits = K.reshape(logits, (x_shape[0], x_shape[1])) ai = K.exp(logits - K.max(logits, axis=-1, keepdims=True)) if mask is not None: mask = K.cast(mask, K.floatx()) ai = ai * mask att_weights = ai / (K.sum(ai, axis=1, keepdims=True) + K.epsilon()) weighted_input = x * K.expand_dims(att_weights) result = K.sum(weighted_input, axis=1) if self.return_attention: return [result, att_weights] return result def get_output_shape_for(self, input_shape): return self.compute_output_shape(input_shape) def compute_output_shape(self, input_shape): output_len = input_shape[2] if self.return_attention: return [(input_shape[0], output_len), (input_shape[0], input_shape[1])] return (input_shape[0], output_len) def compute_mask(self, input, input_mask=None): if isinstance(input_mask, list): return [None] * len(input_mask) else: return None if __name__ == "__main__": model = keras.models.load_model("combined.h5", custom_objects={"AttentionWeightedAverage": AttentionWeightedAverage}) with open("vocabulary.json", "r") as fh: vocab = json.load(fh) while True: try: headline = input() except EOFError: break tokens = STRIP_PUNCTUATION.sub("", headline.lower()).split() inp = numpy.zeros((1, 45)) for i, token in enumerate(tokens): try: inp[0,i] = vocab[token] except KeyError: inp[0,i] = 1 print(model.predict(inp)[0][0] > 0.3) 

combined.h5 y vocabulary.json se pueden recuperar de aquí (muy grande) y aquí .

Clasificador completamente conectado conectado a un modelo de análisis de sentimientos previamente entrenado DeepMoji, que consiste en LSTM bidireccionales apilados y un mecanismo de atención. Congelé las capas de DeepMoji y saqué la capa final de softmax, entrené solo las capas completamente conectadas, luego descongelé las capas de DeepMoji y las entrené juntas para un ajuste fino. El mecanismo de atención se toma de https://github.com/bfelbo/DeepMoji/blob/master/deepmoji/attlayer.py (no quería tener que usar todo su código como una dependencia para una clase, especialmente porque es Python 2 y es bastante difícil de manejar como módulo …)

Esto funciona sorprendentemente mal en el conjunto de pruebas de Mego, considerando que en mi propio conjunto de validación más grande obtiene> 90%. Así que todavía no he terminado con esto.

Comentarios

  • 83% en casos de prueba ocultos, asumiendo que lo ejecuté correctamente

Responder

JavaScript ( Node.js ), 98% (49/50)

96% (192/200) en casos de prueba ocultos

 const words = require("./words"); const bags = require("./bags"); let W = s => s.replace(/[^A-Za-z0-9 ]/g, "").toLowerCase().split(" ").filter(w => w.length > 3); let M = b => { for (let i = 0; i < bags.length; i++) { let f = true; for (let j = 0; j < bags[i].length; j++) if (!b.includes(bags[i][j])) { f = false; break; } if (f) return true; } return false; }; let O = s => { let b = []; W(s).forEach(w => { let p = words.indexOf(w); if (p >= 0) b.push(p); }); return (b.length > 0 && M(b)); };  

Esto requiere dos archivos JSON grandes que «no puedo poner aquí o en » TiO «. Descárgalos de los siguientes enlaces y guárdalos con words.json y nombres, en la misma carpeta que el archivo JS. También hay un enlace para un archivo JS con casos de prueba e impresión de resultado / porcentaje.Puede poner sus casos de prueba ocultos en las variables onions y nonOnions.

Después de guardar los 3 archivos en el mismo directorio, ejecute node onion.js.

La función O devolverá true si es cebolla y false si no es «t. Utiliza una gran lista de bolsas de palabras (sin orden) para detectar si la cadena de entrada es una cebolla. Algo codificado, pero funciona muy bien en una variedad de pruebas aleatorias casos.

Comentarios

  • Esta solución obtiene un 96% de los casos de prueba ocultos

Respuesta

Trabajando con la solución de Arnauld

JavaScript (ES6), 41/50

64% (128/200) en oculto casos de prueba

str.includes("Dad") || str.length ** .25 + str.split(" ").length ** 1.25 * 2 + str.split(/ly\b/).length ** 1.75 * 7 > 76 

JavaScript (ES6), 42/50

62.5% (125/200) en casos de prueba ocultos (no válido)

isOnion = str => str.includes("Dad") || str.length ** .25 + str.split(" ").length ** 1.25 * 2 + str.split(" ").filter(w => w.length > 3 && w.split(/ly/).length > 1).length * 23.54 + /\d/.test(str) * 8 > 76 

La longitud + recuento de palabras + «ly «El concepto funciona bastante bien, pude exprimir algunos puntos más al verificar la palabra» papá «(¿cuándo los artículos reales hablan sobre los papás de las personas en la tercera persona del título?) y un punto adicional al cambiar la heurística de búsqueda «ly» y la comprobación de la presencia de números en el título (que podría ser menos válido en el caso general fuera de la prueba, así que dejé ambas soluciones)

Comentarios

  • No ‘ no sé acerca de la parte de papá … me parece un poco como optimizar el caso de prueba …
  • Y sí, puedo encontrar muchos artículos de Not the Onion que mencionan a los papás
  • Hay ‘ probablemente una mejor manera de hacerlo como parte de la heurística y no solo un duro » win » si contiene papá, pero me imagino que incluso fuera de la base de datos de prueba se habla de forma abstracta sobre un » Dad » es más común en The Onion
  • Su primera solución obtuvo un 64% en los casos de prueba ocultos, por lo que es válida. Su segunda solución obtuvo un 62,5% en los casos de prueba ocultos, por lo que no es válida.
  • @Mego Qué margen tan estrecho …

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *