【问题标题】:MultiLabelBinarizer mixes up data when inverse transformingMultiLabelBinarizer 在逆变换时混淆数据
【发布时间】:2019-01-24 23:03:33
【问题描述】:

我正在使用sklearnmultilabelbinarizer() 来训练我用来训练模型的机器学习中的多个列。

使用它后,我注意到它在对数据进行逆变换时混淆了我的数据。我创建了一个随机值的测试集,我在其中拟合数据、对其进行转换,然后将数据inverse_transform 以返回原始数据。

我在jupyter notebook 中运行了一个简单的测试来显示错误:

inverse_transformed 值中,它在第 1 行中混淆了州和月份。

jupyter notebook code

首先,我如何使用multilabelbinarizer 有错误吗?有没有不同的方法来实现相同的输出?

编辑: 感谢@Nicolas M. 帮助我解决了我的问题。我最终像这样解决了这个问题。

请原谅粗略的解释,但事实证明它比我最初想象的要复杂。我改用label_binarizer 而不是multi_label_binarizer,因为它

我最终腌制了label_binarizer defaultdict,这样我就可以加载它并在我的机器学习项目的不同模块中使用它。

可能不是微不足道的一件事是我为每列创建的数据框添加了新标题。它的形式为 column_name + 列号。我这样做是因为我需要对数据进行逆变换。为此,我搜索了包含原始列名的列,这些列名将较大的数据框分隔成各个列块。

这里有一些我使用的变量以及它们的参考意义:
lb_dict - 存储不同标签二值化器的默认字典。
binarize_df - 存储二值化数据的数据框。
@ 987654334@ - 标签对列中的一个标签进行二值化。
header - 创建新的标题形式:列名 + 编号列。

inverse_df - 存储 inverse_transformed 数据的数据框。
one_label_list - 查找具有原始列标签的列名列表。
one_label_df - 创建一个仅存储二值化数据的新数据框一列的数据。
single_label - 被 inverse_transformed 转换为一列的二值化数据。

在这段代码中,数据是我传递给函数的数据帧。

lb_dict = defaultdict(LabelBinarizer)
# create a place holder dataframe to join new binarized data to
binarize_df = pd.DataFrame(['x'] * len(data.index), columns=['place_holder'])

# loop through each column and create a binarizer and fit/transform the data
# add new data to the binarize_df dataframe
for column in data.columns.values.tolist():

    lb_dict[column].fit(data[column])
    binarized_label = lb_dict[column].transform(data[column])

    header = [column + str(i) for i in range(0, len(binarized_label[0]))]

    binarize_df = binarize_df.join(pd.DataFrame(binarized_label, columns=header))

# drop the place holder value
binarize_df.drop(labels=['place_holder'], axis=1, inplace=True)

这是我写的 inverse_transform 函数:

inverse_df = pd.DataFrame(['x'] * len(output.index), columns=['place_holder'])

# use a for loop to run through the different output columns that need to be inverse_transformed
for column in output_cols:
    # create a list of the different headers based on if the name contains the original output column name
    one_label_list = [x for x in output.columns.values.tolist() if column in x]
    one_label_df = output[one_label_list]

    # inverse transform the data frame for one label
    single_label = label_binarizer[column].inverse_transform(one_label_df.values)

    # join the output of the single label df to the entire output df
    inverse_df = inverse_df.join(pd.DataFrame(single_label, columns=[column]))

inverse_df.drop(labels=['place_holder'], axis=1, inplace=True)

【问题讨论】:

  • 为什么您的代码在图片中,而不是在您的问题中?我当然更喜欢复制粘贴你的代码而不是把它打出来,我相信其他人也有同样的感觉。您需要让人们更容易提供帮助。

标签: python pandas machine-learning sklearn-pandas multilabel-classification


【解决方案1】:

问题来自数据(在这种情况下是模型使用不当)。如果您创建 MultiLabelBinarizer 的数据框,您将拥有:

您可以看到所有列都按升序排序。当您要求重构时,模型将通过逐行“扫描”值来重构它。

所以,如果你选择第一行,你就有:

1000 - 加利福尼亚 - 一月

现在如果你拿第二个,你有:

750 - 2 月 - 纽约

等等……

因此,由于排序顺序,您的月份被交换了。如果你用“ZFebrury”替换月份,它会没问题,但仍然只能用“luck”

您应该做的是为每个分类特征训练 1 个模型并堆叠每个矩阵以获得最终矩阵。要还原它,您应该提取“sub_matrix”并执行inverse_transform

要为每个特征创建 1 个模型,您可以参考 Napitupulu Jon 在此 SO question

中的回答

编辑 1:

我尝试了 SO question 中的代码,但随着列数的变化,它不起作用。这就是我现在所拥有的(但您仍然必须将每个功能的列保存在某处)

import pandas as pd
import numpy as np
from sklearn.preprocessing import MultiLabelBinarizer
from collections import defaultdict

data = {
    "State" : ["California", "New York", "Alaska", "Arizona", "Alaska", "Arizona"],
    "Month" : ["January", "February", "May", "February", "January", "February" ],
    "Number" : ["1000", "750", "500", "25000", "2000", "1"]
}
df = pd.DataFrame(data)

d = defaultdict(MultiLabelBinarizer)  # dict of Features => model

list_encoded = []  # store single matrices
for column in df:
    d[column].fit(df[column])
    list_encoded.append(d[column].transform(df[column]))
merged = np.hstack(list_encoded) # matrix of 6 x 32

希望对你有帮助,而且解释清楚,

尼古拉斯

【讨论】:

  • 非常感谢。我会试一试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多