Detección de noticias falsas con scikit-learn
Este tutorial de scikit-learn te guía paso a paso para crear un clasificador de noticias falsas con ayuda de modelos bayesianos.
· 15 min leer
Cursos de machine learning
Curso
Mejora tu machine learning con scikit-learn en Python. Haz predicciones potentes con conjuntos de datos reales en este curso interactivo.
Curso
Introducción al machine learning, ¡y no hay que programar!
Curso
¡Aprende a limpiar y preparar tus datos para el machine learning!
Detectar las llamadas “noticias falsas” no es tarea fácil. Para empezar, hay que definir qué es una noticia falsa, algo que hoy tiene una carga política evidente. Si consigues acordar una definición, tendrás que recopilar y etiquetar correctamente noticias reales y falsas (idealmente sobre temas similares para ver mejor las diferencias). Una vez recopiladas, deberás encontrar características útiles para distinguir noticias falsas de reales.
Para profundizar en este problema, te recomiendo el artículo de Miguel Martinez-Alvarez, “How can Machine Learning and AI Help Solve the Fake News Problem”.
Por la misma época en que leí el artículo de Miguel, me encontré con una entrada en Open Data Science sobre construir un detector de noticias falsas con modelos bayesianos. El autor incluso creó un repositorio con el conjunto de datos de noticias falsas y reales etiquetadas. Me picó la curiosidad por ver si podía reproducir fácilmente los resultados y, después, entender qué había aprendido el modelo.
En este tutorial, recorrerás conmigo parte de esa exploración inicial y verás si puedes construir un detector de noticias falsas que funcione.
Consejo: si quieres repasar los fundamentos del procesamiento del lenguaje natural (NLP), échale un ojo al curso Natural Language Processing Fundamentals in Python.
Exploración de datos
Para empezar, conviene echar un vistazo rápido a los datos y entender su contenido. Para ello, usa un DataFrame de Pandas, revisa su shape, head y aplica las transformaciones necesarias.
Extracción de los datos de entrenamiento
Ahora que el DataFrame tiene el aspecto que necesitas, separa las etiquetas y prepara los conjuntos de entrenamiento y prueba.
En este cuaderno decidí centrarme en usar el texto largo de los artículos. Como sabía que iba a utilizar bag-of-words y TF-IDF (frecuencia de término–frecuencia inversa de documento) para extraer características, parecía una buena elección. Usar texto más largo debería permitir que aparezcan palabras y rasgos distintivos entre mis datos de noticias reales y falsas.
Creación de clasificadores con vectorizadores
Ahora que ya tienes los datos de entrenamiento y prueba, puedes construir tus clasificadores. Para comprobar si las palabras y tokens de los artículos influyen de forma significativa en que la noticia sea falsa o real, empieza usando
CountVectorizeryTfidfVectorizer.Verás que el ejemplo fija un umbral máximo de
.7para el vectorizador TF-IDFtfidf_vectorizermediante el argumentomax_df. Esto elimina las palabras que aparecen en más del 70% de los artículos. Además, el parámetro integradostop_wordseliminará las stop words en inglés antes de crear los vectores.Hay muchos más parámetros disponibles y puedes consultarlos en la documentación de scikit-learn para
TfidfVectorizeryCountVectorizer.Con los vectores listos, puedes revisar las características de los vectores, almacenadas en
count_vectorizerytfidf_vectorizer.¿Ves algún problema llamativo? (¡Sí!)
Está claro que en el conjunto de datos hay comentarios, medidas u otras palabras sin sentido, además de artículos en varios idiomas. Normalmente dedicarías más tiempo al preprocesado y a eliminar ruido, pero como este tutorial es una pequeña prueba de concepto, veremos si el modelo es capaz de sobreponerse al ruido y clasificar correctamente a pesar de estos problemas.
Intermedio: características de recuento frente a TF-IDF
Me picaba la curiosidad por saber si mis vectorizadores de recuento y TF-IDF habían extraído tokens diferentes. Para comparar características, puedes volcar la información de los vectores a un DataFrame y usar comparaciones sencillas en Python.
Como verás al ejecutar las celdas, ambos vectorizadores extraen los mismos tokens, pero con pesos distintos. Probablemente, cambiar los
max_dfymin_dfdel vectorizador TF-IDF alteraría el resultado y daría lugar a características diferentes en cada uno.5 rows × 56922 columns
5 rows × 56922 columns
Comparación de modelos
Ahora toca entrenar y probar tus modelos.
Empezaremos con un clásico de NLP,
MultinomialNB. Nos servirá para comparar TF-IDF frente a bag-of-words. Mi intuición es que bag-of-words (es decir,CountVectorizer) funcionará mejor con este modelo. (Si quieres leer más sobre la distribución multinomial y por qué funciona mejor con enteros, aquí tienes una explicación bastante concisa de un curso de estadística de UPenn).Personalmente, me resulta más fácil comparar y leer matrices de confusión, así que usé la documentación de scikit-learn para generar unas matrices fáciles de interpretar (¡gracias, open source!). Una matriz de confusión muestra las etiquetas correctas en la diagonal principal (de arriba a la izquierda a abajo a la derecha). El resto de celdas muestran etiquetas incorrectas, a menudo llamadas falsos positivos o falsos negativos. Según el problema, una u otra puede ser más importante. Por ejemplo, en el problema de noticias falsas, ¿es más crítico no etiquetar como falsas las noticias reales? Si es así, quizá queramos ponderar la métrica de precisión para reflejar mejor esta preocupación.
Además de las matrices de confusión, scikit-learn incluye muchas formas de visualizar y comparar modelos. Una muy popular es usar la curva ROC. Hay muchas otras métricas para evaluar modelos en el módulo metrics de scikit-learn.
Y, efectivamente, sin ajustar parámetros, tu conjunto de entrenamiento vectorizado por recuento,
count_train, supera claramente a los vectores TF-IDF.Prueba de modelos lineales
Hay muchísimos artículos que explican por qué los modelos lineales funcionan bien con TF-IDF (mira word2vec para clasificación, la referencia a SVM en el análisis de texto de scikit-learn y muchos más).
Entonces, ¿deberías usar una SVM?
Pues bien, recientemente vi la clase de Victor Lavrenko sobre clasificación de texto, donde compara clasificadores Passive Aggressive con SVM lineales para texto. Vamos a probar este enfoque (con importantes ventajas de velocidad y desventajas de aprendizaje permanente) con el dataset de noticias falsas.
¡Vaya!
Impresiona. La matriz de confusión es distinta y el modelo clasifica un poco mejor las noticias falsas. Podemos probar si ajustar el valor de
alphaenMultinomialNBproduce resultados comparables. También puedes usar ajuste de parámetros con grid search para una búsqueda más exhaustiva.Casi, pero no... A estas alturas, podría ser interesante ajustar parámetros en todos los clasificadores o explorar otros clasificadores bayesianos de scikit-learn. También podrías probar con una máquina de vectores de soporte (SVM) para ver si supera al clasificador Passive Aggressive.
Pero me interesa más qué ha aprendido realmente el modelo Passive Aggressive. Pasemos a la introspección.
Introspección de modelos
Así que, ¿ya está resuelto lo de las noticias falsas? Hemos logrado un 93% de precisión en mi conjunto de datos, ¿cerramos y nos vamos?
Ni mucho menos. Estos resultados me generan cautela, sobre todo por el ruido que vimos en las características. Hay una gran respuesta en StackOverflow con una función muy útil para encontrar los vectores que más influyen en las etiquetas. Solo funciona para clasificación binaria (dos clases), pero eso nos viene bien: aquí solo hay FAKE o REAL.
Usando tu mejor clasificador con el conjunto TF-IDF (
tfidf_vectorizer) y el clasificador Passive Aggressive (linear_clf), inspecciona los 30 vectores principales para noticias falsas y reales:También puedes hacerlo de forma bastante directa con unas pocas líneas en Python, emparejando coeficientes y características y mirando la parte superior e inferior de la lista.
Está claro que hay ciertas palabras que pueden reflejar intencionalidad política y fuente entre las características destacadas de falsas (por ejemplo, corporate y establishment).
Además, en las noticias reales aparece con más frecuencia el verbo "to say", probablemente porque en periódicos y publicaciones periodísticas se citan fuentes directamente (“La canciller alemana Angela Merkel dijo…”).
Para extraer la lista completa de tu clasificador actual y revisar cada token (o comparar fácilmente tokens entre clasificadores), puedes exportarla así:
Intermedio: HashingVectorizer
Otro vectorizador que a veces se usa para clasificación de texto es
HashingVectorizer. LosHashingVectorizerrequieren menos memoria y son más rápidos (porque producen matrices dispersas y usan hashes en lugar de tokens), pero son más difíciles de inspeccionar. Si te interesa, puedes leer más sobre sus pros y contras en la documentación de scikit-learn:HashingVectorizer.Prueba a compararlo con los otros vectorizadores. Suele rendir bastante bien, con mejores resultados que TF-IDF usando
MultinomialNB(algo esperable por las mismas razones por las queCountVectorizerfunciona mejor), aunque no alcanza al TF-IDF con el algoritmo lineal Passive Aggressive.Conclusión
Entonces, ¿tu experimento de clasificador de noticias falsas ha sido un éxito? En absoluto.
Pero, ¿has podido trastear con un nuevo conjunto de datos, probar algunos modelos de clasificación NLP e inspeccionar qué tal funcionaban? Sí.
Como cabía esperar desde el principio, definir noticias falsas con un simple bag-of-words o TF-IDF es un enfoque demasiado simplificado. Más aún con un conjunto multilingüe lleno de ruido. Si no hubieras mirado qué aprendió realmente tu modelo, podrías haber pensado que había captado algo significativo. Así que recuerda: inspecciona siempre tus modelos (¡en la medida de lo posible!).
Me gustaría saber si encuentras otras tendencias en los datos que se me hayan pasado. Publicaré una continuación sobre cómo se comparan distintos clasificadores en cuanto a características importantes en mi blog. Si investigas y encuentras algo interesante, comparte tus hallazgos y notas en los comentarios o contáctame en Twitter (soy @kjam).
¡Espero que te hayas divertido explorando conmigo un nuevo dataset de NLP!
Echa un vistazo al tutorial de DataCamp Python Machine Learning: Scikit-Learn Tutorial.