【问题标题】:How to solve Scikit learn preprocessing pipeline error with Numpy array?如何使用 Numpy 数组解决 Scikit 学习预处理管道错误?
【发布时间】:2023-04-05 00:13:01
【问题描述】:

我正在使用 scikit-learn 构建一个分类器,用于预测两个句子是否是释义(例如释义:爱因斯坦有多高与阿尔伯特爱因斯坦的长度是多少)。

我的数据包含 2 列带有字符串(短语对)和 1 个带有 0 和 1 的目标列(= 没有释义,释义)。我想尝试不同的算法。

我希望下面的最后一行代码适合模型。相反,预处理管道不断产生我无法解决的错误:“AttributeError:'numpy.ndarray'对象没有属性'lower'。”

代码如下,我已经隔离了显示的最后一行中发生的错误(为简洁起见,我排除了其余部分)。我怀疑是因为目标列包含0和1,不能小写。

我已经在 stackoverflow 上尝试过类似问题的答案,但到目前为止没有运气。

您如何解决这个问题?

question1               question2                        is_paraphrase
How long was Einstein?  How tall was Albert Einstein?    1
Does society place too  How do sports contribute to the  0
much importance on      society?
sports?                 
What is a narcissistic  What is narcissistic personality 1  
personality disorder?   disorder?

======

from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np

para = "paraphrases.tsv"

df = pd.read_csv(para, usecols = [3, 5], nrows = 100, header=0, sep="\t")

y = df["is_paraphrase"].values
X = df.drop("is_paraphrase", axis=1).values
X = X.astype(str) # I have tried this
X = np.char.lower(X)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, 
random_state = 21, stratify = y)

text_clf = Pipeline([('vect', CountVectorizer()),('tfidf', TfidfTransformer()), 
('clf', MultinomialNB())])

text_clf.fit(X_train, y_train)

【问题讨论】:

  • 您的火车数据集由两列组成,对吗? question1question2 ?
  • 是的,训练集有两列。
  • 您可以使用TfidfVectorizer 代替 CountVectorizer 和 TfidfTransformer,这将简化此操作。但是您需要一次处理一列。

标签: python numpy scikit-learn nlp data-preprocessing


【解决方案1】:

错误不是因为最后一列,而是因为您的训练 xdataset 将包含两列 question1question2。现在这将导致您X_train 将每一行作为值列表。因此,当CountVectorizer 尝试将其转换为小写时,它会返回错误,因为 numpy.ndarray 不包含 lower 函数。

要解决此问题,您需要将数据集 X_train 拆分为两部分,例如 X_train_pt1X_train_pt2。然后对这些单独执行 CountVectorizer,然后对每个单独的结果执行 tfidfTransformer。还要确保您在这些数据集上使用相同的对象进行转换。

最后,将这两个数组堆叠在一起,并将其作为分类器的输入。你可以找到类似的implementation here

更新:
我认为以下内容应该会有所帮助(我承认这段代码可以进一步改进以提高效率):

def flat_list(my_list):
    return [str(item) for sublist in my_list for item in sublist]


def transform_data(trans_obj_list,dataset_splits):
    X_train = dataset_splits[0].astype(str)
    X_train = flat_list(X_train)

    for trfs in trans_obj_list:
        transformed_vector = trfs().fit(X_train)
        for x in xrange(0,len(dataset_splits)):
            dataset_splits[x] =flat_list(dataset_splits[x].astype(str))
            dataset_splits[x]=transformed_vector.transform(dataset_splits[x])

    return dataset_splits

new_X_train,new_X_test = transform_data([CountVectorizer,TfidfTransformer],[X_train,X_test])

【讨论】:

  • 是否也可以单独将 X_train 小写并在 CountVectorizer 中“关闭”小写?这样代码可以保持更短(更快)。
  • 即使您以某种方式“关闭”小写字母(尽管这是不可能的),CountVectorizer 也被实现为处理单个字符串而不是字符串列表。您将不得不更改整个实现。因此,更好的做法是创建一个接受 tfIdfTransformer 或 CountVectorizo​​r 对象并执行转换并相应地返回数据的通用函数。
  • 非常感谢。已尝试修改后的答案,但现在遇到了一个新错误:TypeError: no supported conversion for types: (dtype('
  • @twhale 它基本上意味着您的数据包含一些 unicode 字符,您需要将它们编码为 ascii 才能正常工作,因为转换函数仅适用于 ascii 字符串。如果您发现此答案有用,请您投票并将此答案标记为正确答案吗?
猜你喜欢
  • 2018-05-18
  • 2018-07-07
  • 2016-02-14
  • 2014-02-02
  • 2013-12-05
  • 1970-01-01
  • 2019-12-03
  • 2019-03-29
  • 2017-12-19
相关资源
最近更新 更多