2017-08-28 4 views
0

上のテキストのクリーンアップのパフォーマンスの向上しますextractFeatures()をpandas列に適用し、結果が新しい列を作成しています:は私がDFを持つデータフレーム

df['cleanText'] = df['text'].apply(clean) 

結果のDFは:

id cleanText 
1  good sentence 
2  sentence number 
3  third sentence 

ループ時間は指数関数的に増大するように見えます。たとえば、%%timeitを使用して、5行に適用すると、1ループあたり17ミリ秒で実行されます。 300行はループごとに800ミリ秒で実行されます。 500行はループごとに1.26秒で実行されます。

stopsWordNetLemmatizer()は、一度だけ呼び出す必要があるため、関数外でインスタンス化して変更しました。 applyライン上%prun -l 10を実行

stops = set(stopwords.words('english')) 
lem = WordNetLemmatizer() 
def clean(text): 
    lettersOnly = re.sub('[^a-zA-Z]',' ', text) 
    tokens = word_tokenize(lettersOnly.lower()) 
    tokens = [w for w in tokens if not w in stops] 
    tokensPOS = pos_tag(tokens) 
    tokensLemmatized = [] 
    for w in tokensPOS: 
     tokensLemmatized.append(lem.lemmatize(w[0], get_wordnet_pos(w[1]))) 
    clean = " ".join(tokensLemmatized) 
    return clean 

は、この表の結果:

  672542 function calls (672538 primitive calls) in 2.798 seconds 

    Ordered by: internal time 
    List reduced from 211 to 10 due to restriction <10> 

    ncalls tottime percall cumtime percall filename:lineno(function) 
    4097 0.727 0.000 0.942 0.000 perceptron.py:48(predict) 
    4500 0.584 0.000 0.584 0.000 {built-in method nt.stat} 
    3500 0.243 0.000 0.243 0.000 {built-in method nt._isdir} 
    14971 0.157 0.000 0.178 0.000 {method 'sub' of '_sre.SRE_Pattern' objects} 
    57358 0.129 0.000 0.155 0.000 perceptron.py:250(add) 
    4105 0.117 0.000 0.201 0.000 {built-in method builtins.max} 
    184365 0.084 0.000 0.084 0.000 perceptron.py:58(<lambda>) 
    4097 0.057 0.000 0.213 0.000 perceptron.py:245(_get_features) 
     500 0.038 0.000 1.220 0.002 perceptron.py:143(tag) 
    2000 0.034 0.000 0.068 0.000 ntpath.py:471(normpath) 

パーセプトロンタガーは、多くのリソースを取って、予想通り、あるように見えますが、私は合理化するかどうかはわかりませんそれ。また、nt.statまたはnt._isdirがどこに呼び出されているのかわかりません。

パフォーマンスを向上させるには、機能を変更するか、メソッドを適用する必要がありますか?この関数はCythonまたはNumbaの候補ですか?私はここを参照してください改善の

+0

あなたのデータと予想される出力がないと言うことはできません。 –

+0

サンプル入力データとクリーニング機能の結果を追加しました。私は適切な出力を得ています。質問はその適切な出力をより早く得る方法に関するものです。 –

+0

興味深い。単語の順序は重要ですか?はい、私は推測していますか? –

答えて

2

最初の明白なポイントは、全体get_wordnet_pos関数が辞書引きに還元可能でなければならないことである。これに代えて

def get_wordnet_pos(treebank_tag): 
    if treebank_tag.startswith('J'): 
     return wordnet.ADJ 
    elif treebank_tag.startswith('V'): 
     return wordnet.VERB 
    elif treebank_tag.startswith('N'): 
     return wordnet.NOUN 
    elif treebank_tag.startswith('R'): 
     return wordnet.ADV 
    else: 
     return wordnet.NOUN 

collectionsパッケージからdefaultdictを初期化:

import collections 
get_wordnet_pos = collections.defaultdict(lambda: wordnet.NOUN) 
get_wordnet_pos.update({'J' : wordnet.ADJ, 
         'V' : wordnet.VERB, 
         'N' : wordnet.NOUN, 
         'R' : wordnet.ADV }) 

このようにルックアップにアクセスします。

get_wordnet_pos[w[1][0]] 

次に、正規表現パターンを複数の場所で使用する場合は、正規表現パターンをあらかじめコンパイルすることを検討できます。あなたが得るスピードアップはそれほど重要ではありませんが、それはすべて重要です。あなたは、あなたがあなたのテキストがどこから来ているのを認識している場合、

pattern.sub(' ', text) 

OTOH、あなたはと表示されない場合がありますかもしれないもののいくつかのアイデアを持っている:あなたの関数の内部

pattern = re.compile('[^a-zA-Z]') 

、あなたが呼びたいです文字のリストをプリコンパイルし、代わりに不格好な正規表現ベースの置換よりもはるかに高速である、str.translateを使用することができます。さらに

tab = str.maketrans(dict.fromkeys("[email protected]#$%^&*()_+-={}[]|\'\":;,<.>/?\\~`", '')) # pre-compiled use once substitution table (keep this outside the function) 

text = 'hello., hi! lol, what\'s up' 
new_text = text.translate(tab) # this would run inside your function 

print(new_text) 

'hello hi lol whats up' 

、私はword_tokenizeがoverkだと思いますとにかく特殊文字を取り除くことで、word_tokenizeのメリットがすべて失われてしまい、実際に句読点などに違いがあります。 text.split()にフォールバックすることができます。

最後に、clean = " ".join(tokensLemmatized)のステップをスキップします。リストを返信し、最後のステップでdf.applymap(" ".join)に電話してください。

私はあなたにベンチマークを残します。

+0

ありがとうございます - 非常に役に立ちます。 defaultdictの場合、 'TypeError: 'collections.defaultdict' object is not callable'というエラーをスローします。それとは別に、置き換えと分割についてあなたが言っていることは、多くの意味があります。 –

+0

@CameronTaylor小さな間違いがあります。 '(...) 'ではなく、' get_wordnet_pos [...] 'のようにdictを呼び出します。私の答えを編集します。 –

+0

それは、元の関数では、タグは 'startswith'によって見つけられるかもしれません。それを 'defaultdict'に実装する方法はありますか?現時点では、多くのタグが単なる1文字以上のものであるため、ほとんどのものを名詞として扱っていると私は信じています。 –

関連する問題