web-dev-qa-db-ja.com

Apple(Inc.)に関するツイートとApple(fruit)に関するツイートを区別するモデルを構築するにはどうすればよいですか?

「Apple」に関する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 推奨)。

83
SAL

私は次のようにします:

  1. 文を単語に分割し、正規化し、辞書を作成します
  2. 各Wordで、会社に関するツイートで発生した回数と、フルーツに関するツイートで発生した回数を保存します。これらのツイートは、人間が確認する必要があります。
  3. 新しいツイートが入ったら、辞書でツイート内のすべての単語を見つけ、加重スコアを計算します。会社に関連して頻繁に使用される単語は高い会社スコアを取得し、逆も同様です。めったに使用されない単語、または会社と果物の両方で使用される単語は、あまりスコアがありません。
36
AMADANON Inc.

探しているものは Named Entity Recognition と呼ばれます。これは、(最も一般的に) 条件付きランダムフィールド を使用して、名前付きエンティティについて学習するように訓練されていることに基づいて、名前付きエンティティを検索する統計的手法です。

本質的には、Wordのコンテンツとcontextを見て(数語を前後に見ながら)、Wordが名前付きエンティティ。

優れたソフトウェアは、長さや形など、単語の他の特徴を見ることができます(「Vonwel-consonant-vowel」で始まる場合は「Vcv」など)

非常に優れたライブラリ(GPL)は Stanford's NER です

デモは次のとおりです。 http://nlp.stanford.edu:8080/ner/

試すサンプルテキスト:

私はApple Apple本部で食べて、私はApple

(3classおよび4classクラシファイアはそれを正しくします)

71
Neil McGuigan

この問題を解決するセミワーキングシステムがあり、scikit-learnを使用してオープンソース化されており、私がやっていることを説明する一連のブログ投稿があります。私が取り組んでいる問題は、ワードセンスの曖昧性解消(複数の ワードセンス オプションのいずれかを選択する)です。これは、名前付きエンティティの認識とは異なります。私の基本的なアプローチは、既存のソリューションといくらか競争力があり、(重要な)カスタマイズが可能です。

既存の商用NERツール(OpenCalais、DBPedia Spotlight、およびAlchemyAPI)があり、十分な商用結果が得られる可能性があります。これらを最初に試してください!

これらのいくつかをクライアントプロジェクトに使用しました(ロンドンでNLP/MLを使用して相談します)が、それらのリコールに満足していません( 精度とリコール )。基本的に、彼らは「これはApple Inc」と言うときは正確ですが、リコールが少ない(「This is Apple Inc」と言われることはほとんどありません)人間にとって、ツイートは明らかにApple Incについてのものです。ツイートに合わせたオープンソースバージョンを構築することは、知的に興味深い演習になると考えました。現在のコードは次のとおりです。 https://github.com/ianozsvald/social_media_brand_disambiguator

私は注意します-私はこのアプローチで一般化されたワードセンスの曖昧性解消の問題を解決しようとはしていません、ちょうどbrand曖昧性解消(企業、人々など。)名前が既にある場合。だからこそ、私はこの単純なアプローチがうまくいくと信じています。

私はこれを6週間前に始めましたが、scikit-learnを使用してPython 2.7で書かれています。非常に基本的なアプローチを使用します。 1〜3 vector n-grams でバイナリカウントベクトライザーを使用してベクトル化します(Wordが表示されるかどうかだけをカウントし、回数はカウントしません)。私はTF-IDFでスケーリングしません(TF-IDFは、ドキュメントの長さが可変である場合に適しています。私にとって、ツイートは1つまたは2つの文のみであり、テスト結果はTF-IDFで改善を示しませんでした)。

基本的なトークナイザーを使用します。これは非常に基本的ですが、驚くほど便利です。 @#は無視されるため(コンテキストが失われます)、もちろんURLは展開されません。次に、 ロジスティック回帰 を使用してトレーニングしますが、この問題はやや線形に分離可能であるようです(一方のクラスの用語のロットはもう一方のクラスには存在しません)。現在、ステミング/クリーニングを回避しています(動作する可能性のある最もシンプルなものを試しています)。

コードには完全なREADMEが含まれており、比較的簡単にツイートを取り込むことができ、テストのための私の提案に従うことができるはずです。

これはAppleで機能します。人々はAppleコンピューターを食べたり飲んだりせず、フルーツを入力したり遊んだりしないため、単語は簡単に別のカテゴリに分割されます。この条件は、テレビ番組の#definanceのようなものを考慮すると保持されない場合があります(人々は、アラブの春、クリケットの試合、試験の改訂、音楽バンドに関連して#definanceも使用します)。ここでは賢いアプローチが必要になるでしょう。

一連のブログ投稿 BrightonPythonユーザーグループで行った1時間のプレゼンテーション(DataScienceLondonでの140人の短いプレゼンテーションになりました)を含むこのプロジェクトについて説明しています。

LogisticRegression(各分類の確率を取得する)のようなものを使用する場合、自信のある分類のみを選択でき、その方法でリコールと取引することで高精度を強制できます(正しい結果が得られますが、それらの数は少なくなります)。これをシステムに合わせて調整する必要があります。

Scikit-learnを使用した可能なアルゴリズムのアプローチは次のとおりです。

  • バイナリCountVectorizerを使用します(ほとんどの単語は1回しか出現しないため、ショートメッセージの用語カウントが多くの情報を追加するとは思わない)
  • デシジョンツリー分類器から始めます。説明可能なパフォーマンスがあります(例については、デシジョンツリーでのオーバーフィットを参照してください)。
  • ロジスティック回帰に移動
  • 分類子によって生成されたエラーを調査します(DecisionTreeのエクスポートされた出力を読むか、LogisticRegressionの係数を調べ、ベクトライザーを通して誤って分類されたツイートを処理し、基になるBag of Words表現がどのように見えるかを確認します-生のツイートで始めました-分類に十分ですか?)
  • https://github.com/ianozsvald/social_media_brand_disambiguator/blob/master/learn1.py にある私のサンプルコードを見てください。このアプローチの有効なバージョンについては

考慮事項:

  • より大きなデータセットが必要です。私は2000個のラベル付きツイートを使用しています(5時間かかりました)、最低でもクラスごとに100以上のバランスの取れたセットが必要です(以下のオーバーフィットノートを参照してください)
  • トークンに#@を保持するようにトークナイザーを改善し(scikit-learnを使用すると非常に簡単です)、おそらく大文字のブランド検出器を追加します(ユーザー@ user2425429として)
  • 物事が難しくなったとき、非線形分類器(上記の@oiezの提案のような)を考えてください。個人的には、LinearSVCの方がロジスティック回帰よりも悪いことがわかりました(ただし、これは、まだ削減していない高次元の特徴空間による可能性があります)。
  • スピーチタガーのツイート固有の部分(@Neilが示唆するように、スタンドフォードのものではなく、私の謙虚な意見では-私の経験では、貧弱なTwitter文法ではパフォーマンスが低下します)
  • 多くのトークンを取得したら、おそらくいくつかの次元削減を行いたいと思うでしょう(これはまだ試していません-LogisticRegression l1 l2ペナルティに関する私のブログ投稿を参照してください)

Re。オーバーフィット。 2000個のアイテムを含むデータセットには、Twitterから「Apple」のツイートの10分間のスナップショットがあります。ツイートの約2/3はApple Inc向け、1/3は他のApple向けです。各クラスのバランスの取れたサブセット(約584行だと思います)を取り出し、トレーニングのために5倍のクロス検証を行います。

私は10分の時間枠しか持っていないので、同じトピックに関する多くのツイートがあり、これがおそらく私の分類器が既存のツールに比べてうまくいく理由です-よく一般化せずにトレーニング機能に過剰適合します(一方、既存のコマーシャルはこのスナップショップではツールのパフォーマンスは低下しますが、より広範なデータセットでより確実に実行できます。これを後続の作業としてテストするために、時間枠を拡張します。

29
Ian Ozsvald

次のことができます。

  1. 果物や会社関連のツイートでの出現回数を含む単語の辞書を作成します。これは、傾向がわかっているサンプルツイートをフィードに送信することで実現できます。

  2. 十分な以前のデータを使用して、ツイートでWordが発生する確率Apple inc。

  3. 単語の個々の確率を乗算して、ツイート全体の確率を取得します。

簡単な例:

p_f =フルーツツイートの確率。

p_w_f =フルーツツイートで発生する単語の確率。

p_t_f =ツイート内のすべての単語が果物になる確率の組み合わせTweet = p_w1_f * p_w2_f * ...

p_f_t =特定のツイートが与えられた場合の果物の確率。

p_c、p_w_c、p_t_c、p_c_tは会社のそれぞれの値です。

値1のラプラシアンスムーザーを追加して、データベースに存在しない新しい単語の頻度がゼロになる問題を排除します。

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"
11
Sudipta

外部ライブラリの使用に問題がない場合は、 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)

重要なことは、次のような2つのリストが作成されることです。

([['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]は、正と負のラベルを表します。

次に、パイプラインを作成します!パイプラインはscikit-learnクラスであり、テキスト処理ステップを簡単に連結できるため、トレーニング/予測時に1つのオブジェクトを呼び出すだけで済みます。

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

Pipeline内には、3つの処理ステップがあります。 CountVectorizerは、単語をトークン化し、それらを分割し、カウントし、データをスパース行列に変換します。 TfidfTransformerはオプションであり、精度評価に応じて削除することもできます(クロス検証テストと最適なパラメーターのグリッド検索は少し複雑なので、ここでは説明しません)。 LinearSVCは、標準のテキスト分類アルゴリズムです。

最後に、ツイートのカテゴリを予測します。

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

繰り返しになりますが、ツイートはリストにある必要があるため、関数として文字列として入力していると想定しました。

それらをすべてクラスなどに入れれば、完了です。少なくとも、この非常に基本的な例では。

このコードはテストしなかったので、コピーして貼り付けるだけでは機能しない可能性がありますが、scikit-learnを使用する場合は、どこから始めればよいかがわかります。

編集:手順をより詳細に説明しようとしました。

9
oiez

決定木の使用は、この問題に対して非常にうまく機能するようです。少なくとも、選択した機能を備えた単純なベイズ分類器よりも高い精度が得られます。

いくつかの可能性を試してみたい場合は、次のコードを使用できます。これには、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 __== '__main__':
    print check_accurracy()
6
Paul Dubs

これまでのコメントをありがとう。 作業ソリューション は、PHPで準備しました。私はまだ、この同じソリューションに対するよりアルゴリズム的なアプローチを他の人から聞くことに興味があります。

<?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.
5
SAL

条件付きランダムフィールドに基づいて回答を簡素化するために、ここで少し...コンテキストが大きくなります。 Apple the the vs vs Apple the fruit。役立つ機能の一覧をここに示します。詳細については、名詞句のチャンク、およびBIOラベルと呼ばれるものを参照してください。( http://www.cis.upenn.edu/~pereira/papers/crf.pdf を参照してください。 )

周囲の単語:前の単語と次の単語の機能ベクトルを構築します。または、前の2単語と次の2単語の機能をさらに必要とする場合。モデルにあまり多くの単語を入れたくないか、データとあまり一致しません。自然言語処理では、これをできるだけ一般的なものにしたいと思うでしょう。

周囲の単語から取得する他の機能には、次のものがあります。

最初の文字が大文字かどうか

Wordの最後の文字がピリオドかどうか

言葉の品詞(品詞タグ付けの部分を調べてください)

Wordのテキスト自体

これはお勧めしませんが、Apple専用の機能の例をさらに示します。

WordIs(アップル)

NextWordIs(Inc。)

ポイントを取得します。名前付きエンティティの認識は、シーケンスを記述したものと考えてから、数学を使用して計算方法をコンピューターに伝えます。

自然言語処理はパイプラインベースのシステムであることに注意してください。通常、物事を文に分割し、トークン化に移行してから、スピーチのタグ付けや依存関係解析の一部を行います。

これで、探しているものを識別するためにモデルで使用できる機能のリストを取得できます。

4
Adam Gibson

あなたが与えたすべての例では、Apple(inc)は AppleまたはApple 株式会社、したがって、可能な方法は以下を検索することです。

  • appleの大文字「A」

  • appleの後の「inc」

  • 「OS」、「オペレーティングシステム」、「Mac」、「iPhone」などの語句.

  • またはそれらの組み合わせ

4
user2425429

LibShortText を使用します。この Python ユーティリティは、短いテキストの分類タスクで動作するように既に調整されており、正常に動作します。あなたがしなければならない最大のことは、フラグの最適な組み合わせを選択するループを書くことです。私はそれを使用して、電子メールで監視されたスピーチ行為の分類を行い、結果は最大95〜97%の精度でした(5倍のクロス検証中!)。

そして、 [〜#〜] libsvm [〜#〜] および [〜#〜 ] liblinear [〜#〜]サポートベクターマシン (SVM)実装はsklearnおよびcranで使用されるため、それらの実装にバグがないことが合理的に保証されます。

3
Pushpendre

Pythonnltkと呼ばれる自然言語のテキストを処理するための本当に良いライブラリがあります。あなたはそれを見てみるべきです。

あなたが試すことができる一つの戦略は、単語「Apple」が含まれるn-gram(単語のグループ)を調べることです。果物について話すときは「アップル」の横に使用される可能性が高い言葉があり、会社について話すときは他の言葉が使用される可能性が高く、それらを使用してツイートを分類できます。

3
Scott Ritchie

AIフィルターを作成してApple Inc(会社)とAppleを区別します(くだもの)。これらはツイートなので、140フィールドのベクトルでトレーニングセットを定義します。各フィールドは、ツイートの位置X(0〜139)に書き込まれた文字です。ツイートが短い場合は、空の値を指定してください。

次に、適切な精度を得るのに十分なトレーニングセットを作成します(好みに応じて)。結果値を各ツイートに割り当て、Apple IncTweet get 1(true)およびApple Tweet(fruit )は0を取得します。 ロジスティック回帰教師あり学習 の場合です。

それは機械学習であり、一般的にコーディングが簡単で、パフォーマンスが向上します。与えられたセットから学ぶ必要があり、ハードコーディングされていません。

Python がわからないので、そのためのコードを書くことはできませんが、機械学習の論理と理論にもっと時間をかけるなら、私がフォローしているクラスを見てみたいかもしれません。

コースター コース機械学習by Andrew Ng を試してください。 [〜#〜] matlab [〜#〜] または Octave で機械学習を学習しますが、基本を習得すると、機械学習を単純な数学(ロジスティック回帰では単純)を理解している場合は、任意の言語。

つまり、誰かからコードを取得しても、機械学習コードで何が起こっているのかを理解することはできません。実際に何が起こっているのかを確認するために、数時間かけて対象に投資することができます。

2
Fawar

エンティティの認識を示唆する回答を避けることをお勧めします。このタスクは、最初にテキスト分類であり、2番目にエンティティ認識であるためです(エンティティ認識なしで実行できます)。

結果への最速パスは、スペイシー+ 天才 になると思います。 Spacyは英語のモデルを熟考しているため、独自のモデルを作成する必要はありません。天才は、トレーニングデータセットをすばやく作成し、ニーズに合わせてスペイシーモデルを微調整できます。

十分なサンプルがある場合は、1日で適切なモデルを作成できます。

0
Dim