Voir ci-dessous 50 tweets sur "Apple". J'ai apposé à la main les correspondances positives concernant Apple Inc. Elles sont identifiées par le chiffre 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 le jeu de données total: http://Pastebin.com/eJuEb4eB
Je dois construire un modèle qui classe "Apple" (Inc). du reste.
Je ne cherche pas un aperçu général de l'apprentissage automatique, je cherche plutôt le modèle actuel en code ( Python préféré).
Je le ferais comme suit:
Ce que vous recherchez s'appelle Reconnaissance des entités nommées . Il s’agit d’une technique statistique qui utilise (le plus souvent) - Champs aléatoires conditionnels pour rechercher des entités nommées, en s’appuyant sur leur formation 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 retrançant 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 NER de Stanford
Voici la démo: http://nlp.stanford.edu:8080/ner/
Quelques exemples de texte à essayer:
Je mangeais une pomme au siège social d’Apple et j’ai pensé à Apple Martin, la fille du gars Coldplay
(les classificateurs 3class et 4class réussissent)
J'ai un système semi-fonctionnel qui résout ce problème, de source ouverte à l'aide de scikit-learn, avec une série de billets de blog décrivant ce que je fais. Le problème que je traite est la désambiguïsation du sens des mots (choisir l’une des multiples options sens des mots ), qui n’est pas la même chose que la reconnaissance d’entité nommée. Mon approche de base est quelque peu concurrentielle par rapport aux solutions existantes et (surtout) personnalisable.
Certains outils NER commerciaux existants (OpenCalais, DBPedia Spotlight et AlchemyAPI) pourraient vous donner un résultat commercial assez satisfaisant. Essayez-les d'abord!
J'en ai utilisé quelques-unes pour un projet client (je consulte en utilisant la PNL/ML à Londres), mais je n'étais pas satisfait de leur rappel ( précision et rappel ). En gros, ils peuvent être précis (quand ils disent "Ceci est Apple Inc", ils sont généralement corrects), mais avec un faible rappel (ils disent rarement "Ceci est Apple Inc" bien que pour un humain, le Tweet concerne évidemment Apple Inc). J'ai pensé que ce serait un exercice intellectuellement intéressant de construire une version open source adaptée aux tweets. Voici le code actuel: https://github.com/ianozsvald/social_media_brand_disambiguator
Je vais noter - je n'essaie pas de résoudre le problème généralisé d'homonymie de Word-sens avec cette approche, juste marque homonymie (sociétés, personnes, etc.) .) quand vous avez déjà leur nom. C'est pourquoi je crois 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 en utilisant un vectoriseur à comptage binaire (je compte seulement si un mot apparaît, pas combien de fois) avec 1-3 n-grammes . Je ne fais pas évoluer avec TF-IDF (TF-IDF est bon lorsque vous avez une longueur de document variable; pour moi, les tweets ne représentent qu'une ou deux phrases et mes résultats de test ne montrent aucune 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 contexte) et, bien sûr, ne développe pas une URL. Je m'entraîne alors à l'aide de régression logistique , et il semble que ce problème soit un peu séparable de manière linéaire (de nombreux termes pour une classe n'existent pas pour l'autre). Actuellement, j'évite tout nettoyage/nettoyage (j'essaie la chose la plus simple qui puisse 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 pas Apple ordinateurs, et nous ne tapons ni ne jouons avec des fruits. Ainsi, les mots sont facilement scindés en une catégorie ou une autre. Cette condition peut ne pas être vérifiée si vous envisagez quelque chose comme #definance pour l'émission télévisée (où les gens utilisent également #definance en relation avec le Printemps arabe, les matchs de cricket, la révision d'un examen et un groupe de musique). Des approches plus intelligentes pourraient bien être nécessaires ici.
J'ai ne série de billets 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 chez DataScienceLondon).
Si vous utilisez quelque chose comme LogisticRegression (où vous obtenez une probabilité pour chaque classification), vous ne pouvez choisir que les classifications confiantes, ce qui vous permet d'imposer une précision élevée en échangeant contre rappel (pour obtenir 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é. surapprentissage. Dans mon ensemble de données contenant 2 000 éléments, j'ai un instantané de 10 minutes sur Twitter de tweets "Apple". Environ 2/3 des tweets sont destinés à Apple Inc, 1/3 aux autres utilisations d’Apple. Je sors un sous-ensemble équilibré (environ 584 lignes, je pense) de chaque classe et effectue une validation croisée en cinq étapes pour la formation.
Comme je ne dispose que de 10 minutes, j’ai de nombreux tweets sur le même sujet, ce qui explique probablement pourquoi mon classificateur se débrouille si bien par rapport aux outils existants - il aura trop de fonctionnalités de formation sans trop bien se généraliser (alors les outils fonctionnent moins bien sur ce composant logiciel enfichable, mais de manière plus fiable sur un ensemble de données plus large). Je vais élargir ma fenêtre de temps pour tester cela ultérieurement.
Vous pouvez faire ce qui suit:
Faites une dictée de mots contenant le nombre d'occurrences dans les tweets relatifs aux fruits et aux entreprises. Cela peut être réalisé en lui donnant des échantillons de tweets dont nous connaissons l'inclinaison.
En utilisant suffisamment de données précédentes, nous pouvons déterminer la probabilité qu'un mot se produise dans Tweet à propos de Apple inc.
Multipliez les probabilités individuelles de mots pour obtenir la probabilité de l'ensemble du tweet.
p_f = Probabilité de tweets de fruits.
p_w_f = Probabilité qu'un mot se produise dans un fruit Tweet.
p_t_f = Probabilité combinée que tous les mots de Tweet produisent un fruit Tweet = p_w1_f * p_w2_f * ...
p_f_t = Probabilité qu'un fruit soit donné à un Tweet particulier.
p_c, p_w_c, p_t_c, p_c_t sont des valeurs respectives pour la société.
Un lisseur laplacien de valeur 1 est ajouté pour éliminer le problème de la fréquence zéro des nouveaux mots qui ne figurent pas 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"
Si vous ne rencontrez pas de problème en utilisant une bibliothèque externe, je recommanderais scikit-learn , car elle 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 compréhension de la liste pour plus de clarté, mais en fonction de la manière 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)
La chose importante 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 facilitant l'enchaînement des étapes de traitement de texte. Vous ne devez donc appeler qu'un seul objet lors de la formation/prévision:
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
Dans le pipeline, il y a trois étapes de traitement. CountVectorizer identifie les mots, les scinde, les compte et transforme les données en une matrice fragmentée. TfidfTransformer est facultatif et vous voudrez peut-être le supprimer en fonction de la précision (effectuer des tests de validation croisée et une recherche sur la grille des meilleurs paramètres est un peu compliqué, je ne vais donc pas en parler ici). LinearSVC est un algorithme de classification de texte standard.
Enfin, vous prédisez la catégorie de tweets:
def predict(pipe, Tweet):
prediction = pipe.predict([Tweet])
return prediction
Encore une fois, le Tweet doit être dans une liste, alors j'ai supposé qu'il entrait dans la fonction en tant que chaîne.
Mettez tous ceux-ci dans une classe ou autre, et vous avez terminé. Au moins, avec cet exemple très basique.
Comme je n'ai pas testé ce code, il risque de ne pas fonctionner si vous ne faites que copier-coller, mais si vous souhaitez utiliser scikit-learn, il devrait vous donner une idée de l'endroit où commencer.
EDIT: essayé d'expliquer les étapes plus en détail.
L'utilisation d'un arbre de décision semble très bien fonctionner pour résoudre 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 quelques 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 en savoir plus sur le fonctionnement de tout cela: 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 __== '__main__':
print check_accurracy()
Merci pour les commentaires jusqu'ici. Voici une solution de travail j'ai préparé 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.
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é vs Apple le fruit. Permettez-moi de vous présenter une liste de fonctionnalités qui pourraient vous être utiles pour commencer. Pour plus d’informations, recherchez la suppression de syntagmes nominaux et un élément 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 souhaitez davantage de fonctionnalités, par exemple les 2 et les 2 mots suivants. Vous ne voulez pas trop de mots dans le modèle ou il ne correspondra pas très bien aux données. Dans Natural Language Processing, vous allez vouloir garder ceci aussi général que possible.
Les autres caractéristiques des mots suivants sont les suivantes:
Si le premier personnage est une capitale
Si le dernier caractère de la Parole est un point
La partie du discours de la Parole (Rechercher une partie du marquage de la parole)
Le texte même de la parole
Je ne le conseille pas, mais pour donner plus d'exemples de fonctionnalités spécifiques à Apple:
WordIs (Apple)
NextWordIs (Inc.)
Tu obtiens le point. Pensez à la reconnaissance d'entité nommée comme décrivant une séquence, puis utilisez des mathématiques pour dire à un ordinateur comment calculer cela.
N'oubliez pas que le traitement du langage naturel est un système basé sur un pipeline. En général, vous divisez des choses en phrases, vous passez à la génération de jetons, puis vous faites une partie du balisage de la parole ou même de l'analyse de dépendance.
Tout cela pour vous fournir une liste de fonctionnalités que vous pouvez utiliser dans votre modèle pour identifier ce que vous recherchez.
Dans tous les exemples que vous avez donnés, Apple (inc) était soit désigné par UNEpple ou Apple inc, donc une solution possible pourrait être de rechercher:
une capitale "A" dans Apple
un "inc" après Apple
des mots/expressions tels que "OS", "système d'exploitation", "Mac", "iPhone", ...
ou une combinaison d'entre eux
Utilisez LibShortText . Cet utilitaire Python a déjà été mis au point pour fonctionner dans les tâches de catégorisation de texte courtes et 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 la classification d'actes de parole supervisés dans des e-mails et les résultats étaient précis à 95-97% (lors de la validation croisée sur 5 fois!).
Et il provient des fabricants de LIBSVM et LIBLINEAR dont la mise en œuvre de la machine à vecteurs de support (SVM) est utilisée dans sklearn et cran, vous pouvez donc être raisonnablement assuré que leur implémentation n'est pas buggy.
Il existe une très bonne bibliothèque pour le traitement de texte en langage naturel dans Python appelé nltk
. Vous devriez y jeter un coup d'oeil.
Une stratégie que vous pouvez essayer consiste à examiner les n-grammes (groupes de mots) contenant le mot "Apple". Certains mots sont plus susceptibles d’être utilisés à côté de "Apple" lorsque vous parlez du fruit, d’autres lorsque vous parlez de la société et vous pouvez les utiliser pour classer les tweets.
Créez un filtre IA pour distinguer Apple Inc (la société) de Apple (le fruit). Comme il s’agit de tweets, définissez votre jeu d’entraînement avec un vecteur de 140 champs, chaque champ étant le caractère inscrit 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 assez grand pour obtenir une bonne précision (subjective à votre goût). Attribuez une valeur de résultat à chaque Tweet, un Apple Inc Tweet obtenez 1 (vrai) et un Tweet Apple (fruit) obtient 0. Ce serait un cas de apprentissage supervisé dans une régression logistique .
C'est l'apprentissage machine, il est généralement plus facile de coder et fonctionne mieux. Il doit apprendre de l'ensemble que vous lui donnez, et ce n'est pas codé en dur.
Je ne sais pas Python , je ne peux donc pas écrire le code correspondant, 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 Coursera course Apprentissage automatique de Andrew Ng . Vous allez apprendre l’apprentissage automatique sur MATLAB ou Octave , mais une fois que vous aurez acquis les bases, vous pourrez écrire l’apprentissage automatique dans n’importe quelle langue si vous comprenez les mathématiques simples (régression logistique simple). ).
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.
Je recommanderais d'éviter les réponses suggérant la reconnaissance d'entité. Parce que cette tâche est une classification de texte d’abord et une reconnaissance d’entité ensuite (vous pouvez le faire sans la reconnaissance d’entité).
Je pense que le chemin le plus rapide vers des résultats sera spacy + prodige . Spacy a bien réfléchi au modèle de la langue anglaise, vous n’avez donc pas à créer le vôtre. While Prodigy permet de créer rapidement des jeux de données d’entraînement et d’ajuster avec précision le modèle spécifique à vos besoins.
Si vous avez suffisamment d'échantillons, vous pouvez avoir un modèle décent en 1 jour.