我如何建立一个模型来区分有关Apple(Inc。)的推文和关于apple(水果)的推文?

时间:2013-06-27 20:20:59

标签: java python r machine-learning classification

请参阅下文,了解有关“苹果”的50条推文。我亲手打了一些关于Apple Inc.的积极比赛。他们在下面标记为1。

以下是几行:

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

以下是总数据集:http://pastebin.com/eJuEb4eB

我需要构建一个对“Apple”(Inc)进行分类的模型。其余的。

我不是在寻找机器学习的概述,而是在寻找代码中的实际模型(Python首选)。

12 个答案:

答案 0 :(得分:71)

您要找的是Named Entity Recognition。这是一种统计技术(最常见的)使用Conditional Random Fields来查找命名实体,这是基于经过训练来学习有关命名实体的事情。

基本上,它会查看单词的内容和上下文,(回顾和转发几个单词),以估计单词是命名实体的概率。

好的软件可以查看单词的其他功能,例如它们的长度或形状(例如" Vcv"如果它以&#34开头; Vowel-consonant-vowel")

非常好的图书馆(GPL)是Stanford's NER

这是演示:http://nlp.stanford.edu:8080/ner/

要尝试的一些示例文字:

  

我在Apple总部吃了一个苹果,我想到了   Apple Martin,酷玩家的女儿

(3类和4类分类器使其正确)

答案 1 :(得分:36)

我会这样做:

  1. 将句子拆分为单词,将其标准化,构建字典
  2. 用每个单词,存储关于公司的推文发生的次数,以及它们在推文中出现的关于水果的次数 - 这些推文必须由人类确认
  3. 当一条新推文进来时,在字典中找到推文中的每个单词,计算一个加权分数 - 与公司相关的频繁使用的单词会获得较高的公司分数,反之亦然;很少使用,或与公司和水果一起使用的单词不会得到太多分数。

答案 2 :(得分:11)

您可以执行以下操作:

  1. 在水果和公司相关推文中制作包含其发生次数的单词。这可以通过提供一些我们知道倾向的样本推文来实现。

  2. 使用足够的先前数据,我们可以找到关于apple inc的推文中出现单词的概率。

  3. 将单词的单个概率乘以获得整条推文的概率。

  4. 一个简化的例子:

    p_f =水果推文的可能性。

    p_w_f =水果推文中出现单词的概率。

    p_t_f =推文中所有单词的组合概率都是水果推文       = p_w1_f * p_w2_f * ...

    p_f_t =给出特定推文的水果概率。

    p_c,p_w_c,p_t_c,p_c_t 是公司的相应值。

    添加了值为1的laplacian平滑器,以消除我们数据库中没有的新单词的零频率问题。

    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"
    

答案 3 :(得分:9)

如果使用外部库没有问题,我建议使用scikit-learn,因为它可能会更好地做到这一点。比你自己编码的任何东西都快。我会做这样的事情:

建立你的语料库。为清晰起见,我列出了清单,但根据数据的存储方式,您可能需要做不同的事情:

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)

重要的是你得到两个看起来像这样的列表:

([['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]表示正面和负面标签。

然后,您创建一个管道! Pipeline是一个scikit-learn类,可以很容易地将文本处理步骤链接在一起,因此您只需在训练/预测时调用一个对象:

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

在管道内部有三个处理步骤。 CountVectorizer对单词进行标记,对其进行分割,对其进行计数,并将数据转换为稀疏矩阵。 TfidfTransformer是可选的,您可能希望根据准确度等级将其删除(进行交叉验证测试和最佳参数的网格搜索有点涉及,所以我不会在这里介绍它)。 LinearSVC是一种标准的文本分类算法。

最后,您预测推文的类别:

def predict(pipe, tweet):
    prediction = pipe.predict([tweet])
    return prediction

同样,推文需要在列表中,所以我认为它是以字符串形式输入函数。

将所有这些放入课堂或其他任何地方,你就完成了。至少,有了这个非常基本的例子。

我没有测试这段代码,所以如果你只是复制粘贴它可能不起作用,但如果你想使用scikit-learn它应该让你知道从哪里开始。

编辑:尝试更详细地解释这些步骤。

答案 4 :(得分:6)

使用决策树似乎可以很好地解决这个问题。至少它比我选择的功能的朴素贝叶斯分类器产生更高的准确度。

如果您想玩一些可能性,可以使用以下代码,这需要安装nltk。 nltk书籍也可以在线免费获取,因此您可能想要了解所有这些内容的实际效果: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()

答案 5 :(得分:5)

感谢您迄今为止的评论。这是我用PHP编写的working 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;
}
?>

以上输出:

           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.

答案 6 :(得分:4)

在您提供的所有示例中,Apple(inc)被称为 A pple或apple inc ,因此可能的方法是搜索:

  • Apple的首都“A”

  • 苹果后的“inc”

  • “OS”,“操作系统”,“Mac”,“iPhone”等字词/短语......

  • 或其组合

答案 7 :(得分:4)

为了简化基于条件随机场的答案,有点......背景在这里很大。你会想要在那些明确显示苹果公司与苹果水果的推文中挑选出来。让我概述一下这里可能对您有用的功能列表。有关更多信息,请查找名词短语chunking,以及称为BIO标签的内容。见(http://www.cis.upenn.edu/~pereira/papers/crf.pdf

周围的单词:为前一个单词和下一个单词构建一个特征向量,或者如果你想要更多的特征,可能是前两个和后两个单词。您不希望模型中有太多单词,否则它将无法很好地匹配数据。 在自然语言处理中,您将希望保持尽可能通用。

从周围的单词中获取的其他功能包括:

第一个角色是否为大写

单词中的最后一个字符是否为句号

单词的词性(查找词性标注)

一词的文字本身

我不建议这样做,而是提供更多专门针对Apple的功能示例:

WordIs(苹果)

NextWordIs(INC。)

你明白了。将命名实体识别视为描述序列,然后使用一些数学来告诉计算机如何计算它。

请记住,自然语言处理是基于管道的系统。通常情况下,您会将内容分解为句子,转移到标记化,然后执行部分语音标记甚至依赖性解析。

这就是为了向您提供可在模型中使用的功能列表,以确定您要查找的内容。

答案 8 :(得分:3)

在名为nltk的{​​{3}}中处理自然语言文本有一个非常好的库。你应该看看它。

您可以尝试的一种策略是查看n-gram(单词组),其中包含“apple”一词。在谈论水果时,有些词更可能被用在“苹果”旁边,有些词在谈论公司时更有可能被使用,你可以用它来对推文进行分类。

答案 9 :(得分:3)

使用LibShortText。此Python实用程序已经过调整,可用于短文本分类任务,并且运行良好。你需要做的最大的事情就是编写一个循环来选择最好的标志组合。我用它在电子邮件中进行监督言语行为分类,结果准确率高达95-97%(在5倍交叉验证期间!)。

它来自LIBSVMLIBLINEAR的制作者,其support vector machine(SVM)实现用于s​​klearn和cran,因此您可以合理地确保它们的实现不是错误的

答案 10 :(得分:2)

制作AI过滤器,以区分 Apple Inc (公司)与 apple (水果)。由于这些是推文,因此使用140个字段的向量定义训练集,每个字段是在位置X(0到139)的推文中写入的字符。如果推文较短,只需给出一个空白值。

然后建立一个足够大的训练集,以获得良好的准确性(主观根据您的口味)。为每条推文分配一个结果值, Apple Inc 推文获得1(真),苹果推文(水果)获得0.这将是supervised learninglogistic regression的情况}}

那就是机器学习,通常更容易编码并且表现更好。它必须从你给它的集合中学习,而且它不是硬编码的。

我不知道Python,所以我不能为它编写代码,但如果你要花更多时间学习机器学习的逻辑和理论,你可能想看看我正在关注的课程。

Coursera尝试Machine Learning课程 Andrew Ng 。您将学习MATLABOctave上的机器学习,但是一旦掌握了基础知识,如果您理解简单的数学(逻辑回归中的简单),您就能用任何语言编写机器学习。

也就是说,从某人那里获取代码不会让您能够理解机器学习代码中的内容。您可能希望花几个小时来研究这个主题,看看究竟发生了什么。

答案 11 :(得分:0)

我建议避免回答暗示实体认可的答案。因为此任务首先是文本分类,然后是实体识别(您完全可以在没有实体识别的情况下完成此任务)。

我认为最快的结果路径将是spacy + prodigy。 Spacy对英语模型进行了深思熟虑,因此您不必自己构建。神童可以快速创建训练数据集并根据需要微调spacy模型。

如果您有足够的样本,则可以在1天之内得到一个体面的模型。