簡體   English   中英

用於pandas DataFrame中文本的Jaccard相似度

[英]Jaccard Similarity for Texts in a pandas DataFrame

我想測量pandas DataFrame中文本之間的jaccard相似度。 更確切地說,我有一些實體組,並且在一段時間內每個實體都有一些文本。 我想分析每個實體的文本相似度(這里是Jaccard相似度)隨時間的變化。

一個簡單的例子來說明我的觀點:


import pandas as pd

entries = [
    {'Entity_Id':'Firm1', 'date':'2001-02-05', 'text': 'This is a text'},
    {'Entity_Id':'Firm1', 'date':'2001-03-07', 'text': 'This is a text'},
    {'Entity_Id':'Firm1', 'date':'2003-01-04', 'text': 'No similarity'},
    {'Entity_Id':'Firm1', 'date':'2007-10-12', 'text': 'Some similarity'},
    {'Entity_Id':'Firm2', 'date':'2001-10-10', 'text': 'Another firm'},
    {'Entity_Id':'Firm2', 'date':'2005-12-03', 'text': 'Another year'},
    {'Entity_Id':'Firm3', 'date':'2002-05-05', 'text': 'Something different'}
    ]

df = pd.DataFrame(entries)

Entity_Id日期文本

Firm1   2001-02-05   'This is a text' 
Firm1   2001-03-07   'This is a text'
Firm1   2003-01-04   'No similarity'
Firm1   2007-10-12   'Some similarity'
Firm2   2001-10-10   'Another firm'
Firm2   2005-12-03   'Another year'
Firm3   2002-05-05   'Something different'

我想要的輸出將是這樣的:

Entity_Id日期文本Jaccard

Firm1   2001-02-05   'This is a text'       NaN
Firm1   2001-03-07   'This is a text'       1
Firm1   2003-01-04   'No similarity'        0
Firm1   2007-10-12   'Some similarity'      0.33
Firm2   2001-10-10   'Another firm'         NaN 
Firm2   2005-12-03   'Another year'         0.33  
Firm3   2002-05-05   'Something different'  NaN 

也就是說,我喜歡比較一組公司中的所有文本元素,而不管文本之間的時間間隔。 我想將它與以前的文本進行比較。 因此,每個公司的第一個條目總是空的,因為沒有可比較的文本。

我的方法是按實體標識符將文本移動一個時間間隔(下一個可用日期)。 然后識別每個實體的第一份報告並標記該報告。 (我在text_shifted中輸入NaNs的原始文本,稍后將其刪除 - >需要對整列進行標記化)

df = df.sort_values(['Entity_Id', 'date'], ascending=True)
df['text_shifted'] = df.groupby(['Entity_Id'])['text'].shift(1)
df['IsNaN'] = df['text_shifted'].isnull().astype(int)
df['text_shifted'] = df['text_shifted'].fillna(df['text'])

在下面我使用jaccard相似性如下:

def jaccard_similarity(query, document):
    intersection = set(query).intersection(set(document))
    union = set(query).union(set(document))
    return len(intersection)/len(union)

但是我必須首先對輸入進行標記。 但如果我做的事情如下:

import nltk
df['text_tokens'] = df.text.apply(nltk.word_tokenize)
df['shift_tokens'] = df.text_shifted.apply(nltk.word_tokenize)

在非簡化的文本示例中需要多年來標記文本,其中每個文本大約有5000個單詞,並且我有大約10萬個文本。

有什么方法可以加快這個過程嗎? 我可以避免標記化還是更好地使用sklearn來計算相似度?

如果我使用這里建議的余弦相似度余弦相似性逐行我得到我的結果很快。 但我堅持用jaccard做這件事。

加速該過程的一種方法可以是使用Pandas on Ray進行並行處理。

您可以嘗試使用jaccard_distance的 NLTK實現jaccard相似性。 我找不到處理時間的任何顯着改進(用於計算相似度),可能在更大的數據集上更好地工作。

嘗試將NLTK實現與您的自定義jaccard相似度函數進行比較(平均長度為4個字/令牌的200個文本樣本)

NTLK jaccard_distance:

CPU times: user 3.3 s, sys: 30.3 ms, total: 3.34 s
Wall time: 3.38 s

自定義jaccard相似性實現:

CPU times: user 3.67 s, sys: 19.2 ms, total: 3.69 s
Wall time: 3.71 s

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM