Python Scikit-Learn 库中分类数据的异常值预测

Posted

技术标签:

【中文标题】Python Scikit-Learn 库中分类数据的异常值预测【英文标题】:Outlier prediction with categorical data in Pythons Scikit-Learn lib 【发布时间】:2020-02-01 11:55:39 【问题描述】:

我试图用我自己的输出进行预测。我使用 Python Scikit-learn lib 和 Isolation Forest 作为算法。 我不知道我做错了什么,但是当我想转换我的输入数据时,我总是会出错。 我在这一行得到一个错误:

    input_par = encoder.transform(val)#ERROR

这是错误: Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample.

我也试过了,但总是报错:

    input_par = encoder.transform([val])#ERROR

这是错误:alueError: Specifying the columns using strings is only supported for pandas DataFrames

我做错了什么,我该如何解决这个错误? 另外,我应该使用OneHotEncoderLabelEncoder 还是CountVectorizer

这是我的代码:

import pandas as pd

from sklearn.ensemble import IsolationForest
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, LabelEncoder

textual_data = ['i love you', 'I love your dress', 'i like that', 'thats good', 'amazing', 'wrong', 'hi, how are you, are you doing good']
num_data = [4, 1, 3, 2, 65, 3,3]

df = pd.DataFrame('my text': textual_data,
                   'num data': num_data)
x = df

# Transform the features
encoder = ColumnTransformer(transformers=[('onehot', OneHotEncoder(), ['my text'])], remainder='passthrough')
#encoder = ColumnTransformer(transformers=[('lab', LabelEncoder(), ['my text'])])

x = encoder.fit_transform(x)

isolation_forest = IsolationForest(contamination = 'auto', behaviour = 'new')
model = isolation_forest.fit(x)

list_of_val = [['good work',2], ['you are wrong',54], ['this was amazing',1]]

for val in list_of_val:

    input_par = encoder.transform(val)#ERROR

    outlier = model.predict(input_par)
    #print(outlier)

    if outlier[0] == -1:
        print('Values', val, 'are outliers')

    else:
        print('Values', val, 'are not outliers')

编辑:

我也试过这个:

list_of_val = [['good work',2], ['you are wrong',54], ['this was amazing',1]]

for val in list_of_val:

    input_par = encoder.transform(pd.DataFrame('my text': val[0],
                                               'num data': val[1]))

但我收到此错误:

ValueError: If using all scalar values, you must pass an index

【问题讨论】:

也发布错误。 我已经更新了问题,我已经添加了错误 上述代码只是将句子编码为一种热编码。您确定要对句子进行编码还是要对句子中包含的标记进行编码。 我想查找异常值,以检查我的输入文本是否异常值,是否可以使用文本数据执行此操作?另外,我应该使用什么编码? 所以我认为你的问题陈述是,根据你想要找到异常值的句子的上下文。您如何确定 -1 预测是异常值?? 【参考方案1】:

我将尝试列出您可能会发现有用的观察结果:

例如,LabelEncoder 可用于将非数字数据转换为数字标签。 OneHotEncoder 通常采用数字或非数字数据并将其转换为 one-hot 编码。两者通常用于预处理“标签”(监督学习问题的类别)。 据我了解,您正在尝试预测异常值(异常检测)。我不清楚话语和整数之间的连接是否只是硬编码的,或者您是否想以某种方式生成这种连接。如果这是您想要的,那么您无法使用前面提到的编码器来实现这一点,因为您正在将它们拟合到一些数据(通常应该是标签)并尝试转换新的不相关数据(ValueError:y 包含以前看不见的标签) .但是,可以通过将 OneHotEncoder 的 handle_unknown 参数设置为“忽略”来解决此问题(来自文档:“如果在转换期间存在未知的分类特征,是否引发错误或忽略”)。即使您可以使用这些编码器之一实现您想要的,您也应该记住,这不是它的主要目的。

我假设您对“负面”话语赋予了较高的价值(即使“错误”不对应于您的训练数据中的 65),而对“正面”话语赋予了较小的价值。如果您假设您已经知道每个话语的每个整数,您可以在被认为是“正”示例的模型上训练模型,并仅在测试中给出“负”示例(异常值)。您不会在“正面”和“负面”示例上训练 IsolationForest - 这只是可以使用决策树建模的基本二元分类。可以看到 IsolationForest 的直观示例here。以下是您的问题的代码:

import numpy as np
from sklearn.ensemble import IsolationForest

textual_data = ['i love you', 'I love your dress', 'i like that', 'thats good', 'amazing', ...]
integer_connection = [1, 1, 2, 3, 2, 2, 3, 1, 3, 4, 1, 2, 1, 2, 1, 2, 1, 1]
integer_connection = np.array([[n] for n in integer_connection])

isolation_forest = IsolationForest(contamination = 'auto', behaviour = 'new')
isolation_forest.fit(integer_encoded)

list_of_val = [['good work', 2], ['you are wrong', 54], ['this was amazing', 1]]

text_vals = [d[0] for d in list_of_val]
numeric_vals = np.array([[d[1]] for d in list_of_val])

print(integer_encoded, numeric_vals)

outliers = isolation_forest.predict(numeric_vals)
print(outliers)

总的来说,我认为您的方法对于自然语言话语的异常值预测是不正确的。对于您在这个特定示例中尝试执行的操作,我可以推荐使用来自例如spaCy 的词向量相似性,或者可能是简单的词袋方法。

如果你不关心这些点,你只想要一个工作代码,这是我想要做的事情的版本:

import numpy as np

from sklearn.ensemble import IsolationForest
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, LabelEncoder


textual_data = ['i love you', 'I love your dress', 'i like that', 'thats good', 'amazing', 'wrong', 'hi, how are you, are you doing good']


encodings = 

num_data = [4, 1, 3, 2, 65, 3, 3]


onehot_encoder = OneHotEncoder(handle_unknown='ignore')
onehots = onehot_encoder.fit_transform(np.array([[utt, no] for utt, no in zip(textual_data, num_data)]))

for i, l in enumerate(onehots):
    original_label = (textual_data[i], num_data[i])
    encodings[original_label] = l

print(encodings)

isolation_forest = IsolationForest(contamination = 'auto', behaviour = 'new')
model = isolation_forest.fit(onehots)

list_of_val = [['good work', 2], ['you are wrong', 54], ['this was amazing', 1]]


test_encoded = onehot_encoder.transform(np.array(list_of_val))
print(test_encoded)

outliers = isolation_forest.predict(test_encoded)
print(outliers)

for i, outlier in enumerate(outliers):
    if outlier == -1:
        print('Values', list_of_val[i], 'are outliers')

    else:
        print('Values', list_of_val[i], 'are not outliers')

【讨论】:

【参考方案2】:

你确定你在做什么有意义吗?您的 OneHotEncoder() 使用 one-hot(又名“one-of-K”或“dummy”)编码方案对分类变量 ('my text') 进行编码。将其视为标签和数字返回之间的映射。

在您的 textual_data 中,您有 7 个不同的标签:['i love you', 'I love your dress', 'i like that', 'thats good', 'amazing', 'wrong', 'hi, how are you, are you doing good']。这些中的每一个都将被编码。这发生在您的:

>>> x = encoder.fit_transform(x)
>>> print(x)
<7x8 sparse matrix of type '<class 'numpy.float64'>'
    with 14 stored elements in Compressed Sparse Row format>

在这里,您的编码器会为所有 7 个标签创建一个映射。

当您继续编写脚本并希望使用相同的编码器来转换新标签时,它会失败:

>>> to_predict = pd.DataFrame('my text': ['good work', 'you are wrong', 'this was amazing'],
                               'num data': [2, 54, 1])
>>> encoder.transform(to_predict)
ValueError: Found unknown categories ['this was amazing', 'good work', 'you are wrong'] in column 0 during transform

它在其映射中找不到这些标签。但是,如果您有新的观察结果,而您的标签是映射的一部分,那么它将能够转换它们:

>>> to_predict = pd.DataFrame('my text': ['i like that', 'i love you', 'i love you'],
                               'num data': [2, 54, 1])
>>> encoder.transform(to_predict)
<3x8 sparse matrix of type '<class 'numpy.float64'>'
    with 6 stored elements in Compressed Sparse Row format>

您可以做的是将这些带有新标签的新观察结果添加到您原来的 df 并通过您的管道再次运行它们,以便它们成为您映射的一部分。

我必须承认我完全没有这方面的经验,所以如果我错了,请纠正我,但在我看来就是这样。祝你的项目好运。

【讨论】:

检查我的问题,我已经更新了。在问题的最后,我提出了我尝试过的内容。我试图将数据框传递给encoder.transform(...),但我得到了同样的错误。当我用分类数据制作回归模型时,我将数据框传递给 encoder.transform(...) 并且它工作了,我不知道为什么现在它不工作了。我做了同样的事情,我只是使用不同的算法 'my text': [val[0]], 'num data': [val[1]] 避免 ValueError: If using all scalar values, you must pass an index 我已经这样做了,我得到了这个错误:ValueError: Found unknown categories ['good work'] in column 0 during transform 这个答案提出了一个很好的观点,您的测试数据包含训练中不存在的类别,所以它永远不会起作用。尝试首先将list_of_val 转换为df,与x 逐行连接,在这个新df 上调用encoder.fit(),然后分别transform 两个dfs【参考方案3】:

你有一个非常相似的问题

AttributeError when using ColumnTransformer into a pipeline

如那里所述,建议使用 pandas 进行编码(还有一个单热编码示例)。希望对您有所帮助!

【讨论】:

我已经尝试过该解决方案,但它不起作用。这就是为什么我问了一个问题并悬赏它【参考方案4】:

尝试通过运行将您的列表 list_of_val 转换为 numpy 数组

import numpy as np
list_of_val = np.asarray(list_of_val)

【讨论】:

还是不行。我收到一个错误:ValueError: Specifying the columns using strings is only supported for pandas DataFrames 【参考方案5】:

当数据是单个变量时收到这样的消息,也称为时间序列:)

PDFPandas DataFrame

### pick real data
X_train = PDF.y          # single dimension, or time-series
y_train = PDF.isAnomaly  # validation variable

### reshape for isolation forest
X_train = np.array(X_train).reshape(-1, 1)

【讨论】:

以上是关于Python Scikit-Learn 库中分类数据的异常值预测的主要内容,如果未能解决你的问题,请参考以下文章

Python Scikit-learn 感知器输出概率

为决策树中的每个数据点找到对应的叶节点(scikit-learn)

具有混合数据类型(文本、数字、分类)的 Python scikit-learn 分类

python 使用scikit-learn框架来分类

python Scikit-Learn的不同分类模型

python 使用scikit-learn进行文档分类