如何在Python Scikit-learn中存储与预向量化X匹配的预测类别?

我想使用名字来预测性别。不仅是名字,还包括从名字中提取的特征,如将“姓氏”作为从名字派生的特征。我的代码流程如下:将数据导入df > 指定lr分类器和dv字典向量化器 > 使用函数创建特征 > 执行字典向量化 > 训练。我想做以下几件事,但找不到任何相关资源。

1) 我想将预测的类别(0和1)添加回原始数据集或我可以看到名字和预测性别类别的数据集。目前我的y_test_predictions仅对应于X_test,这是一个稀疏矩阵。

2) 如何保留训练好的分类器,并用它来预测另一个包含许多名字的数据集的性别?以及如何仅插入一个名字“Rick Grime”,让分类器告诉我它预测的性别是什么?

我曾用nltk做过类似的事情,但在Scikit-learn中找不到任何示例或参考资料。

代码如下:

    import pandas as pd    from pandas import DataFrame, Series    import numpy as np    import re    import random    import time    from random import randint    import csv    import sys    from sklearn.metrics import classification_report    from sklearn.linear_model import LogisticRegression    from sklearn.svm import LinearSVC    from sklearn.tree import DecisionTreeClassifier    from sklearn.naive_bayes import MultinomialNB    from sklearn.feature_extraction import DictVectorizer    from sklearn.metrics import confusion_matrix as sk_confusion_matrix    from sklearn.metrics import roc_curve, auc    import matplotlib.pyplot as plt    from sklearn.metrics import precision_recall_curve    from sklearn import cross_validation     data = pd.read_csv("file.csv", header=0, encoding="utf-8")    df = DataFrame(data)    dv = DictVectorizer()    lr = LogisticRegression()    X = df.raw_name.values    X2 = df.name.values    y = df.gender.values    def feature_full_name(nameString):        try:            full_name = nameString            if len(full_name) > 1: # 不接受只有一个字符的名字                return full_name            else: return '?'        except: return '?'    def feature_full_last_name(nameString):        try:            last_name = nameString.rsplit(None, 1)[-1]            if len(last_name) > 1: # 不接受只有一个字符的名字                return last_name            else: return '?'        except: return '?'    def feature_name_entity(nameString2):        space = 0        try:            for i in nameString2:                if i == ' ':                    space += 1            return space+1        except: return 0    my_dict = [{'last-name': feature_full_last_name(i)} for i in X]    my_dict2 = [{'name-entity': feature_name_entity(feature_full_name(i))} for i in X2]    all_dict = []    for i in range(0, len(my_dict)):        temp_dict = dict(            my_dict[i].items() + my_dict2[i].items()            )        all_dict.append(temp_dict)    newX = dv.fit_transform(all_dict)    X_train, X_test, y_train, y_test = cross_validation.train_test_split(newX, y, test_size=0.3)    lr.fit(X_train, y_train)    y_test_predictions = lr.predict(X_test)

回答:

我会使用Scikit-learn的一些内置工具来分割数据框,向量化名字,并预测结果。然后你可以将预测结果添加回测试数据框中。例如,使用一小组名字作为示例:

data = {'Bruce Lee': 'Male',        'Bruce Banner': 'Male',        'Bruce Springsteen': 'Male',        'Bruce Willis': 'Male',        'Sarah McLaughlin': 'Female',        'Sarah Silverman': 'Female',        'Sarah Palin': 'Female',        'Sarah Hyland': 'Female'}import pandas as pddf = pd.DataFrame.from_dict(data, orient='index').reset_index()df.columns = ['name', 'gender']print(df)                name  gender0    Sarah Silverman  Female1        Sarah Palin  Female2  Bruce Springsteen    Male3       Bruce Banner    Male4          Bruce Lee    Male5       Sarah Hyland  Female6   Sarah McLaughlin  Female7       Bruce Willis    Male

现在我们可以使用Scikit-learn的CountVectorizer来统计名字中的单词;这基本上与你上面所做的输出相同,只是它不根据名字长度等进行过滤。为了便于使用,我们将它与交叉验证的逻辑回归放在一个管道中:

from sklearn.feature_extraction.text import CountVectorizerfrom sklearn.linear_model import LogisticRegressionCVfrom sklearn.pipeline import make_pipelineclf = make_pipeline(CountVectorizer(), LogisticRegressionCV(cv=2))

现在我们可以将数据分割成训练/测试集,拟合管道,然后分配结果:

from sklearn.cross_validation import train_test_splitdf_train, df_test = train_test_split(df, train_size=0.5, random_state=0)clf.fit(df_train['name'], df_train['gender'])df_test = df_test.copy() # 这样我们可以修改它df_test['predicted'] = clf.predict(df_test['name'])print(df_test)                name  gender predicted6   Sarah McLaughlin  Female    Female2  Bruce Springsteen    Male      Male1        Sarah Palin  Female    Female7       Bruce Willis    Male      Male

同样,我们可以将一个名字列表传递给管道并获得预测:

>>> clf.predict(['Bruce Campbell', 'Sarah Roemer'])array(['Male', 'Female'], dtype=object)

如果你想在文本向量化中使用更复杂的逻辑,你可以为你的输入数据创建一个自定义转换器:在网上搜索“scikit-learn custom transformer”应该能给你提供一组不错的示例来参考。


编辑:这里有一个使用自定义转换器从输入名字生成字典的示例:

from sklearn.base import TransformerMixinclass ExtractNames(TransformerMixin):    def transform(self, X, *args):        return [{'first': name.split()[0],                 'last': name.split()[-1]}                for name in X]    def fit(self, *args):        return selftrans = ExtractNames()>>> trans.fit_transform(df['name'])[{'first': 'Bruce', 'last': 'Springsteen'}, {'first': 'Bruce', 'last': 'Banner'}, {'first': 'Sarah', 'last': 'Hyland'}, {'first': 'Sarah', 'last': 'Silverman'}, {'first': 'Sarah', 'last': 'Palin'}, {'first': 'Bruce', 'last': 'Lee'}, {'first': 'Bruce', 'last': 'Willis'}, {'first': 'Sarah', 'last': 'McLaughlin'}]

现在你可以将它与DictVectorizer放在一个管道中来生成稀疏特征:

from sklearn.feature_extraction import DictVectorizerfrom sklearn.pipeline import make_pipelinepipe = make_pipeline(ExtractNames(), DictVectorizer())>>> pipe.fit_transform(df['name'])<8x10 sparse matrix of type '<class 'numpy.float64'>'    with 16 stored elements in Compressed Sparse Row format>

最后,你可以创建一个结合这些与交叉验证的逻辑回归的管道,并按上面的方法进行操作:

clf = make_pipeline(ExtractNames(), DictVectorizer(), LogisticRegressionCV())clf.fit(df_train['name'], df_train['gender'])df_test['predicted'] = clf.predict(df_test['name'])

从这里开始,如果你愿意,你可以修改ExtractNames转换器来进行更复杂的特征提取(使用你上面的一些代码),你最终会得到一个管道实现你的过程,但让你可以简单地在输入字符串列表上调用predict()。希望这对你有帮助!

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

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

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

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