如何使用pandas列和字典高效构建特征?

我有一个机器学习问题,需要计算pandas数据框文本列与字典值的二元Jaccard相似度。目前我将它们存储为列表,然后转换为列。这在生产环境中证明非常慢。有没有更有效的方法来做这件事?

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

from itertools import tee, islicedef 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:            breakdef 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.nandef 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)

使用上述函数构建二元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 collectionssample_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


回答:

这件事比我想象的要难,因为稀疏矩阵的广播问题。另外,在短时间内我无法完全向量化它。

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

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 collectionssample_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 CountVectorizerfrom scipy.sparse import csr_matriximport numpy as np

并定义一个CountVectorizer来创建基于字符的n_grams

ngram_vectorizer = CountVectorizer(ngram_range=(2, 2), analyzer="char")

你可以自由选择你需要的n-grams。我建议使用现有的分词器和n-gram创建器。你应该能找到很多这样的工具。CountVectorizer也可以进行广泛的调整(例如转换为小写,消除空格等)。

我们连接所有数据:

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

我们这样做,因为我们的向量化器需要为所有出现的标记提供一个共同的索引方案。

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

ngrammed = ngram_vectorizer.fit_transform(all_data) >0

ngrammed现在是一个稀疏矩阵,包含了在各自行中出现的标记的标识符,不再是之前的计数。你可以检查ngram_vecotrizer并找到从标记到列ID的映射。

接下来,我们想将样本字典中的每个grammes条目与我们的ngrammed文本数据的每一行进行比较。我们需要在这里使用一些魔法:

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).astype(bool)    support = texts.maximum(repeated_row_matrix)    intersection = texts.multiply(repeated_row_matrix).todense()    jaccard_similarities.append(pd.Series((intersection.sum(axis=1)/support.sum(axis=1)).A1, name=key))

support是一个布尔数组,用于测量两个可比较对象的n-grams的并集。intersection只有在标记同时存在于两个可比较对象中时才为True。请注意,.A1表示底层基本数组的matrix对象。

现在

pd.concat(jaccard_similarities, axis=1)

得到

         r1        r2        r30  0.631579  0.444444  0.5000001  0.480000  0.333333  0.384615

你也可以将它连接到df,并通过

pd.concat([df, pd.concat(jaccard_similarities, axis=1)], axis=1)  id                          text        r1        r2        r30  1         this is a sample text  0.631579  0.444444  0.5000001  2  this is a second sample text  0.480000  0.333333  0.384615

Related Posts

如何对SVC进行超参数调优?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

如何在初始训练后向模型添加训练数据?

我想在我的scikit-learn模型已经训练完成后再…

使用Google Cloud Function并行运行带有不同用户参数的相同训练作业

我正在寻找一种方法来并行运行带有不同用户参数的相同训练…

加载Keras模型,TypeError: ‘module’ object is not callable

我已经在StackOverflow上搜索并阅读了文档,…

在计算KNN填补方法中特定列中NaN值的”距离平均值”时

当我从头开始实现KNN填补方法来处理缺失数据时,我遇到…

使用巨大的S3 CSV文件或直接从预处理的关系型或NoSQL数据库获取数据的机器学习训练/测试工作

已关闭。此问题需要更多细节或更清晰的说明。目前不接受回…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注