python - 如何使用 pandas 列和字典有效地构建特征?

标签 python pandas dataframe machine-learning feature-extraction

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

以下是我目前正在执行的步骤: 对于字典中的每个键: 1. 获取 pandas 列和 dict[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)

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

最佳答案

所以,由于稀疏矩阵的一些广播问题,这比我更困难。此外,在短时间内我无法将其完全矢量化。

我向框架添加了一个额外的文本行:

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 scipy.sparse import csr_matrix
import numpy as np

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

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

随意选择您需要的 n 元语法。我建议采用现有的分词器和 n-gram 创建器。你应该找到很多这样的。此外,CountVectorizer 可以进行广泛的调整(例如转换为小写、删除空格等)

我们连接所有数据:

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

我们这样做是因为我们的向量化器需要为所有出现的标记有一个通用的索引方案。

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

ngrammed = ngram_vectorizer.fit_transform(all_data) >0

ngrammed 现在是一个稀疏矩阵,其中包含出现在相应行中的标记的标识符,而不是像以前那样包含计数。您可以检查ngram_vecotrizer 并找到从标记到列 ID 的映射。

接下来,我们要将示例字典中的每个语法条目与 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 是 bool 数组,用于测量两个可比较的 n 元语法的并集。仅当两个可比对象中都存在标记时,intersection 才为 True。请注意,.A1 表示一个矩阵对象作为底层基本数组。

现在

pd.concat(jaccard_similarities, axis=1)

给出

         r1        r2        r3
0  0.631579  0.444444  0.500000
1  0.480000  0.333333  0.384615

您也可以将 is 与 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.631579  0.444444  0.500000
1  2  this is a second sample text  0.480000  0.333333  0.384615

关于python - 如何使用 pandas 列和字典有效地构建特征?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58250720/

相关文章:

python - 向 Pandas 数据框索引添加名称

python - 运行时错误 : There is no current event loop in thread 'Dummy-1'

python - 为什么要继承对象类型

python - 如何在 python 中将 csv 的列值转换为多行

python - 计算行级 Pandas 数据框中空单元格的数量并相应地创建一列

python - Pandas fillna() 按特定顺序排列

python - 如何以表格的形式进行抓取,使列表变得均匀

python - 在带有 Matplotlib 的 Python 中,如何检查图中的子图是否为空

python - pandas,尝试从行数太多的数据帧中仅对每个 movie_id 采样 5 行

python - 如何在 pandas 数据框中通过两列和第三列求和来从组中获取最大值?