如何有效使用熊猫列和字典来构建要素?

问题描述 投票:0回答:1

我有一个机器学习问题,我在计算熊猫数据框文本列的bigram Jaccard相似度与字典值。目前,我将它们存储为列表,然后将其转换为列。事实证明,这在生产中非常缓慢。有没有更有效的方法?

以下是我目前正在执行的步骤:对于字典中的每个键:1.为熊猫列和字典[key]获取二元组2.计算Jaccard相似度3.附加到一个空列表4.将列表存储在数据框中5.将列表转换为列

from itertools import tee, islice

def count_ngrams(lst, n):
    tlst = lst
    while True:
        a, b = tee(tlst)
        l = tuple(islice(a, n))
        if len(l) == n:
            yield l
            next(b)
            tlst = b
        else:
            break

def n_gram_jaccard_similarity(str1, str2,n):

    a = set(count_ngrams(str1.split(),n))
    b = set(count_ngrams(str2.split(),n))

    intersection = a.intersection(b)
    union = a.union(b)

    try:
        return len(intersection) / float(len(union))

    except:
        return np.nan

def jc_list(sample_dict,row,n):
    sim_list = []
    for key in sample_dict:
       sim_list.append(n_gram_jaccard_similarity(sample_dict[key],row["text"],n))

    return str(sim_list)

使用上述功能按如下方式构建bigram Jaccard相似性特征:

df["bigram_jaccard_similarity"]=df.apply(lambda row: jc_list(sample_dict,row,2),axis=1)
df["bigram_jaccard_similarity"] = df["bigram_jaccard_similarity"].map(lambda x:[float(i) for i in [a for a in [s.replace(',','').replace(']', '').replace('[','') for s in x.split()] if a!='']])
df[[i for i in sample_dict]] = pd.DataFrame(df["bigram_jaccard_similarity"].values.tolist(), index= df.index)

样本输入:

df = pd.DataFrame(columns=["id","text"],index=None)
df.loc[0] = ["1","this is a sample text"]

import collections

sample_dict = collections.defaultdict()
sample_dict["r1"] = "this is sample 1" 
sample_dict["r2"] = "is sample" 
sample_dict["r3"] = "sample text 2"

预期输出:

enter image description here

python pandas dataframe machine-learning feature-extraction
1个回答
0
投票

因此,由于某些稀疏矩阵的广播问题,这比我要困难得多。另外,在很短的时间内,我无法完全矢量化它。

我在框架中添加了额外的文本行:

df = pd.DataFrame(columns=["id","text"],index=None)
df.loc[0] = ["1","this is a sample text"]
df.loc[1] = ["2","this is a second sample text"]

import collections

sample_dict = collections.defaultdict()
sample_dict["r1"] = "this is sample 1" 
sample_dict["r2"] = "is sample" 
sample_dict["r3"] = "sample text 2"

我们将使用以下模块/功能/类:

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics import jaccard_score
from scipy.sparse import csr_matrix
import numpy as np

并定义一个CountVectorizer

ngram_vectorizer = CountVectorizer(ngram_range=(1, 2))

随意选择所需的n-gram。在上面的设置中,我们创建1-gram和bi-gram。我们连接所有数据:

all_data = np.concatenate((df.text.to_numpy(),np.array(list(sample_dict.values()))))

我们这样做,因为我们的矢量化器需要针对所有出现的令牌采用通用的索引方案。

现在让我们适合Count矢量化器并相应地转换数据:

ngrammed = ngram_vectorizer.fit_transform(all_data)

ngrammed现在是一个稀疏矩阵,其中包含出现在相应行中的令牌的标识符。您可以检查ngram_vecotrizer 并找到从标记到列ID的映射。

[接下来,我们想将样本字典中的每个gramme条目与ngrammed文本数据的每一行进行比较。我们需要一些魔术:

ngram_vecotrizer

现在:

texts = ngrammed[:len(df)]
samples = ngrammed[len(df):]
text_rows = len(df)

jaccard_similarities = []
for key, ngram_sample in zip(sample_dict.keys(), samples):
    repeated_row_matrix = csr_matrix(np.ones([text_rows,1])) * ngram_sample
    jaccard_similarities.append(pd.Series(jaccard_score(texts.T, repeated_row_matrix.T, average=None), name=key))

给予

pd.concat(jaccard_similarities, axis=1)

您也可以连接到 r1 r2 r3 0 0.714286 0.428571 0.428571 1 0.400000 0.200000 0.333333 并通过]获取>

df

发生魔法的地方发生了什么?首先,我们正在广播我们的稀疏矩阵,即样本字典中与一个键相关的行-与文本匹配,即,将文本的每一行与与键相关的行进行比较。

现在,我们需要了解pd.concat([df, pd.concat(jaccard_similarities, axis=1)], axis=1) id text r1 r2 r3 0 1 this is a sample text 0.714286 0.428571 0.428571 1 2 this is a second sample text 0.400000 0.200000 0.333333 average=None功能中的工作方式。使用此选项,您可以计算两个矩阵的jaccard相似度第I列。最初,我们将观察结果放在行中,因此,我们将转置并将行变成列。

注意,现在,我们仅迭代示例字典中的条目。所有其他迭代实质上都是矢量化的(假设sklearn和scipy为我们完成了vecotization)。很想知道这需要多长时间:)

此外,您可能想调整jaccard_score中的选项,以查看其实际功能

最后但并非最不重要:我认为从我的结果中,您可以轻松地重新创建到目前为止缺少的列。

© www.soinside.com 2019 - 2024. All rights reserved.