Vea a continuación 50 tweets sobre "manzana". He etiquetado a mano las coincidencias positivas sobre Apple Inc. Están marcadas como 1 a continuación.
Aquí hay un par de líneas:
1|“@chrisgilmer: Apple targets big business with new iOS 7 features http://bit.ly/15F9JeF ”. Finally.. A corp iTunes account!
0|“@Zach_Paull: When did green skittles change from lime to green apple? #notafan” @Skittles
1|@dtfcdvEric: @MaroneyFan11 apple inc is searching for people to help and tryout all their upcoming tablet within our own net page No.
0|@STFUTimothy have you tried apple pie shine?
1|#SuryaRay #India Microsoft to bring Xbox and PC games to Apple, Android phones: Report: Microsoft Corp... http://dlvr.it/3YvbQx @SuryaRay
Aquí está el conjunto de datos total: http://pastebin.com/eJuEb4eB
Necesito construir un modelo que clasifique a "Apple" (Inc). del resto.
No estoy buscando una descripción general del aprendizaje automático, sino un modelo real en el código (se prefiere Python ).
Respuestas:
Lo haría de la siguiente manera:
fuente
Lo que busca se llama Reconocimiento de entidad nombrada . Es una técnica estadística que (más comúnmente) usa campos aleatorios condicionales para encontrar entidades con nombre, basándose en haber sido entrenado para aprender cosas sobre entidades con nombre.
Básicamente, analiza el contenido y el contexto de la palabra (mirando hacia atrás y hacia adelante algunas palabras) para estimar la probabilidad de que la palabra sea una entidad con nombre.
Un buen software puede observar otras características de las palabras, como su longitud o forma (como "Vcv" si comienza con "Vocal-consonante-vocal")
Una muy buena biblioteca (GPL) es la NER de Stanford
Aquí está la demostración: http://nlp.stanford.edu:8080/ner/
Algunos ejemplos de texto para probar:
(los clasificadores de 3 clases y 4 clases lo hacen bien)
fuente
english.conll.4class.distsim.crf.ser.gz
? Me encantaría ver cómo se construye algo como esto.Tengo un sistema semi-funcional que resuelve este problema, de código abierto usando scikit-learn, con una serie de publicaciones de blog que describen lo que estoy haciendo. El problema que estoy abordando es la desambiguación del sentido de las palabras (elegir una de las múltiples opciones de sentido de las palabras ), que no es lo mismo que el reconocimiento de entidades nombradas. Mi enfoque básico es algo competitivo con las soluciones existentes y (fundamentalmente) es personalizable.
Existen algunas herramientas comerciales de NER (OpenCalais, DBPedia Spotlight y AlchemyAPI) que pueden brindarle un resultado comercial suficientemente bueno. ¡Pruébelo primero!
Usé algunos de estos para un proyecto de cliente (consulto usando NLP / ML en Londres), pero no estaba contento con su recuperación ( precisión y recuperación ). Básicamente, pueden ser precisos (cuando dicen "Esto es Apple Inc" suelen ser correctos), pero con poca memoria (rara vez dicen "Esto es Apple Inc", aunque para un humano el tweet es obviamente sobre Apple Inc). Pensé que sería un ejercicio intelectualmente interesante crear una versión de código abierto adaptada a los tweets. Aquí está el código actual: https://github.com/ianozsvald/social_media_brand_disambiguator
Notaré: no estoy tratando de resolver el problema generalizado de desambiguación del sentido de las palabras con este enfoque, solo desambiguación de marca (empresas, personas, etc.) cuando ya tiene su nombre. Por eso creo que este enfoque sencillo funcionará.
Comencé esto hace seis semanas y está escrito en Python 2.7 usando scikit-learn. Utiliza un enfoque muy básico. Vectorizo usando un vectorizador de conteo binario (solo cuento si aparece una palabra, no cuántas veces) con 1-3 n-gramos . No escalo con TF-IDF (TF-IDF es bueno cuando tiene un documento de longitud variable; para mí, los tweets son solo una o dos oraciones, y los resultados de mis pruebas no mostraron mejoras con TF-IDF).
Utilizo el tokenizador básico que es muy básico pero sorprendentemente útil. Ignora @ # (por lo que pierde algo de contexto) y, por supuesto, no expande una URL. Luego entreno usando regresión logística , y parece que este problema es algo linealmente separable (muchos términos para una clase no existen para la otra). Actualmente estoy evitando cualquier extracción / limpieza (estoy probando la cosa más simple posible que podría funcionar).
El código tiene un README completo, y debería poder ingerir sus tweets con relativa facilidad y luego seguir mis sugerencias para la prueba.
Esto funciona para Apple, ya que la gente no come ni bebe computadoras Apple, ni escribimos ni jugamos con frutas, por lo que las palabras se dividen fácilmente en una categoría u otra. Es posible que esta condición no se mantenga al considerar algo como #definanciamiento para el programa de televisión (donde la gente también usa #definanciamiento en relación con la Primavera Árabe, partidos de cricket, revisión de exámenes y una banda de música). Es posible que aquí se requieran enfoques más inteligentes.
Tengo una serie de publicaciones en el blog que describen este proyecto, incluida una presentación de una hora que di en el grupo de usuarios de BrightonPython (que se convirtió en una presentación más corta para 140 personas en DataScienceLondon).
Si usa algo como LogisticRegression (donde obtiene una probabilidad para cada clasificación), puede elegir solo las clasificaciones confiables, y de esa manera puede forzar una alta precisión al negociar contra el recuerdo (para obtener resultados correctos, pero menos). Tendrá que ajustar esto a su sistema.
Aquí hay un posible enfoque algorítmico usando scikit-learn:
Cosas para considerar:
Re. sobreajuste. En mi conjunto de datos con 2000 elementos, tengo una instantánea de 10 minutos de Twitter de los tweets de 'apple'. Aproximadamente 2/3 de los tweets son para Apple Inc, 1/3 para otros usos de Apple. Saco un subconjunto equilibrado (aproximadamente 584 filas, creo) de cada clase y hago una validación cruzada de cinco veces para el entrenamiento.
Dado que solo tengo una ventana de tiempo de 10 minutos, tengo muchos tweets sobre el mismo tema, y esta es probablemente la razón por la que mi clasificador funciona tan bien en relación con las herramientas existentes: se habrá sobreajustado a las funciones de entrenamiento sin generalizar bien (mientras que el comercial existente las herramientas funcionan peor en esta tienda de instantáneas, pero de manera más confiable en un conjunto más amplio de datos). Ampliaré mi ventana de tiempo para probar esto como un trabajo posterior.
fuente
Puede hacer lo siguiente:
Haga un dictado de palabras que contengan su recuento de ocurrencia en tweets relacionados con frutas y empresas. Esto se puede lograr alimentándolo con algunos tweets de muestra cuya inclinación conocemos.
Utilizando suficientes datos anteriores, podemos averiguar la probabilidad de que aparezca una palabra en un tweet sobre apple inc.
Multiplica las probabilidades individuales de las palabras para obtener la probabilidad del tweet completo.
Un ejemplo simplificado:
p_f = Probabilidad de tweets de frutas.
p_w_f = Probabilidad de que aparezca una palabra en un tweet de frutas.
p_t_f = Probabilidad combinada de que todas las palabras del tweet ocurran un tweet de frutas = p_w1_f * p_w2_f * ...
p_f_t = Probabilidad de fruta dado un tweet en particular.
p_c, p_w_c, p_t_c, p_c_t son valores respectivos para la empresa.
Se agrega un suavizador laplaciano de valor 1 para eliminar el problema de frecuencia cero de palabras nuevas que no están en nuestra base de datos.
old_tweets = {'apple pie sweet potatoe cake baby https://vine.co/v/hzBaWVA3IE3': '0', ...} known_words = {} total_company_tweets = total_fruit_tweets =total_company_words = total_fruit_words = 0 for tweet in old_tweets: company = old_tweets[tweet] for word in tweet.lower().split(" "): if not word in known_words: known_words[word] = {"company":0, "fruit":0 } if company == "1": known_words[word]["company"] += 1 total_company_words += 1 else: known_words[word]["fruit"] += 1 total_fruit_words += 1 if company == "1": total_company_tweets += 1 else: total_fruit_tweets += 1 total_tweets = len(old_tweets) def predict_tweet(new_tweet,K=1): p_f = (total_fruit_tweets+K)/(total_tweets+K*2) p_c = (total_company_tweets+K)/(total_tweets+K*2) new_words = new_tweet.lower().split(" ") p_t_f = p_t_c = 1 for word in new_words: try: wordFound = known_words[word] except KeyError: wordFound = {'fruit':0,'company':0} p_w_f = (wordFound['fruit']+K)/(total_fruit_words+K*(len(known_words))) p_w_c = (wordFound['company']+K)/(total_company_words+K*(len(known_words))) p_t_f *= p_w_f p_t_c *= p_w_c #Applying bayes rule p_f_t = p_f * p_t_f/(p_t_f*p_f + p_t_c*p_c) p_c_t = p_c * p_t_c/(p_t_f*p_f + p_t_c*p_c) if p_c_t > p_f_t: return "Company" return "Fruit"
fuente
Si no tiene problemas para usar una biblioteca externa, le recomiendo scikit-learn, ya que probablemente pueda hacer esto mejor y más rápido que cualquier cosa que pueda codificar usted mismo. Solo haría algo como esto:
Construye tu corpus. Hice las comprensiones de la lista para mayor claridad, pero dependiendo de cómo se almacenan sus datos, es posible que deba hacer cosas diferentes:
def corpus_builder(apple_inc_tweets, apple_fruit_tweets): corpus = [tweet for tweet in apple_inc_tweets] + [tweet for tweet in apple_fruit_tweets] labels = [1 for x in xrange(len(apple_inc_tweets))] + [0 for x in xrange(len(apple_fruit_tweets))] return (corpus, labels)
Lo importante es que terminas con dos listas que se ven así:
([['apple inc tweet i love ios and iphones'], ['apple iphones are great'], ['apple fruit tweet i love pie'], ['apple pie is great']], [1, 1, 0, 0])
[1, 1, 0, 0] representan las etiquetas positivas y negativas.
Luego, ¡crea un Pipeline! Pipeline es una clase de scikit-learn que facilita encadenar los pasos de procesamiento de texto para que solo tenga que llamar a un objeto al entrenar / predecir:
def train(corpus, labels) pipe = Pipeline([('vect', CountVectorizer(ngram_range=(1, 3), stop_words='english')), ('tfidf', TfidfTransformer(norm='l2')), ('clf', LinearSVC()),]) pipe.fit_transform(corpus, labels) return pipe
Dentro del Pipeline hay tres pasos de procesamiento. CountVectorizer tokeniza las palabras, las divide, las cuenta y transforma los datos en una matriz dispersa. El TfidfTransformer es opcional, y es posible que desee eliminarlo dependiendo de la calificación de precisión (hacer pruebas de validación cruzada y una búsqueda en cuadrícula de los mejores parámetros es un poco complicado, por lo que no entraré en él aquí). LinearSVC es un algoritmo de clasificación de texto estándar.
Finalmente, predice la categoría de tweets:
def predict(pipe, tweet): prediction = pipe.predict([tweet]) return prediction
Nuevamente, el tweet debe estar en una lista, así que asumí que ingresaba a la función como una cadena.
Ponlos todos en una clase o lo que sea, y listo. Al menos, con este ejemplo muy básico.
No probé este código, por lo que es posible que no funcione si solo copia y pega, pero si desea usar scikit-learn, debería darle una idea de por dónde empezar.
EDITAR: intenté explicar los pasos con más detalle.
fuente
El uso de un árbol de decisiones parece funcionar bastante bien para este problema. Al menos produce una mayor precisión que un clasificador bayes ingenuo con mis características elegidas.
Si desea jugar con algunas posibilidades, puede usar el siguiente código, que requiere que nltk esté instalado. El libro nltk también está disponible gratuitamente en línea, por lo que es posible que desee leer un poco sobre cómo funciona todo esto: http://nltk.googlecode.com/svn/trunk/doc/book/ch06.html
#coding: utf-8 import nltk import random import re def get_split_sets(): structured_dataset = get_dataset() train_set = set(random.sample(structured_dataset, int(len(structured_dataset) * 0.7))) test_set = [x for x in structured_dataset if x not in train_set] train_set = [(tweet_features(x[1]), x[0]) for x in train_set] test_set = [(tweet_features(x[1]), x[0]) for x in test_set] return (train_set, test_set) def check_accurracy(times=5): s = 0 for _ in xrange(times): train_set, test_set = get_split_sets() c = nltk.classify.DecisionTreeClassifier.train(train_set) # Uncomment to use a naive bayes classifier instead #c = nltk.classify.NaiveBayesClassifier.train(train_set) s += nltk.classify.accuracy(c, test_set) return s / times def remove_urls(tweet): tweet = re.sub(r'http:\/\/[^ ]+', "", tweet) tweet = re.sub(r'pic.twitter.com/[^ ]+', "", tweet) return tweet def tweet_features(tweet): words = [x for x in nltk.tokenize.wordpunct_tokenize(remove_urls(tweet.lower())) if x.isalpha()] features = dict() for bigram in nltk.bigrams(words): features["hasBigram(%s)" % ",".join(bigram)] = True for trigram in nltk.trigrams(words): features["hasTrigram(%s)" % ",".join(trigram)] = True return features def get_dataset(): dataset = """copy dataset in here """ structured_dataset = [('fruit' if x[0] == '0' else 'company', x[2:]) for x in dataset.splitlines()] return structured_dataset if __name__ == '__main__': print check_accurracy()
fuente
dict()
otro lugar? Creo que si el conjunto de entrenamiento de uno es lo suficientemente grande, ¿no debería una computadora ser capaz de descubrir las características por sí misma? (¿sin supervisión?)'hasBigram(foo,bar)' = True
dónde se incluye la cadena de tweetsfoo bar
? Entonces, ¿crea bigrams y trigramas para cada tweet y lo marca en la característica positivadict()
? Por lo tanto, dado el tweet,"alpha beta gamma delta"
construirá dict () bigramsalpha,beta; beta,gamma; and gamma,delta;
y trigrams paraalpha,beta,gamma
ybeta,gamma,delta
? ¿Y a partir de los bi y tri gramas positivos y negativos dados, los clasificadores de árbol de decisión o bayes pueden hacer su magia?Gracias por los comentarios hasta ahora. Aquí hay una solución funcional que preparé con PHP. Todavía estaría interesado en escuchar de otros un enfoque más algorítmico para esta misma solución.
<?php // Confusion Matrix Init $tp = 0; $fp = 0; $fn = 0; $tn = 0; $arrFP = array(); $arrFN = array(); // Load All Tweets to string $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'http://pastebin.com/raw.php?i=m6pP8ctM'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $strCorpus = curl_exec($ch); curl_close($ch); // Load Tweets as Array $arrCorpus = explode("\n", $strCorpus); foreach ($arrCorpus as $k => $v) { // init $blnActualClass = substr($v,0,1); $strTweet = trim(substr($v,2)); // Score Tweet $intScore = score($strTweet); // Build Confusion Matrix and Log False Positives & Negatives for Review if ($intScore > 0) { if ($blnActualClass == 1) { // True Positive $tp++; } else { // False Positive $fp++; $arrFP[] = $strTweet; } } else { if ($blnActualClass == 1) { // False Negative $fn++; $arrFN[] = $strTweet; } else { // True Negative $tn++; } } } // Confusion Matrix and Logging echo " Predicted 1 0 Actual 1 $tp $fp Actual 0 $fn $tn "; if (count($arrFP) > 0) { echo "\n\nFalse Positives\n"; foreach ($arrFP as $strTweet) { echo "$strTweet\n"; } } if (count($arrFN) > 0) { echo "\n\nFalse Negatives\n"; foreach ($arrFN as $strTweet) { echo "$strTweet\n"; } } function LoadDictionaryArray() { $strDictionary = <<<EOD 10|iTunes 10|ios 7 10|ios7 10|iPhone 10|apple inc 10|apple corp 10|apple.com 10|MacBook 10|desk top 10|desktop 1|config 1|facebook 1|snapchat 1|intel 1|investor 1|news 1|labs 1|gadget 1|apple store 1|microsoft 1|android 1|bonds 1|Corp.tax 1|macs -1|pie -1|clientes -1|green apple -1|banana -10|apple pie EOD; $arrDictionary = explode("\n", $strDictionary); foreach ($arrDictionary as $k => $v) { $arr = explode('|', $v); $arrDictionary[$k] = array('value' => $arr[0], 'term' => strtolower(trim($arr[1]))); } return $arrDictionary; } function score($str) { $str = strtolower($str); $intScore = 0; foreach (LoadDictionaryArray() as $arrDictionaryItem) { if (strpos($str,$arrDictionaryItem['term']) !== false) { $intScore += $arrDictionaryItem['value']; } } return $intScore; } ?>
Los resultados anteriores:
Predicted 1 0 Actual 1 31 1 Actual 0 1 17 False Positives 1|Royals apple #ASGame @mlb @ News Corp Building http://instagram.com/p/bBzzgMrrIV/ False Negatives -1|RT @MaxFreixenet: Apple no tiene clientes. Tiene FANS// error.... PAGAS por productos y apps, ergo: ERES CLIENTE.
fuente
En todos los ejemplos que proporcionó, se hizo referencia a Apple (inc) como A pple o apple inc , por lo que una posible forma podría ser buscar:
una "A" mayúscula en Apple
un "inc" después de apple
palabras / frases como "SO", "sistema operativo", "Mac", "iPhone", ...
o una combinación de ellos
fuente
Para simplificar un poco las respuestas basadas en campos aleatorios condicionales ... el contexto es enorme aquí. Querrá destacar en esos tweets que muestran claramente a Apple la empresa frente a Apple la fruta. Permítanme esbozar una lista de características aquí que podrían ser útiles para comenzar. Para obtener más información, busque fragmentación de frases nominales y algo llamado etiquetas BIO. Ver ( http://www.cis.upenn.edu/~pereira/papers/crf.pdf )
Palabras circundantes: cree un vector de características para la palabra anterior y la siguiente, o si desea más características, tal vez las 2 palabras anteriores y las 2 siguientes. No desea demasiadas palabras en el modelo o no coincidirá muy bien con los datos. En Procesamiento del lenguaje natural, querrá mantener esto lo más general posible.
Otras características que se pueden obtener de las palabras circundantes son las siguientes:
Si el primer carácter es mayúscula
Si el último carácter de la palabra es un punto.
La parte gramatical de la palabra (busque el etiquetado de parte gramatical)
El texto mismo de la palabra
No recomiendo esto, pero para dar más ejemplos de funciones específicamente para Apple:
WordIs (Apple)
NextWordIs (Inc.)
Tú entiendes. Piense en el reconocimiento de entidades nombradas como una descripción de una secuencia y luego use algunas matemáticas para decirle a una computadora cómo calcular eso.
Tenga en cuenta que el procesamiento del lenguaje natural es un sistema basado en canalizaciones. Por lo general, divide las cosas en oraciones, pasa a la tokenización y luego realiza parte del etiquetado de voz o incluso el análisis de dependencia.
Todo esto es para obtener una lista de características que puede usar en su modelo para identificar lo que está buscando.
fuente
Hay una biblioteca realmente buena para procesar texto en lenguaje natural en Python llamada
nltk
. Deberías echarle un vistazo.Una estrategia que podría probar es mirar n-gramas (grupos de palabras) con la palabra "manzana" en ellos. Es más probable que algunas palabras se usen junto a "manzana" cuando se habla de la fruta, otras cuando se habla de la empresa, y puede usarlas para clasificar los tweets.
fuente
nltk
) que pueda ayudarme a comenzar en la dirección correcta con una tarea de aprendizaje automático de "hola mundo". La manzana (inc) contra la manzana (fruta) parece una asignación perfecta.Utilice LibShortText . Esta utilidad de Python ya se ha ajustado para que funcione en tareas de categorización de texto corto y funciona bien. Lo máximo que tendrá que hacer es escribir un bucle para elegir la mejor combinación de banderas. Lo usé para hacer una clasificación supervisada de actos de habla en correos electrónicos y los resultados fueron hasta un 95-97% precisos (¡durante 5 veces la validación cruzada!).
Y proviene de los creadores de LIBSVM y LIBLINEAR, cuya implementación de máquina de vectores de soporte (SVM) se usa en sklearn y cran, por lo que puede estar razonablemente seguro de que su implementación no tiene errores.
fuente
Haga un filtro de inteligencia artificial para distinguir Apple Inc (la empresa) de la manzana (la fruta). Dado que estos son tweets, defina su conjunto de entrenamiento con un vector de 140 campos, cada campo es el carácter escrito en el tweet en la posición X (0 a 139). Si el tweet es más corto, simplemente dé un valor para estar en blanco.
Luego, construya un conjunto de entrenamiento lo suficientemente grande para obtener una buena precisión (subjetiva a su gusto). Asigne un valor de resultado a cada tweet, un tweet de Apple Inc obtiene 1 (verdadero) y un tweet de manzana (fruta) obtiene 0. Sería un caso de aprendizaje supervisado en una regresión logística .
Eso es aprendizaje automático, generalmente es más fácil de codificar y funciona mejor. Tiene que aprender del conjunto que le da, y no está codificado.
No conozco Python , por lo que no puedo escribir el código para él, pero si se tomara más tiempo para la lógica y la teoría del aprendizaje automático, es posible que desee ver la clase que estoy siguiendo.
Prueba el curso de Coursera Machine Learning de Andrew Ng . Aprenderá el aprendizaje automático en MATLAB u Octave , pero una vez que obtenga los conceptos básicos, podrá escribir el aprendizaje automático en cualquier idioma si comprende las matemáticas simples (simple en regresión logística).
Es decir, obtener el código de alguien no le permitirá comprender lo que está sucediendo en el código de aprendizaje automático. Es posible que desee invertir un par de horas en el tema para ver qué está pasando realmente.
fuente
Recomendaría evitar respuestas que sugieran reconocimiento de entidad. Porque esta tarea es una clasificación de texto primero y un reconocimiento de entidad en segundo lugar (puede hacerlo sin el reconocimiento de entidad).
Creo que el camino más rápido hacia los resultados será Spacy + Prodigy . Spacy tiene un modelo bien pensado para el idioma inglés, por lo que no tienes que construir el tuyo propio. Mientras que prodigy permite crear rápidamente conjuntos de datos de entrenamiento y ajustar el modelo de espacio para sus necesidades.
Si tiene suficientes muestras, puede tener un modelo decente en 1 día.
fuente
spaCy
tienener
componente de tubería, ¿no sería beneficioso para esta clasificación? Supongo que su modelo puede reconocerApple
(ya que es una de las empresas más grandes y conocidas del mundo) mucho mejor que un modelo que se le ocurra en un día.spacy.Doc
partir de cada texto, repita sus NER condoc.ents
y verifique si algún NER tiene un.text
atributo igual aApple
. Dato curioso, su primer ejemplo consiste en Apple.