2017-06-08 3 views
1

したがって、私は電話通話記録のモデルを訓練することを任されています。次のコードはこれを行います。小さな背景情報: - xは文字列のリストで、各i番目の要素は全体の文字列です - yはブール値のリストで、コールの結果が正または負であることを示します。SKLearn Naive Bayes:tfidfベクトル化後に機能を追加する

次のコードは機能しますが、ここに私の問題があります。 私は列車に乗るための機能として通話時間を含める必要があります。私はトランスクリプトをベクトル化するTFIDFトランスフォーマの後に、TFIDF出力にコール期間機能を連結したものと仮定します。たぶんこれは思ったより簡単ですが、コードの冒頭に表示されるパンダのデータフレームにトランスクリプトと期間があります。 データフレーム列(numpy配列)の期間がある場合、モデルにその機能を追加するには何が必要ですか?

追加の質問:

  • 私はベクトル化された文字列に私を制限ナイーブベイズモデルについての基本的な前提足りませんか?
  • 私のパイプラインのどのステップで、新しい機能を追加しますか?
  • これをパイプラインで実行することはできますか、それともこのようなことをするために分割する必要がありますか?

コード:

import numpy as np 
import pandas as pd 
import random 
from sklearn.naive_bayes import GaussianNB 
from sklearn.naive_bayes import MultinomialNB 
from sklearn.feature_extraction.text import CountVectorizer 
from sklearn.datasets import fetch_20newsgroups 
from sklearn.feature_extraction.text import TfidfTransformer 
from sklearn.pipeline import Pipeline 
from sklearn.linear_model import SGDClassifier 
from sklearn.grid_search import GridSearchCV 
from sklearn.cross_validation import cross_val_score 
from sklearn.feature_selection import SelectPercentile 
from sklearn.metrics import roc_auc_score 
from sklearn.feature_selection import chi2 


def main(): 
filename = 'QA_training.pkl' 
splitRatio = 0.67 
dataframe = loadData(filename) 
x, y = getTrainingData(dataframe) 
print len(x), len(y) 

x_train, x_test = splitDataset(x, splitRatio) 
y_train, y_test = splitDataset(y, splitRatio) 

#x_train = np.asarray(x_train) 

percentiles = [10, 15, 20, 25, 30, 35, 40, 45, 50] 

MNNB_pipe = Pipeline([('vec', CountVectorizer()),('tfidf', TfidfTransformer()),('select', SelectPercentile(score_func=chi2)),('clf', MultinomialNB())]) 
MNNB_param_grid = { 
#'vec__max_features': (10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000), 
'tfidf__use_idf': (True, False), 
'tfidf__sublinear_tf': (True, False), 
'vec__binary': (True, False), 
'tfidf__norm': ('l1', 'l2'), 
'clf__alpha': (1, 0.1, 0.01, 0.001, 0.0001, 0.00001), 
'select__percentile': percentiles 
} 
MNNB_search = GridSearchCV(MNNB_pipe, param_grid=MNNB_param_grid, cv=10, scoring='roc_auc', n_jobs=-1, verbose=1) 
MNNB_search = MNNB_search.fit(x_train, y_train) 
MNNB_search_best_cv = cross_val_score(MNNB_search.best_estimator_, x_train, y_train, cv=10, scoring='roc_auc', n_jobs=-1, verbose=10) 

SGDC_pipe = Pipeline([('vec', CountVectorizer()),('tfidf', TfidfTransformer()),('select', SelectPercentile(score_func=chi2)),('clf', SGDClassifier())]) 
SGDC_param_grid = { 
#'vec__max_features': [10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000], 
'tfidf__use_idf': [True, False], 
'tfidf__sublinear_tf': [True, False], 
'vec__binary': [True, False], 
'tfidf__norm': ['l1', 'l2'], 
'clf__loss': ['modified_huber','log'], 
'clf__penalty': ['l1','l2'], 
'clf__alpha': [1e-3], 
'clf__n_iter': [5,10], 
'clf__random_state': [42], 
'select__percentile': percentiles 
} 
SGDC_search = GridSearchCV(SGDC_pipe, param_grid=SGDC_param_grid, cv=10, scoring='roc_auc', n_jobs=-1, verbose=1) 
SGDC_search = SGDC_search.fit(x_train, y_train) 
SGDC_search_best_cv = cross_val_score(SGDC_search.best_estimator_, x_train, y_train, cv=10, scoring='roc_auc', n_jobs=-1, verbose=10) 

# pre_SGDC = SGDC_clf.predict(x_test) 
# print (np.mean(pre_SGDC == y_test)) 

mydata = [{'model': MNNB_search.best_estimator_.named_steps['clf'],'features': MNNB_search.best_estimator_.named_steps['select'], 'mean_cv_scores': MNNB_search_best_cv.mean()}, 
      #{'model': GNB_search.best_estimator_.named_steps['classifier'],'features': GNB_search.best_estimator_.named_steps['select'], 'mean_cv_scores': GNB_search_best_cv.mean()}, 
      {'model': SGDC_search.best_estimator_.named_steps['clf'],'features': SGDC_search.best_estimator_.named_steps['select'], 'mean_cv_scores': SGDC_search_best_cv.mean()}] 
model_results_df = pd.DataFrame(mydata) 
model_results_df.to_csv("best_model_results.csv") 
+0

FWIWでは、CountVectorizer + TfidfTransformerを単純なTfidfVectorizerに集約したいと思うかもしれませんが、これは単なるマイナーコード簡略化のポイントです。それはアルゴリズムをまったく変えません。 – mgilson

+0

はい、その観測に感謝します! –

答えて

1

限り、私は承知しているとして、sklearnパイプラインは、API駆動型です - パイプライン自体に起こる本当の魔法はありません。したがって、その観点からは、あなたがしたいことを行うTfidfVectorizerの周りに独自のラッパーを作成できるはずです。

class MyVectorizer(object): 
    def __init__(self, tfidf_kwargs=None): 
     self._tfidf = TfidfVectorizer(**(tfidf_kwargs or None)) 

    def fit(self, X, y=None): 
     self._tfidf.fit(X['text'], y) 
     return self 

    def fit_transform(self, X, y=None): 
     self.fit(X) 
     return self.transform(X, copy=False) 

    def transform(self, X, copy=True): 
     result = self._tfidf.transform(X['text'], copy=copy) 
     # result is a sparse matrix. I'm not sure of a clean way 
     # to add a column to a sparse matrix. If you have the 
     # memory, you can use a dense matrix instead... 
     return np.column_stack((result, X['duration'])) 

をそして私はあなたがこのすべてを使用するように設定されるべきだと思う:

df = pd.DataFrame({'text': ['foo text', 'bar text'], 'duration': [1, 2]}) 

あなたはおそらく次のようにあなたの変換を実現することができます。たとえば、あなたがこのようになりますDATAFRAMEを持っていると仮定しましょう元のtfidfベクトル化器の代わりに。

関連する問題