Search code examples
pythonkerasneural-network

Transformation to multilabel classification


I'm trying to implement a neural network in Python (Keras) that will predict the probability of multiple outcomes. At the moment I have the following code, for simplicity I reduced the problem to 3 inputs and 3 outputs:

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')

I need help implementing the output of probabilities for all 3 outcomes [POUTPUT1, POUTPUT2, POUTPUT3] (currently outputs only 1) and saving them in a table like this one:

enter image description here


Solution

  • You need to adapt input and output of your model, and change your sigmoid output activation for an activation that supports categories (softmax for example) Try something like this:

    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)
    

    So, I tested your code with the changes I suggested, and the network seems to work. Try this :

    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])
    
    

    Then, when i print predicted_test[0], it gives me the outputs :

    [[0.9967424  0.00114053 0.00211706]]
    

    After that, I don't know exactly what you want to do with the dataframe, but I would try something like :

    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(...)
    

    3rd edit to solve your problem, I think it's ok now, the initial question is solve. You should close this topic and open a new one if you encounter a new issue.