Veja abaixo 50 tweets sobre "apple". Identifiquei manualmente as correspondências positivas sobre a Apple Inc. Elas estão marcadas como 1 abaixo.
Aqui estão algumas linhas:
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
Aqui está o conjunto de dados total: http://pastebin.com/eJuEb4eB
Preciso construir um modelo que classifique "Apple" (Inc). do resto.
Não estou procurando uma visão geral do aprendizado de máquina, em vez disso, estou procurando um modelo real no código ( Python de preferência).
Respostas:
Eu faria da seguinte forma:
fonte
O que você está procurando é chamado de Reconhecimento de Entidade Nomeada . É uma técnica estatística que (mais comumente) usa campos aleatórios condicionais para encontrar entidades nomeadas, com base em ter sido treinado para aprender coisas sobre entidades nomeadas.
Essencialmente, ele analisa o conteúdo e o contexto da palavra, (olhando algumas palavras para trás e para a frente), para estimar a probabilidade de que a palavra seja uma entidade nomeada.
Um bom software pode analisar outras características das palavras, como seu comprimento ou forma (como "Vcv" se começar com "Vogal-consoante-vogal")
Uma biblioteca muito boa (GPL) é o NER de Stanford
Aqui está a demonstração: http://nlp.stanford.edu:8080/ner/
Alguns exemplos de texto para experimentar:
(os classificadores 3class e 4class acertam)
fonte
english.conll.4class.distsim.crf.ser.gz
? Adoraria ver como alguém constrói algo assim.Eu tenho um sistema semi-funcional que resolve esse problema, código aberto usando o scikit-learn, com uma série de postagens de blog que descrevem o que estou fazendo. O problema que estou enfrentando é a desambiguação de sentido de palavra (escolher uma das várias opções de sentido de palavra ), que não é o mesmo que Reconhecimento de entidade nomeada. Minha abordagem básica é um tanto competitiva com as soluções existentes e (crucialmente) é personalizável.
Existem algumas ferramentas comerciais NER (OpenCalais, DBPedia Spotlight e AlchemyAPI) que podem fornecer um resultado comercial bom o suficiente - experimente primeiro!
Eu usei alguns deles para um projeto de cliente (eu consultor usando PNL / ML em Londres), mas não fiquei feliz com a recordação ( precisão e recall ). Basicamente, eles podem ser precisos (quando dizem "Esta é a Apple Inc", normalmente estão corretos), mas com pouca memória (raramente dizem "Esta é a Apple Inc", embora para um humano o tweet seja obviamente sobre a Apple Inc). Achei que seria um exercício intelectualmente interessante construir uma versão de código aberto sob medida para tweets. Aqui está o código atual: https://github.com/ianozsvald/social_media_brand_disambiguator
Vou observar - não estou tentando resolver o problema generalizado de desambiguação de sentido de palavra com esta abordagem, apenas desambiguação de marca (empresas, pessoas, etc.) quando você já tem seus nomes. É por isso que acredito que essa abordagem simples funcionará.
Comecei isso há seis semanas e está escrito em Python 2.7 usando scikit-learn. Ele usa uma abordagem muito básica. Eu vetorizo usando um vetorizador de contagem binária (só conto se uma palavra aparece, não quantas vezes) com 1-3 n-gramas . Eu não escala com TF-IDF (TF-IDF é bom quando você tem um comprimento de documento variável; para mim, os tweets são apenas uma ou duas frases e meus resultados de teste não mostraram melhorias com TF-IDF).
Eu uso o tokenizer básico, que é muito básico, mas surpreendentemente útil. Ele ignora @ # (assim você perde algum contexto) e, claro, não expande um URL. Eu, então, treino usando regressão logística , e parece que esse problema é um tanto linearmente separável (muitos termos para uma classe não existem para a outra). Atualmente estou evitando qualquer corte / limpeza (estou tentando a coisa mais simples possível que pode funcionar).
O código tem um README completo, e você deve ser capaz de ingerir seus tweets com relativa facilidade e seguir minhas sugestões de teste.
Isso funciona para a Apple, pois as pessoas não comem ou bebem computadores Apple, nem digitamos ou brincamos com frutas, então as palavras são facilmente divididas em uma categoria ou outra. Esta condição pode não se manter ao considerar algo como #definance para o programa de TV (onde as pessoas também usam #definance em relação à Primavera Árabe, partidas de críquete, revisão de exames e uma banda de música). Abordagens mais inteligentes podem ser necessárias aqui.
Tenho uma série de posts descrevendo este projeto, incluindo uma apresentação de uma hora que fiz no grupo de usuários BrightonPython (que se transformou em uma apresentação mais curta para 140 pessoas na DataScienceLondon).
Se você usar algo como LogisticRegression (onde obtém uma probabilidade para cada classificação), você pode escolher apenas as classificações confiáveis e, dessa forma, pode forçar a alta precisão negociando contra recall (para obter resultados corretos, mas menos deles). Você terá que ajustar isso ao seu sistema.
Aqui está uma possível abordagem algorítmica usando scikit-learn:
Coisas a considerar:
Ré. sobreajuste. Em meu conjunto de dados com 2.000 itens, tenho um instantâneo de 10 minutos do Twitter de tweets da 'apple'. Cerca de 2/3 dos tweets são para a Apple Inc, 1/3 para outros usos da apple. Eu retiro um subconjunto equilibrado (cerca de 584 linhas, eu acho) de cada classe e faço a validação cruzada quíntupla para o treinamento.
Uma vez que tenho apenas uma janela de tempo de 10 minutos, tenho muitos tweets sobre o mesmo tópico, e é provavelmente por isso que meu classificador se sai tão bem em relação às ferramentas existentes - ele terá ajustes excessivos para os recursos de treinamento sem generalizar bem (enquanto o comercial existente ferramentas têm pior desempenho neste snapshop, mas de forma mais confiável em um conjunto mais amplo de dados). Estarei expandindo minha janela de tempo para testar isso como um trabalho subsequente.
fonte
Você pode fazer o seguinte:
Faça um ditado de palavras contendo sua contagem de ocorrência em tweets relacionados a frutas e empresas. Isso pode ser conseguido alimentando-o com alguns tweets de amostra cuja inclinação conhecemos.
Usando dados anteriores suficientes, podemos descobrir a probabilidade de uma palavra ocorrer em um tweet sobre a apple inc.
Multiplique as probabilidades individuais de palavras para obter a probabilidade de todo o tweet.
Um exemplo simplificado:
p_f = Probabilidade de tweets de frutas.
p_w_f = Probabilidade de uma palavra ocorrer em um tweet de frutas.
p_t_f = Probabilidade combinada de todas as palavras no tweet ocorrerem um tweet de fruta = p_w1_f * p_w2_f * ...
p_f_t = Probabilidade de fruta em um determinado tweet.
p_c, p_w_c, p_t_c, p_c_t são os respectivos valores da empresa.
Um suavizador laplaciano de valor 1 é adicionado para eliminar o problema de frequência zero de novas palavras que não estão em nosso banco de dados.
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"
fonte
Se você não tiver problemas ao usar uma biblioteca externa, recomendo o scikit-learn, pois ele provavelmente pode fazer isso melhor e mais rápido do que qualquer coisa que você possa codificar sozinho. Eu apenas faria algo assim:
Construa seu corpus. Fiz as compreensões da lista para maior clareza, mas dependendo de como seus dados são armazenados, pode ser necessário fazer coisas 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)
O importante é que você acaba com duas listas parecidas com esta:
([['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])
O [1, 1, 0, 0] representa os rótulos positivos e negativos.
Então, você cria um Pipeline! Pipeline é uma classe scikit-learn que torna mais fácil encadear as etapas de processamento de texto para que você só precise chamar um objeto ao treinar / prever:
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 do pipeline, existem três etapas de processamento. O CountVectorizer simboliza as palavras, divide-as, conta-as e transforma os dados em uma matriz esparsa. O TfidfTransformer é opcional e você pode querer removê-lo dependendo da classificação de precisão (fazer testes de validação cruzada e uma pesquisa de grade para os melhores parâmetros é um pouco complicado, então não vou entrar no assunto aqui). O LinearSVC é um algoritmo de classificação de texto padrão.
Finalmente, você prevê a categoria de tweets:
def predict(pipe, tweet): prediction = pipe.predict([tweet]) return prediction
Novamente, o tweet precisa estar em uma lista, então presumi que ele estava inserindo a função como uma string.
Coloque todos eles em uma classe ou qualquer outra coisa e pronto. Pelo menos, com este exemplo básico.
Não testei este código, então pode não funcionar se você apenas copiar e colar, mas se você quiser usar o scikit-learn, ele deve dar uma ideia de por onde começar.
EDIT: tente explicar as etapas em mais detalhes.
fonte
Usar uma árvore de decisão parece funcionar muito bem para esse problema. Pelo menos ele produz uma precisão maior do que um classificador bayes ingênuo com minhas características escolhidas.
Se você quiser brincar com algumas possibilidades, pode usar o código a seguir, que requer a instalação do nltk. O livro nltk também está disponível gratuitamente online, então você pode querer ler um pouco sobre como tudo isso realmente funciona: 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()
fonte
dict()
outro lugar? Acho que se um conjunto de treinamento for grande o suficiente, um computador não deveria ser capaz de descobrir os recursos por si só? (sem supervisão?)'hasBigram(foo,bar)' = True
onde a string do tweet incluifoo bar
? Então, ele cria bigramas e trigramas para cada tweet e os sinaliza no recurso positivodict()
? Portanto, dado o tweet"alpha beta gamma delta"
,, ele criará dict () bigrams paraalpha,beta; beta,gamma; and gamma,delta;
e trigramas paraalpha,beta,gamma
ebeta,gamma,delta
? E a partir dos bi e tri gramas positivos e negativos dados, os classificadores da árvore de decisão ou bayes podem fazer sua mágica?Obrigado pelos comentários até agora. Aqui está uma solução de trabalho que preparei com PHP. Ainda estou interessado em ouvir de outras pessoas uma abordagem mais algorítmica para essa mesma solução.
<?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; } ?>
Os resultados acima:
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.
fonte
Em todos os exemplos que você deu, Apple (inc) foi referido como A pple ou apple inc , portanto, uma maneira possível seria pesquisar:
um "A" maiúsculo na Apple
um "inc" depois da maçã
palavras / frases como "OS", "sistema operacional", "Mac", "iPhone", ...
ou uma combinação deles
fonte
Para simplificar um pouco as respostas com base em campos aleatórios condicionais ... o contexto é enorme aqui. Você vai querer escolher aqueles tweets que mostram claramente a Apple a empresa versus a maçã a fruta. Deixe-me esboçar uma lista de recursos aqui que podem ser úteis para você começar. Para obter mais informações, pesquise agrupamento de frases nominais e algo chamado rótulos BIO. Veja ( http://www.cis.upenn.edu/~pereira/papers/crf.pdf )
Palavras circundantes: Construa um vetor de características para a palavra anterior e a próxima ou, se desejar mais características, talvez as 2 palavras anteriores e as próximas 2. Você não quer muitas palavras no modelo ou não corresponderá muito bem aos dados. No Processamento de Linguagem Natural, você vai querer manter isso o mais geral possível.
Outros recursos para obter a partir das palavras ao redor incluem o seguinte:
Se o primeiro caractere é maiúsculo
Se o último caractere da palavra é um ponto
A classe gramatical da palavra (procurar marcação de classe gramatical)
O próprio texto da palavra
Não aconselho isso, mas para dar mais exemplos de recursos especificamente para a Apple:
WordIs (Apple)
NextWordIs (Inc.)
Você entendeu. Pense no reconhecimento de entidade nomeada como uma descrição de uma sequência e, em seguida, use um pouco de matemática para dizer a um computador como calculá-la.
Lembre-se de que o processamento de linguagem natural é um sistema baseado em pipeline. Normalmente, você divide as coisas em frases, passa para a tokenização e, em seguida, faz a marcação de classes gramaticais ou mesmo a análise de dependência.
Isso tudo para obter uma lista de recursos que você pode usar em seu modelo para identificar o que está procurando.
fonte
Existe uma biblioteca muito boa para processar texto em linguagem natural em Python, chamada
nltk
. Você deveria dar uma olhada nisso.Uma estratégia que você pode tentar é olhar para n-gramas (grupos de palavras) com a palavra "maçã" neles. Algumas palavras são mais prováveis de serem usadas ao lado de "maçã" quando se fala sobre a fruta, outras quando se fala sobre a empresa, e você pode usá-las para classificar tweets.
fonte
nltk
) que pode me ajudar a começar na direção certa com uma tarefa de aprendizado de máquina "hello world". A maçã (inc) vs. maçã (fruta) parece uma atribuição perfeita.Use LibShortText . Este utilitário Python já foi ajustado para funcionar em tarefas curtas de categorização de texto e funciona bem. O máximo que você terá que fazer é escrever um loop para escolher a melhor combinação de sinalizadores. Usei-o para fazer a classificação de atos de fala supervisionados em e-mails e os resultados foram até 95-97% precisos (durante a validação cruzada de 5 vezes!).
E vem dos fabricantes de LIBSVM e LIBLINEAR, cuja implementação de máquina de vetores de suporte (SVM) é usada em sklearn e cran, então você pode estar razoavelmente seguro de que sua implementação não tem bugs.
fonte
Faça um filtro AI para distinguir a Apple Inc (a empresa) da maçã (a fruta). Como são tweets, defina seu conjunto de treinamento com um vetor de 140 campos, cada campo sendo o caractere escrito no tweet na posição X (0 a 139). Se o tweet for mais curto, basta dar um valor para estar em branco.
Em seguida, construa um conjunto de treinamento grande o suficiente para obter uma boa precisão (subjetiva ao seu gosto). Atribua um valor de resultado a cada tweet, um tweet da Apple Inc obtém 1 (verdadeiro) e um tweet da maçã (fruta) obtém 0. Seria um caso de aprendizagem supervisionada em uma regressão logística .
Isso é aprendizado de máquina, geralmente é mais fácil de codificar e tem melhor desempenho. Ele tem que aprender com o conjunto que você fornece e não está codificado.
Não conheço Python , então não posso escrever o código para ele, mas se você dedicar mais tempo à lógica e teoria do aprendizado de máquina, talvez queira dar uma olhada na aula que estou seguindo.
Experimente o curso Coursera Machine Learning de Andrew Ng . Você aprenderá o aprendizado de máquina no MATLAB ou Octave , mas depois de obter o básico, será capaz de escrever o aprendizado de máquina em qualquer linguagem se você entender a matemática simples (simples em regressão logística).
Ou seja, obter o código de alguém não o tornará capaz de entender o que está acontecendo no código de aprendizado de máquina. Você pode querer investir algumas horas no assunto para ver o que realmente está acontecendo.
fonte
Eu recomendaria evitar respostas que sugiram o reconhecimento de entidade. Porque esta tarefa é primeiro uma classificação de texto e depois o reconhecimento de entidade (você pode fazer isso sem o reconhecimento de entidade).
Acho que o caminho mais rápido para os resultados será spacy + prodigy . Spacy tem um modelo bem pensado para o idioma inglês, então você não precisa construir o seu próprio. Enquanto o prodígio permite criar rapidamente conjuntos de dados de treinamento e ajustar o modelo de espaço para suas necessidades.
Se você tiver amostras suficientes, pode ter um modelo decente em 1 dia.
fonte
spaCy
temner
componente de pipeline, não seria benéfico para esta classificação? Presumo que o modelo deles pode reconhecerApple
(por ser uma das maiores e mais conhecidas empresas do mundo) muito melhor do que um modelo que você pode criar em um dia.spacy.Doc
partir de cada texto, iterar sobre seus NERs comdoc.ents
e verificar se algum NER possui.text
atributo igual aApple
. Curiosidade, seu primeiro exemplo consiste na Apple.