转换为多标签分类

Posted

技术标签:

【中文标题】转换为多标签分类【英文标题】:Transformation to multilabel classification 【发布时间】:2022-01-21 16:39:07 【问题描述】:

我正在尝试在 Python (Keras) 中实现一个神经网络,该网络将预测多个结果的概率。目前我有以下代码,为简单起见,我将问题简化为 3 个输入和 3 个输出:

import keras as k
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

data_frame = pd.read_csv("123.csv")
input_names = ["Sex", "Age", "IQ"]
output_names = ["OUTPUT1", "OUTPUT2", "OUTPUT3"]

raw_input_data = data_frame[input_names]
raw_output_data = data_frame[output_names]

max_age = 100
encoders = "Age": lambda age: [age/max_age],
            "Sex": lambda gen: "male": [0], "female": [1].get(gen),
            "IQ": lambda iq_value: [iq_value],
            "OUTPUT1": lambda output1_value: [output1_value],
            "OUTPUT2": lambda output2_value: [output2_value],
            "OUTPUT3": lambda output3_value: [output3_value]

def dataframe_to_dict(df):
    result = dict()
    for column in df.columns:
        values = data_frame[column].values
        result[column] = values
    return result


def make_supervised(df):
    raw_input_data = data_frame[input_names]
    raw_output_data = data_frame[output_names]
    return "inputs": dataframe_to_dict(raw_input_data),
            "outputs": dataframe_to_dict(raw_output_data)


def encode(data):
    vectors = []
    for data_name, data_values in data.items():
        encoded = list(map(encoders[data_name], data_values))
        vectors.append(encoded)
    formatted = []
    for vector_raw in list(zip(*vectors)):
        vector = []
        for element in vector_raw:
            for e in element:
                vector.append(e)
        formatted.append(vector)
    return formatted


supervised = make_supervised(data_frame)
encoded_inputs = np.array(encode(supervised["inputs"]))
encoded_outputs = np.array(encode(supervised["outputs"]))

train_x = encoded_inputs[:300]
train_y = encoded_outputs[:300]

test_x = encoded_inputs[300:]
test_y = encoded_outputs[300:]

model = k.Sequential()
model.add(k.layers.Dense(units=5, activation="relu"))
model.add(k.layers.Dense(units=1, activation="sigmoid"))
model.compile(loss="mse", optimizer="sgd", metrics=["accuracy"])

fit_results = model.fit(x=train_x, y=train_y, epochs=100, validation_split=0.2)

plt.title("Losses train/validation")
plt.plot(fit_results.history["loss"], label="Train")
plt.plot(fit_results.history["val_loss"], label="Validation")
plt.legend()
plt.show()

plt.title("Accuracies train/validation")
plt.plot(fit_results.history["accuracy"], label="Train")
plt.plot(fit_results.history["val_accuracy"], label="Validation")
plt.legend()
plt.show()

predicted_test = model.predict(test_x)
real_data = data_frame.iloc[300:][input_names+output_names]
real_data["POUTPUT1", "POUTPUT2", "POUTPUT3"] = predicted_test
print(real_data)
real_data.to_csv('C:/***/133.csv')

我需要帮助实现所有 3 个结果 [POUTPUT1、POUTPUT2、POUTPUT3] 的概率输出(当前仅输出 1 个)并将它们保存在如下表中:

【问题讨论】:

【参考方案1】:

您需要调整模型的输入和输出,并将 sigmoid 输出激活更改为支持类别的激活(例如 softmax)尝试如下操作:

INPUT_DIM = 3
OUTPUT_DIM = 3

# first define your model
model = k.models.Sequential()
model.add(k.layers.Dense(8, activation='relu',  input_dim = INPUT_DIM ))
model.add(k.layers.Dense(8, activation='relu'))
  ## you can add more layer if you want, to customize your model
model.add(k.layers.Dense(OUTPUT_DIM, activation='softmax'))

# then compile
model.compile(loss="mse", optimizer="sgd", metrics=["accuracy"])

# then fit
fit_results = model.fit(train_x, train_y, epochs=100, validation_split=0.2)

因此,我使用我建议的更改测试了您的代码,并且网络似乎可以正常工作。 试试这个:

import keras as k
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

data_frame = pd.read_csv("123.csv")
input_names = ["Sex", "Age", "IQ"]
output_names = ["OUTPUT1", "OUTPUT2", "OUTPUT3"]

raw_input_data = data_frame[input_names]
raw_output_data = data_frame[output_names]

max_age = 100
encoders = "Age": lambda age: [age/max_age],
            "Sex": lambda gen: "male": [0], "female": [1].get(gen),
            "IQ": lambda iq_value: [iq_value],
            "OUTPUT1": lambda output1_value: [output1_value],
            "OUTPUT2": lambda output2_value: [output2_value],
            "OUTPUT3": lambda output3_value: [output3_value]

def dataframe_to_dict(df):
    result = dict()
    for column in df.columns:
        values = data_frame[column].values
        result[column] = values
    return result


def make_supervised(df):
    raw_input_data = data_frame[input_names]
    raw_output_data = data_frame[output_names]
    return "inputs": dataframe_to_dict(raw_input_data),
            "outputs": dataframe_to_dict(raw_output_data)


def encode(data):
    vectors = []
    for data_name, data_values in data.items():
        encoded = list(map(encoders[data_name], data_values))
        vectors.append(encoded)
    formatted = []
    for vector_raw in list(zip(*vectors)):
        vector = []
        for element in vector_raw:
            for e in element:
                vector.append(e)
        formatted.append(vector)
    return formatted


supervised = make_supervised(data_frame)
encoded_inputs = np.array(encode(supervised["inputs"]))
encoded_outputs = np.array(encode(supervised["outputs"]))

print(encoded_inputs)
print(encoded_outputs)

train_x = encoded_inputs[:-10]
train_y = encoded_outputs[:-10]

test_x = encoded_inputs[-10:] # I changed this to fit my fake data
test_y = encoded_outputs[-10:] # but you can keep your code.

INPUT_DIM = 3
OUTPUT_DIM = 3

# first define your model
model = k.models.Sequential()
model.add(k.layers.Dense(8, activation='relu',  input_dim = INPUT_DIM ))
model.add(k.layers.Dense(8, activation='relu'))
model.add(k.layers.Dense(OUTPUT_DIM, activation='softmax'))

# then compile
model.compile(loss="mse", optimizer="sgd", metrics=["accuracy"])

# then fit
fit_results = model.fit(train_x, train_y, epochs=100, validation_split=0.2)

# plt.title("Losses train/validation")
# plt.plot(fit_results.history["loss"], label="Train")
# plt.plot(fit_results.history["val_loss"], label="Validation")
# plt.legend()
# plt.show()

# plt.title("Accuracies train/validation")
# plt.plot(fit_results.history["accuracy"], label="Train")
# plt.plot(fit_results.history["val_accuracy"], label="Validation")
# plt.legend()
# plt.show()

predicted_test = model.predict(test_x)
print(predicted_test[0])

然后,当我打印 predicted_test[0] 时,它会给我输出:

[[0.9967424  0.00114053 0.00211706]]

在那之后,我不知道你想对数据框做什么,但我会尝试类似:

real_data = data_frame.iloc[-2:][input_names+output_names]
real_data.reset_index(inplace=True)
real_data["POUTPUT1"] = predicted_test[:,0]
real_data["POUTPUT2"] = predicted_test[:,1]
real_data["POUTPUT3"] = predicted_test[:,2]
print(real_data)
# then save it
real_data.to_csv(...)

第三次编辑以解决您的问题,我认为现在可以了,最初的问题已解决。 如果遇到新问题,您应该关闭此主题并打开一个新主题。

【讨论】:

我可能太从字面上接受了你的建议:D 我收到一个错误:imgur.com/mdZQkvG 制作时:imgur.com/NcXzlU6 我应该在代码的开头进行更改吗?还是我只是错误地执行了您的建议? 是的,太字面了:) 你必须先制作模型(从输入到输出的model.add),然后编译它。我将编辑消息以使其更清晰 我将不胜感激。我对这个神经网络的发展课题很感兴趣,但是理论知识和实践知识都不够的时候很难。 我在编译之前把model.add的部分(和OUTPUT_DIM有关)进行了结转。至于模型的进一步改进,这在理论上是可以理解的。现在,我想弄清楚如何以这种形式启动它。但是问题并没有消除(我什至试着按照你的表格去做,删除了我的插件)。

以上是关于转换为多标签分类的主要内容,如果未能解决你的问题,请参考以下文章

将二进制分类转换为多标签?

转换为多标签分类

为多标签分类评估 DNNClassifier

为多类多标签分类构建混淆矩阵

为多标签分类生成 sklearn 指标的问题

python中的多类分类