As variáveis disponíveis para o problema são:
1) survival: variável binária a ser prevista (output), diz se a pessoa sobreviveu ou não;
2) pclass: classificação do ticket (primeira, segunda ou terceira classe)
3) sex: gênero (masculino ou feminino)
3) age: idade em anos
4) sibsp: número de irmãos/cônjuge a bordo no Titanic
5) parch: número de pais/crianças a bordo no Titanic
6) ticket: número do ticket
7) fare: preço pago pela passagem
8) cabin: número da cabine
9) embarked: portão de embarque (C = Cherbourg, Q = Queenstown e S = Southampton)
Em um primeiro momento, as variáveis escolhidas para prever survival foram: pclass, sex, age, sibsp, parch e fare. Com base nessas variáveis, foram construídos histogramas referentes a cada uma das variáveis e também um gráfico para ver a relação entre pclass e fare (uma vez que elas passam informações muito parecidas). Essa análise das variáveis permite identificar correlação entre variáveis, detectar possíveis outliers, o que influencia na qualidade de previsão do modelo. O código correspondente a essa análise é:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import linear_model, svm
from sklearn.neighbors import KNeighborsClassifier
if __name__ == '__main__':
# Geração de número pseudo aleatório para que o resultado seja
# replicável
RANDOM_SEED = 31
# Lendo os dados
data = np.genfromtxt("train.csv", delimiter = ",", skip_header = 1)
y_data = data[:, 1]
# Selecionando as colunas do arquivo de acordo com as variáveis escolhidas
x_data = data[:,[2, 6, 7, 8, 10]]
y_data = y_data.reshape(891, 1)
# Concatenando x e y em uma matriz
xy_data = np.hstack((x_data, y_data))
xy_data = xy_data[~np.isnan(xy_data).any(axis = 1)]
# Separando novamente o x_data do y_data
x_data = xy_data[:, : - 1]
y_data = xy_data[:, -1]
# Analisando os dados
plt.hist(x_data[:, 0], bins = 3)
plt.xlabel("Passenger Class")
plt.title("Histograma de Passenger Class (pclass)")
plt.show()
plt.hist(x_data[:, 1])
plt.xlabel("Age")
plt.title("Histograma de Age (age)")
plt.show()
plt.hist(x_data[:, 2])
plt.xlabel("Number of siblings/spouses")
plt.title("Histograma de Number of siblings/spouses (sibsp)")
plt.show()
plt.hist(x_data[:, 3])
plt.xlabel("Number of parents/children")
plt.title("Histograma de Number of parents/children (parch)")
plt.show()
plt.hist(x_data[:, 4])
plt.xlabel("Fare")
plt.title("Histograma de Fare (fare)")
plt.show()
plt.hist(y_data, bins = 2)
plt.xlabel("Survived")
plt.title("Histograma de Survived (survived)")
plt.show()
plt.scatter(x_data[:, 0], x_data[:, 4])
plt.xlabel("Pclass")
plt.ylabel("Fare")
plt.show()







Após essa análise das variáveis, foi decidido deixar de utilizar a variável pclass, uma vez que ela já estaria sendo representada pela variável fare. Além disso, há presença de alguns outliers, como pode ser visto pelos histogramas. Contudo, optou-se por utilizar todos os pontos, mas caso o modelo tivesse o desempenho prejudicado, os outliers seriam removidos.
# Remoção da variável pclass
x_data = x_data[:, 1:]
Agora, dividimos os dados em 3 partes: uma para treinamento, outra para validação e seleção do modelo e a terceira para o teste. Como os dados não aparentavam seguir nenhum padrão, ou seja, não estavam "arrumados", dividimos as 3 partes sequencialmente.
# Dividindo os dados em 3 partes: training set, validation set e test set
num_train = int(0.9 * x_data.shape[0]) # num de elementos no training set
num_val = int(0.05 * x_data.shape[0]) # num de elementos no validations set
# Training set
x_train = x_data[:num_train + 1, :]
y_train = y_data[:num_train + 1]
# Validation set
x_val = x_data[num_train + 1:num_train + 1 + num_val + 1, :]
y_val = y_data[num_train + 1:num_train + 1 + num_val + 1]
# Test set
x_test = x_data[num_train + 1 + num_val + 1:, :]
y_test = y_data[num_train + 1 + num_val + 1:]
Por fim, a implementação dos modelos. Todos os modelos foram implementados utilizando o pacote scikit-learn. Os parâmetros de cada modelo foram escolhidos com base no desempenho no validation set. Começamos com o modelo de classificação linear, que funciona como um benchmark para os outros modelos por ser um modelo mais simples. Em seguida, utilizamos o SVM linear com parâmetro de regularização (L2) igual a \(10^{-1}\). Depois implementamos o primeiro modelo não linear, o SVM com polinômio de grau 2. Por fim, fazemos o K Nearest Neighbors com o número de neighbors igual a 1. O código desses modelos e a performance no validation set é:
# Classificação linear (benchmark)
lin_model = linear_model.SGDClassifier(loss = "perceptron",
penalty = "none", max_iter = 10^8,
tol = 1e-5,
random_state = RANDOM_SEED)
lin_model.fit(x_train, y_train)
accuracy = lin_model.score(x_val, y_val)
print("A acurácia do modelo linear no validation set é: " + str(accuracy))
# SVM linear
svm_lin_model = linear_model.SGDClassifier(loss = "hinge",
penalty = "l2", alpha = 1e-1,
max_iter = 10^8,
tol = 1e-5,
random_state = RANDOM_SEED)
svm_lin_model.fit(x_train, y_train)
accuracy = svm_lin_model.score(x_val, y_val)
print("A acurácia do SVM linear no validation set é: " +
str(accuracy))
# SVM não linear
svm_nonlinear_model = svm.NuSVC(kernel = "poly", degree = 2,
max_iter = 10^8,
tol = 1e-5, random_state = RANDOM_SEED)
svm_nonlinear_model.fit(x_train, y_train)
accuracy = svm_nonlinear_model.score(x_val, y_val)
print("A acurácia do SVM não linear no validation set é: "
+str(accuracy))
# K Nearest Neighbors
knn_model = KNeighborsClassifier(n_neighbors = 1)
knn_model.fit(x_train, y_train)
accuracy = knn_model.score(x_train, y_train)
print("A acurácia do modelo K Nearest Neighbors no validation set é: "
+ str(accuracy))
Os resultados obtidos foram:
A acurácia do modelo linear no validation set é: 0.7777777777777778
A acurácia do SVM linear no validation set é: 0.75
A acurácia do SVM não linear no validation set é: 0.8333333333333334
A acurácia do modelo K Nearest Neighbors no validation set é: 0.9720062208398134
Por fim, com os modelos totalmente definidos, tentamos estimar a capacidade de generalização avaliando os modelos no test set.
# Testando os modelos para o test set
accuracy_lin_test = lin_model.score(x_test, y_test)
accuracy_svm_lin_test = svm_lin_model.score(x_test, y_test)
accuracy_svm_nonlinear_test = svm_nonlinear_model.score(x_test, y_test)
accuracy_knn_model_test = knn_model.score(x_train, y_train)
print(accuracy_lin_test)
print(accuracy_svm_lin_test)
print(accuracy_svm_nonlinear_test)
print(accuracy_knn_model_test)
Os resultados obtidos foram:
Modelo linear: 0.6571428571428571
SVM linear: 0.7142857142857143
SVM não linear: 0.6
K Nearest Neighbors: 0.9720062208398134
Pode-se notar que todos os modelos são melhores que simplesmente chutar se a pessoa sobrevive ou não (o que resulta em uma acurácia de 0.5). Além disso, percebe-se que a performance de todos os modelos é melhor no validation set se comparado com o test set. Isso acontece pois escolhemos os parâmetros que produziam o melhor desempenho no validation set. Enquanto isso, o test set possuem dados nunca vistos que são utilizados para estimar a capacidade de generalização dos modelos.
O modelo que apresentou o melhor resultado foi o K Nearest Neighbors com k igual a 1. Nesse modelo, dado um novo ponto para teste, ele escolhe o ponto visto no treinamento mais próximo e atribui a mesma classe para o novo ponto.