【问题标题】:Jaccard Similarity for Texts in a pandas DataFramepandas DataFrame 中文本的 Jaccard 相似性
【发布时间】:2018-03-07 17:32:34
【问题描述】:

我想测量 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 中输入了 NaN 的原始文本,稍后将其删除 -> 需要将其用于整个列的标记化)

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 来计算相似度?

如果我按照此处的建议使用余弦相似度:Cosine Similarity row-wise 我很快就能得到结果。但我坚持用 jaccard 来做这件事。

【问题讨论】:

  • 您是否尝试过介绍您的工作?基本上看起来标记化是瓶颈

标签: python pandas scikit-learn similarity sklearn-pandas


【解决方案1】:

加快进程的一种方法是使用Pandas on Ray进行并行处理。

您可以尝试使用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

【讨论】:

    猜你喜欢
    • 2011-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-02
    • 2023-03-07
    • 2018-01-23
    • 1970-01-01
    相关资源
    最近更新 更多