如何在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

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

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