2017-05-02 5 views
2

필자는 파이썬에서 텍스트 문장/단락 목록에서 명명 된 엔티티 (NLTK 사용)를 제거하는 몇 가지 사용자 정의 함수를 작성했습니다. 내가 가지고있는 문제는 나의 방법이 매우 느리다는 것이다. 특히 많은 양의 데이터에 대해. 누구든지 더 빨리 달릴 수 있도록 최적화하는 방법에 대한 제안이 있습니까? NLTK를 사용한 빠른 명명 된 엔티티 제거

import nltk 
import string 

# Function to reverse tokenization 
def untokenize(tokens): 
    return("".join([" "+i if not i.startswith("'") and i not in string.punctuation else i for i in tokens]).strip()) 

# Remove named entities 
def ne_removal(text): 
    tokens = nltk.word_tokenize(text) 
    chunked = nltk.ne_chunk(nltk.pos_tag(tokens)) 
    tokens = [leaf[0] for leaf in chunked if type(leaf) != nltk.Tree] 
    return(untokenize(tokens)) 

내가 일반적으로 텍스트 목록이 코드를 사용하고 지능형리스트를 통해 ne_removal 함수를 호출합니다. 아래 예 :

text_list = ["Bob Smith went to the store.", "Jane Doe is my friend."] 
named_entities_removed = [ne_removal(text) for text in text_list] 
print(named_entities_removed) 
## OUT: ['went to the store.', 'is my friend.'] 

업데이트 :이 코드를 사용하여 배치 버전으로 전환하려고 시도했지만 약간 빠릅니다. 계속 탐구 할 것입니다. 지금까지 의견을 보내 주셔서 감사합니다.

def extract_nonentities(tree): 
    tokens = [leaf[0] for leaf in tree if type(leaf) != nltk.Tree] 
    return(untokenize(tokens)) 

def fast_ne_removal(text_list): 
    token_list = [nltk.word_tokenize(text) for text in text_list] 
    tagged = nltk.pos_tag_sents(token_list) 
    chunked = nltk.ne_chunk_sents(tagged) 
    non_entities = [] 
    for tree in chunked: 
     non_entities.append(extract_nonentities(tree)) 
    return(non_entities) 
+1

codereview 로의 마이그레이션이 적절한 지 잘 모르겠습니다. 지나치게 느린 코드 _ 문제는 "코드를 더 잘 구조 할 수 있습니까?"가 아닙니다. – alexis

답변

2

당신이 ne_chunk()를 호출 할 때마다, 그것은 chunker 객체를 초기화하고 디스크에서 청크에 대한 통계 모델을로드 할 필요가있다. 위도는 pos_tag()입니다. 그래서 그 대신 한 번에 하나 개의 문장에 그들을 호출하는, 텍스트의 전체 목록에 자신의 배치 버전을 호출

all_data = [ nltk.word_tokenize(sent) for sent in list_of_all_sents ] 
tagged = nltk.pos_tag_sents(all_data) 
chunked = nltk.ne_chunk_sents(tagged) 

이 당신에게 상당한 속도 향상을 제공해야합니다. 그래도 여전히 느리다면 코드를 프로파일 링하고 @Lenz가 제안한 것처럼 더 강력한 도구로 전환해야하는지 고려해보십시오.

+0

또한,'string.punctuation에없는 '테스트는 문자열을 검색하여'i'를 찾습니다. 'string.punctuation'을 (전역 적으로 정의 된) 세트로 대체하면이 라인이 놀라 울 정도로 빨라질 것입니다. 그러나 이것은 태그 지정과 청킹이 훨씬 더 많은 시간이 소요되기 때문에 전체 런타임의 중요한 부분인지 예측할 수 없습니다. – alexis

+0

고마워요! 나는 배치 버전 (원래 게시물에 추가 된 코드)을 가지고 놀고있다. 나는 1,000 문장으로 시간을 측정했는데, 그 속도는 약간 빨랐다 (구식의 경우 78.9 초 대 옛날의 경우 82.5). 과속을 빠르게하는 쉬운 방법으로 spaCy의 명명 된 엔티티 태그 지정자를 사용하여 탐색 할 수 있습니다. 처음에는'string.punctuation' 변경을 시도하겠습니다. – user1895076

+0

나는 그 말을 듣고 조금 놀랐다. 코드에 문제가없는 한 큰 차이를 만들어야합니다. 그러나 현재 코드를 철저히 프로파일하고 시간이 어디로 갈지 이해할 때까지 다른 태그 작성기를 설치하는 데 시간을 낭비하지 마십시오. 비효율적 인 기본 데이터 관리와 같이 어리석은 일이 아닌지 확인하십시오. – alexis