Voir ci-dessous 50 tweets sur "apple". J'ai étiqueté à la main les correspondances positives sur Apple Inc. Ils sont marqués comme 1 ci-dessous.
Voici quelques lignes:
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
Voici l'ensemble de données total: http://pastebin.com/eJuEb4eB
J'ai besoin de construire un modèle qui classe "Apple" (Inc). du reste.
Je ne cherche pas un aperçu général de l'apprentissage automatique, mais plutôt un modèle réel dans le code ( Python préféré).
Réponses:
Je le ferais comme suit:
la source
Ce que vous recherchez s'appelle la reconnaissance d'entités nommées . C'est une technique statistique qui utilise (le plus souvent) des champs aléatoires conditionnels pour trouver des entités nommées, en se basant sur le fait d'avoir été formé pour apprendre des choses sur les entités nommées.
Essentiellement, il examine le contenu et le contexte du mot, (en regardant en arrière et en avant quelques mots), pour estimer la probabilité que le mot soit une entité nommée.
Un bon logiciel peut examiner d'autres caractéristiques des mots, telles que leur longueur ou leur forme (comme "Vcv" s'il commence par "voyelle-consonne-voyelle")
Une très bonne bibliothèque (GPL) est le NER de Stanford
Voici la démo: http://nlp.stanford.edu:8080/ner/
Quelques exemples de texte à essayer:
(les classificateurs 3class et 4class font les choses correctement)
la source
english.conll.4class.distsim.crf.ser.gz
? J'adorerais voir comment on construit quelque chose comme ça.J'ai un système semi-fonctionnel qui résout ce problème, open source en utilisant scikit-learn, avec une série d'articles de blog décrivant ce que je fais. Le problème que j'aborde est la désambiguïsation du sens des mots (en choisissant l'une des multiples options de sens des mots ), qui n'est pas la même chose que la reconnaissance d'entités nommées. Mon approche de base est quelque peu compétitive avec les solutions existantes et (surtout) personnalisable.
Il existe des outils NER commerciaux existants (OpenCalais, DBPedia Spotlight et AlchemyAPI) qui pourraient vous donner un résultat commercial assez bon - essayez-les d'abord!
J'en ai utilisé certains pour un projet client (je consulte en NLP / ML à Londres), mais je n'étais pas satisfait de leur rappel ( précision et rappel ). Fondamentalement, ils peuvent être précis (quand ils disent "Ceci est Apple Inc", ils ont généralement raison), mais avec un faible rappel (ils disent rarement "Ceci est Apple Inc." même si pour un humain le tweet concerne évidemment Apple Inc.). J'ai pensé que ce serait un exercice intellectuellement intéressant de créer une version open source adaptée aux tweets. Voici le code actuel: https://github.com/ianozsvald/social_media_brand_disambiguator
Je note - je n'essaye pas de résoudre le problème généralisé de désambiguïsation du sens des mots avec cette approche, juste la marque désambiguïsation de la (entreprises, personnes, etc.) lorsque vous avez déjà leur nom. C'est pourquoi je pense que cette approche simple fonctionnera.
J'ai commencé cela il y a six semaines et il est écrit en Python 2.7 en utilisant scikit-learn. Il utilise une approche très basique. Je vectorise à l'aide d'un vectoriseur de comptage binaire (je ne compte que si un mot apparaît, pas combien de fois) avec 1 à 3 n-grammes . Je ne mets pas à l'échelle avec TF-IDF (TF-IDF est bien lorsque vous avez une longueur de document variable; pour moi, les tweets ne sont qu'une ou deux phrases, et mes résultats de test n'ont pas montré d'amélioration avec TF-IDF).
J'utilise le tokenizer de base qui est très basique mais étonnamment utile. Il ignore @ # (vous perdez donc un peu de contexte) et, bien sûr, ne développe pas une URL. Je m'entraîne ensuite en utilisant la régression logistique , et il semble que ce problème soit quelque peu linéairement séparable (beaucoup de termes pour une classe n'existent pas pour l'autre). Actuellement, j'évite tout raclage / nettoyage (j'essaie la chose la plus simple possible qui pourrait fonctionner).
Le code a un fichier README complet, et vous devriez pouvoir ingérer vos tweets relativement facilement, puis suivre mes suggestions de test.
Cela fonctionne pour Apple car les gens ne mangent ni ne boivent d'ordinateurs Apple, et nous ne tapons ni ne jouons avec des fruits, de sorte que les mots sont facilement divisés en une catégorie ou une autre. Cette condition peut ne pas tenir lorsque l'on considère quelque chose comme #definance pour l'émission de télévision (où les gens utilisent également #definance en relation avec le printemps arabe, les matchs de cricket, la révision d'examen et un groupe de musique). Des approches plus intelligentes pourraient bien être nécessaires ici.
J'ai une série d'articles de blog décrivant ce projet, y compris une présentation d'une heure que j'ai donnée au groupe d'utilisateurs BrightonPython (qui s'est transformée en une présentation plus courte pour 140 personnes à DataScienceLondon).
Si vous utilisez quelque chose comme LogisticRegression (où vous obtenez une probabilité pour chaque classification), vous ne pouvez choisir que les classifications fiables, et de cette façon, vous pouvez forcer une haute précision en échangeant contre le rappel (vous obtenez ainsi des résultats corrects, mais moins nombreux). Vous devrez l'adapter à votre système.
Voici une approche algorithmique possible utilisant scikit-learn:
Choses à considérer:
Ré. sur-ajustement. Dans mon ensemble de données avec 2000 éléments, j'ai un instantané de 10 minutes sur Twitter des tweets «apple». Environ 2/3 des tweets sont pour Apple Inc, 1/3 pour d'autres usages Apple. Je tire un sous-ensemble équilibré (environ 584 lignes je pense) de chaque classe et fais une validation croisée de cinq fois pour la formation.
Comme je n'ai qu'une fenêtre de temps de 10 minutes, j'ai beaucoup de tweets sur le même sujet, et c'est probablement pourquoi mon classificateur se débrouille si bien par rapport aux outils existants - il aura sur-ajusté les fonctionnalités de formation sans bien généraliser (alors que le commercial existant les outils fonctionnent moins bien sur ce snapshop, mais de manière plus fiable sur un ensemble plus large de données). Je vais élargir ma fenêtre de temps pour tester cela comme un travail ultérieur.
la source
Vous pouvez faire ce qui suit:
Faites un dict de mots contenant leur nombre d'occurrences dans les tweets liés aux fruits et à l'entreprise. Cela peut être réalisé en lui donnant quelques exemples de tweets dont nous connaissons l'inclinaison.
En utilisant suffisamment de données antérieures, nous pouvons connaître la probabilité qu'un mot apparaisse dans un tweet à propos de apple inc.
Multipliez les probabilités individuelles des mots pour obtenir la probabilité de tout le tweet.
Un exemple simplifié:
p_f = Probabilité de tweets de fruits.
p_w_f = Probabilité qu'un mot apparaisse dans un tweet de fruits.
p_t_f = Probabilité combinée de tous les mots du tweet sur un tweet de fruits = p_w1_f * p_w2_f * ...
p_f_t = Probabilité de fruit étant donné un tweet particulier.
p_c, p_w_c, p_t_c, p_c_t sont des valeurs respectives pour l'entreprise.
Un lisseur laplacien de valeur 1 est ajouté pour éliminer le problème de la fréquence zéro des nouveaux mots qui ne sont pas là dans notre base de données.
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"
la source
Si vous ne rencontrez pas de problème lors de l'utilisation d'une bibliothèque externe, je vous recommande scikit-learn car il peut probablement le faire mieux et plus rapidement que tout ce que vous pourriez coder vous-même. Je ferais juste quelque chose comme ça:
Construisez votre corpus. J'ai fait la liste des compréhensions pour plus de clarté, mais en fonction de la façon dont vos données sont stockées, vous devrez peut-être faire différentes choses:
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)
L'important est que vous vous retrouvez avec deux listes qui ressemblent à ceci:
([['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])
Les [1, 1, 0, 0] représentent les étiquettes positives et négatives.
Ensuite, vous créez un pipeline! Pipeline est une classe scikit-learn qui facilite l'enchaînement des étapes de traitement de texte afin que vous n'ayez à appeler qu'un seul objet lors de l'apprentissage / de la prédiction:
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
À l'intérieur du pipeline, il y a trois étapes de traitement. Le CountVectorizer tokenise les mots, les divise, les compte et transforme les données en une matrice clairsemée. Le TfidfTransformer est facultatif, et vous voudrez peut-être le supprimer en fonction de la note de précision (faire des tests de validation croisée et une recherche de grille pour les meilleurs paramètres est un peu impliqué, donc je ne vais pas y entrer ici). Le LinearSVC est un algorithme de classification de texte standard.
Enfin, vous prédisez la catégorie des tweets:
def predict(pipe, tweet): prediction = pipe.predict([tweet]) return prediction
Encore une fois, le tweet doit être dans une liste, j'ai donc supposé qu'il entrait la fonction sous forme de chaîne.
Mettez tout cela dans une classe ou autre, et vous avez terminé. Du moins, avec cet exemple très basique.
Je n'ai pas testé ce code, il peut donc ne pas fonctionner si vous faites simplement un copier-coller, mais si vous souhaitez utiliser scikit-learn, cela devrait vous donner une idée de par où commencer.
EDIT: essayé d'expliquer les étapes plus en détail.
la source
L'utilisation d'un arbre de décision semble fonctionner assez bien pour ce problème. Au moins, il produit une précision plus élevée qu'un classificateur bayésien naïf avec les fonctionnalités que j'ai choisies.
Si vous voulez jouer avec certaines possibilités, vous pouvez utiliser le code suivant, qui nécessite l'installation de nltk. Le livre nltk est également disponible gratuitement en ligne, vous voudrez peut-être lire un peu comment tout cela fonctionne réellement: 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()
la source
dict()
ailleurs? Je pense que si l'ensemble de formation est assez grand, un ordinateur ne devrait-il pas être capable de comprendre les fonctionnalités lui-même? (non supervisé?)'hasBigram(foo,bar)' = True
où la chaîne de tweet comprend-ellefoo bar
? Donc, il construit des bigrammes et des trigrammes pour chaque tweet et le signale dans la fonction positivedict()
? Par conséquent, étant donné le tweet,"alpha beta gamma delta"
il construira des bigrammes dict () pouralpha,beta; beta,gamma; and gamma,delta;
et des trigrammes pouralpha,beta,gamma
etbeta,gamma,delta
? Et à partir des bi et tri grammes positifs et négatifs donnés, l'arbre de décision ou les classificateurs bayes peuvent faire leur magie?Merci pour les commentaires jusqu'ici. Voici une solution de travail que j'ai préparée avec PHP. Je serais toujours intéressé d'entendre des autres une approche plus algorithmique de cette même solution.
<?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; } ?>
Les sorties ci-dessus:
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.
la source
Dans tous les exemples que vous avez donnés, Apple (inc) était soit appelé A pple soit apple inc , donc un moyen possible pourrait être de rechercher:
un «A» majuscule dans Apple
un "inc" après la pomme
des mots / expressions comme "OS", "système d'exploitation", "Mac", "iPhone", ...
ou une combinaison d'entre eux
la source
Pour simplifier un peu les réponses basées sur les champs aléatoires conditionnels ... le contexte est énorme ici. Vous voudrez choisir dans ces tweets qui montrent clairement à Apple la société contre Apple le fruit. Permettez-moi de présenter ici une liste de fonctionnalités qui pourraient vous être utiles pour commencer. Pour plus d'informations, recherchez la segmentation des phrases nominales et quelque chose appelé étiquettes BIO. Voir ( http://www.cis.upenn.edu/~pereira/papers/crf.pdf )
Mots environnants: créez un vecteur de caractéristiques pour le mot précédent et le mot suivant, ou si vous voulez plus de caractéristiques, peut-être les 2 mots précédents et les 2 suivants. Vous ne voulez pas trop de mots dans le modèle ou il ne correspondra pas très bien aux données. Dans le traitement du langage naturel, vous voudrez garder cela aussi général que possible.
Les autres fonctionnalités à tirer des mots environnants sont les suivantes:
Si le premier caractère est une majuscule
Si le dernier caractère du mot est un point
La partie du discours du mot (Rechercher une partie du balisage de la parole)
Le texte lui-même du mot
Je ne le conseille pas, mais pour donner plus d'exemples de fonctionnalités spécifiquement pour Apple:
WordIs (Apple)
NextWordIs (Inc.)
Tu obtiens le point. Pensez à la reconnaissance d'entités nommées comme décrivant une séquence, puis utilisez des mathématiques pour indiquer à un ordinateur comment calculer cela.
Gardez à l'esprit que le traitement du langage naturel est un système basé sur un pipeline. En règle générale, vous divisez les choses en phrases, passez à la tokenisation, puis effectuez une partie du balisage vocal ou même de l'analyse des dépendances.
Tout cela pour vous donner une liste des fonctionnalités que vous pouvez utiliser dans votre modèle pour identifier ce que vous recherchez.
la source
Il existe une très bonne bibliothèque pour traiter du texte en langage naturel en Python appelée
nltk
. Vous devriez y jeter un œil.Une stratégie que vous pourriez essayer est de regarder les n-grammes (groupes de mots) avec le mot «pomme» en eux. Certains mots sont plus susceptibles d'être utilisés à côté de "pomme" lorsque vous parlez du fruit, d'autres lorsque vous parlez de l'entreprise, et vous pouvez les utiliser pour classer les tweets.
la source
nltk
) qui peut m'aider à démarrer dans la bonne direction avec une tâche d'apprentissage automatique "bonjour le monde". La pomme (inc) contre la pomme (fruit) semble être une affectation parfaite.Utilisez LibShortText . Cet utilitaire Python a déjà été réglé pour fonctionner pour de courtes tâches de catégorisation de texte, et il fonctionne bien. Le maximum que vous aurez à faire est d'écrire une boucle pour choisir la meilleure combinaison d'indicateurs. Je l'ai utilisé pour faire une classification supervisée des actes de parole dans les e-mails et les résultats étaient jusqu'à 95-97% précis (lors de la validation croisée 5 fois!).
Et il vient des créateurs de LIBSVM et LIBLINEAR dont l' implémentation de la machine vectorielle de support (SVM) est utilisée dans sklearn et cran, vous pouvez donc être raisonnablement assuré que leur implémentation n'est pas boguée.
la source
Créez un filtre AI pour distinguer Apple Inc (la société) de la pomme (le fruit). Puisqu'il s'agit de tweets, définissez votre ensemble d'entraînement avec un vecteur de 140 champs, chaque champ étant le caractère écrit dans le tweet à la position X (0 à 139). Si le tweet est plus court, donnez simplement une valeur pour être vide.
Ensuite, construisez un ensemble d'entraînement suffisamment grand pour obtenir une bonne précision (subjective à votre goût). Attribuez une valeur de résultat à chaque tweet, un tweet Apple Inc obtient 1 (vrai) et un tweet pomme (fruit) obtient 0. Ce serait un cas d' apprentissage supervisé dans une régression logistique .
C'est l'apprentissage automatique, est généralement plus facile à coder et fonctionne mieux. Il doit apprendre de l'ensemble que vous lui donnez, et il n'est pas codé en dur.
Je ne connais pas Python , donc je ne peux pas écrire le code pour cela, mais si vous deviez prendre plus de temps pour la logique et la théorie de l'apprentissage automatique, vous voudrez peut-être regarder la classe que je suis.
Essayez le cours Coursera Machine Learning par Andrew Ng . Vous apprendrez l'apprentissage automatique sur MATLAB ou Octave , mais une fois que vous aurez les bases, vous serez en mesure d'écrire l'apprentissage automatique dans n'importe quelle langue si vous comprenez les mathématiques simples (simples en régression logistique).
Autrement dit, obtenir le code de quelqu'un ne vous permettra pas de comprendre ce qui se passe dans le code d'apprentissage automatique. Vous voudrez peut-être investir quelques heures sur le sujet pour voir ce qui se passe réellement.
la source
Je recommanderais d'éviter les réponses suggérant la reconnaissance des entités. Parce que cette tâche est d'abord une classification de texte et une reconnaissance d'entité en second lieu (vous pouvez le faire sans la reconnaissance d'entité du tout).
Je pense que le chemin le plus rapide vers les résultats sera spacy + prodigy . Spacy a bien pensé un modèle pour la langue anglaise, vous n'avez donc pas à créer le vôtre. Alors que prodigy permet de créer rapidement des ensembles de données d'entraînement et d'ajuster le modèle Spacy en fonction de vos besoins.
Si vous avez suffisamment d'échantillons, vous pouvez avoir un modèle décent en 1 jour.
la source
spaCy
est-ce que lener
composant pipeline est- il utile pour cette classification? Je suppose que leur modèle peut reconnaîtreApple
(car c'est l'une des entreprises les plus grandes et les plus connues au monde) bien mieux qu'un modèle que vous pouvez créer en un jour.spacy.Doc
partir de chaque texte, parcourez leursdoc.ents
NER avec et vérifiez si un NER a un.text
attribut égal àApple
. Fait amusant, leur premier exemple consiste en Apple.