2017-12-18 36 views
0

나는 유사성을 분석 할 필요가있는 수백 개의 txt 파일이있는 폴더가 있습니다. 다음은 유사성 분석을 실행하는 데 사용하는 스크립트의 예입니다. 결국 배열이나 행렬 등을 얻을 수 있습니다.임계 값을 사용하여 행렬 계수 계산

cos_similarity > 0.5 (또는 다른 임계 값을 사용하기로 결정했습니다.) 동일한 파일을 비교할 때 cos_similarity == 1을 제거하면 얼마나 많은 쌍이 있는지 알고 싶습니다. , 당연하지.

두 번째로 파일 이름을 기준으로 이러한 쌍의 목록이 필요합니다.

1

["doc1", "doc4"]

정말 당신의 도움을 주셔서 감사합니다 나는 조금에 어느 방향을 모르고 잃은 느낌으로 : 같은

은 그래서 예를 들어, 출력은 아래에 보일 것이다 가기.

doc1 = "Amazon's promise of next-day deliveries could be investigated amid customer complaints that it is failing to meet that pledge." 
doc2 = "The BBC has been inundated with comments from Amazon Prime customers. Most reported problems with deliveries." 
doc3 = "An Amazon spokesman told the BBC the ASA had confirmed to it there was no investigation at this time." 
doc4 = "Amazon's promise of next-day deliveries could be investigated amid customer complaints..." 
documents = [doc1, doc2, doc3, doc4] 

# In my real script I iterate through a folder (path) with txt files like this: 
#def read_text(path): 
# documents = [] 
# for filename in glob.iglob(path+'*.txt'): 
#  _file = open(filename, 'r') 
#  text = _file.read() 
#  documents.append(text) 
# return documents 

import nltk, string, numpy 
nltk.download('punkt') # first-time use only 
stemmer = nltk.stem.porter.PorterStemmer() 
def StemTokens(tokens): 
    return [stemmer.stem(token) for token in tokens] 
remove_punct_dict = dict((ord(punct), None) for punct in string.punctuation) 
def StemNormalize(text): 
    return StemTokens(nltk.word_tokenize(text.lower().translate(remove_punct_dict))) 

nltk.download('wordnet') # first-time use only 
lemmer = nltk.stem.WordNetLemmatizer() 
def LemTokens(tokens): 
    return [lemmer.lemmatize(token) for token in tokens] 
remove_punct_dict = dict((ord(punct), None) for punct in string.punctuation) 
def LemNormalize(text): 
    return LemTokens(nltk.word_tokenize(text.lower().translate(remove_punct_dict))) 

from sklearn.feature_extraction.text import CountVectorizer 
LemVectorizer = CountVectorizer(tokenizer=LemNormalize, stop_words='english') 
LemVectorizer.fit_transform(documents) 
tf_matrix = LemVectorizer.transform(documents).toarray() 

from sklearn.feature_extraction.text import TfidfTransformer 
tfidfTran = TfidfTransformer(norm="l2") 
tfidfTran.fit(tf_matrix) 
tfidf_matrix = tfidfTran.transform(tf_matrix) 
cos_similarity_matrix = (tfidf_matrix * tfidf_matrix.T).toarray() 

from sklearn.feature_extraction.text import TfidfVectorizer 
TfidfVec = TfidfVectorizer(tokenizer=LemNormalize, stop_words='english') 
def cos_similarity(textlist): 
    tfidf = TfidfVec.fit_transform(textlist) 
    return (tfidf * tfidf.T).toarray() 
cos_similarity(documents) 

아웃 : 나는 당신의 질문을 알 수있는 바와 같이

array([[ 1.  , 0.1459739 , 0.03613371, 0.76357693], 
     [ 0.1459739 , 1.  , 0.11459266, 0.19117117], 
     [ 0.03613371, 0.11459266, 1.  , 0.04732164], 
     [ 0.76357693, 0.19117117, 0.04732164, 1.  ]]) 
+0

보세요! 이전 스 니펫에서는 함수를 왼쪽 및 오른쪽으로 생성하고 있음을 알 수 있습니다. 같은 코드를 반복해서 사용하는 경우에만 함수를 작성하므로 시간과 노력을 절약 할 수 있습니다. 그러나 함수가 단지 한 줄이거나 한 번만 사용하면 더 깨끗하고 읽기 쉽고 이해하기 쉬운 코드를 만들지 않는 것이 좋습니다. –

+0

당신은 절대적으로 옳습니다! 나는이 튜토리얼을 온라인 튜토리얼에서 가져 왔지만 당신이 제안한대로 정리할 것이다. – aviss

+0

keep rockin ', bro –

답변

1

, 당신은 출력 NumPy와 배열을 읽는 기능을 만들려면

은 행렬을 얻기 위해 내 스크립트의 예입니다 및 두 값을 반환하는 특정 값 (임계 값) :

  • 주어진 워드 수보다 많은 워드 프로세서 수 이전
  • 이 문서의 이름입니다.

    • 출력 NumPy와 배열 기능 cos_similarity()에서 :

  • 그래서, 여기에 내가 세 가지 인수를 다음과 같은 기능을했습니다.
  • 문서 이름 목록.
  • 특정 숫자 (임계 값).

그리고 여기에 그것의 :

>>> docs_names = ["doc1", "doc2", "doc3", "doc4"] 
>>> arr = cos_similarity(documents) 
>>> arr 
array([[ 1.  , 0.1459739 , 0.03613371, 0.76357693], 
    [ 0.1459739 , 1.  , 0.11459266, 0.19117117], 
    [ 0.03613371, 0.11459266, 1.  , 0.04732164], 
    [ 0.76357693, 0.19117117, 0.04732164, 1.  ]]) 
>>> threshold = 0.5 
>>> get_docs(arr, docs_names, threshold) 
(1, [('doc1', 'doc4')]) 
>>> get_docs(arr, docs_names, 1) 
(0, []) 
>>> get_docs(lst, docs_names, 0.13) 
(3, [('doc1', 'doc2'), ('doc1', 'doc4'), ('doc2', 'doc4')]) 

이 기능이 어떻게 작동하는지 보자 :

def get_docs(arr, docs_names, threshold): 
    output_tuples = [] 
    for row in range(len(arr)): 
     lst = [row+1+idx for idx, num in \ 
        enumerate(arr[row, row+1:]) if num >= threshold] 
     for item in lst: 
      output_tuples.append((docs_names[row], docs_names[item])) 

    return len(output_tuples), output_tuples 

하는의 행동에 보자 첫번째

  • 을, 나는 모든 행을 반복 numpy 배열의.
  • 둘째, 인덱스가 행 인덱스보다 큰 행의 모든 ​​항목을 반복합니다. 그래서 우리는 다음과 같은 traingular 모양으로 반복합니다 : 그리고 그것은 문서의 각 쌍이 전체 배열에서 두 번 언급 되었기 때문입니다. arr[0][1]arr[1][0]의 두 값이 동일 함을 알 수 있습니다.당신은 또한 대각선 아이템이 포함되어 있지 않음을 알아야합니다. 왜냐하면 우리는 evey 문서가 그 자체와 매우 유사하기 때문에 1이라는 것을 알고 있기 때문입니다. :)
  • 마지막으로 값이 주어진 임계 값보다 크거나 같은 항목을 가져 와서 색인을 반환합니다. 이 색인은 나중에 문서 이름을 가져 오는 데 사용됩니다.
+0

정확히 내가 무엇을 찾고 있었습니까. 정말 고맙습니다. 내가 작성한 함수를 읽고 있는데 대각선 쌍 (num == 1)을 제거하는 방법을 잘 모르겠다. 설명해 주시겠습니까? – aviss

+0

내 대답을 편집했습니다. –

+0

Brilliant! 고맙습니다. – aviss