我想测量熊猫数据框架中文本之间的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个单词,而我有大约100 000个文本。
有什么办法可以加快流程?我可以避免使用令牌化还是更好地使用Sklearn来计算相似性?
如果我使用此处建议的余弦相似性:余弦相似性行,我会很快获得结果。但是我与jaccard一起工作。
加快该过程的一种方法可以是使用射线上的pandas并行处理。
您可以尝试使用jaccard_distance的NLTK实现Jaccard相似性。不过,我找不到处理时间的显着改善(用于计算相似性),在较大的数据集上可能会更好地工作。
尝试将NLTK实现与您的自定义JACCARD相似性函数进行比较(在200个平均长度4个单词/令牌的文本样本上)
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