如何在 scikit 学习中对具有多个文本列的数据框进行矢量化而不丢失对原始列的跟踪

How to vectorize a data frame with several text columns in scikit learn without losing track of the origin columns

我有几个 pandas 数据系列,想训练这些数据以映射到输出 df["output"].

至此我已经将系列合二为一,并用逗号分隔。

df = pd.read_csv("sourcedata.csv")
sample = df["catA"] + "," + df["catB"] + "," + df["catC"]

def my_tokenizer(s):
    return s.split(",")

vect = CountVectorizer()
vect = CountVectorizer(analyzer='word',tokenizer=my_tokenizer, ngram_range=(1, 3), min_df=1) 
train = vect.fit_transform(sample.values)

lf = LogisticRegression()
lfit = lf.fit(train, df["output"])
pred = lambda x: lfit.predict_proba(vect.transform([x]))

问题是这是词袋方法,没有考虑
- 每个类别的独特顺序。 ("orange banana" 不同于 "banana orange")
- 文本是一个类别与另一个类别具有不同的意义("US" 在一个类别中可能表示原产国与目的地)

例如,整个字符串可以是:
pred("US, Chiquita Banana, China")
A 类:原产国
B 类:公司和水果类型(顺序很重要)
C 类:目的地

目前我这样做的方式会忽略任何类型的排序,并且出于某种原因还会在我的功能名称中生成额外的空格(这会更加混乱):

In [1242]: vect.get_feature_names()[0:10]
Out[1242]:
[u'',
 u' ',
 u'  ',
 u'   ',
 u'    ',
 u'     ',
 u'   US',
 u'   CA',
 u'   UK']

欢迎提出任何建议!!非常感谢

好的,首先让我们准备您的数据集,方法是选择相关列并使用 strip:

删除前导和尾随空格
sample = df[['catA','catB','catC']]
sample = df.apply(lambda col: col.str.strip())

从这里您可以选择几个选项,了解如何为训练集对其进行矢量化。如果您的所有特征的级别数量较少(比如总共少于 1000 个),您可以简单地将它们视为分类变量并设置 train = pd.get_dummies(sample) 以将它们转换为二进制指示变量。在此之后,您的数据将如下所示:

catA_US   catA_CA ... cat_B_chiquita_banana   cat_B_morningstar_tomato ... catC_China ...
1         0           1                       0                            1   
...

请注意,变量名称以其来源列开头,因此这可确保模型知道它们的来源。此外,您使用的是精确的字符串,因此第二列中的词序将被保留。

如果你有太多的级别使它无法工作,或者你想考虑 catB 中的单个单词以及双字母组,你可以将你的 CountVectorizer 分别应用于每一列,然后使用 hstack 连接生成的输出矩阵:

import scipy.sparse as sp
vect = CountVectorizer(ngram_range=(1, 3))
train = sp.hstack(sample.apply(lambda col: vect.fit_transform(col)))

尝试将您的数据框映射到代表您的数据的字典列表(其中每个条目代表一列),然后编写一个自定义分词器函数,该函数接受字典作为输入并输出特征列表。

在下面的示例中,我创建了一个自定义分词器,它遍历每一列,这样您就可以在将它们附加到您的分词列表之前在函数中对它们进行任何您想做的事情。然后使用 Pandas.

将数据转换为字典列表
def my_tokenizer(d):
    # create empty list to store tokens
    tokens = []

    # do something with catA data
    tokens.append(d['catA'])

    # do something with catB data
    tokens.append(d['catB'].lower())

    return tokens

sample = df[['catA','catB','catC']]
vect = CountVectorizer(tokenizer=my_tokenizer)
train = vect.fit_transform(sample.to_dict(orient='records'))