Vamos começar importando dados para um pandas DataFrame a partir de um arquivo CSV:
In [1]:
import pandas as pd
In [2]:
raw_data = pd.read_csv('datasets/titanic.csv')
raw_data.head()
Out[2]:
In [3]:
raw_data.info()
A informação acima mostra que esse dataset contém informações sobre 891 passageiros: seus nome, gênero, idade, etc (para uma descrição completa do significado de cada coluna, confira este link).
In [4]:
# POrcentagem de valores em branco em cada coluna
(raw_data.isnull().sum() / len(raw_data)) * 100.0
Out[4]:
Pode-se ver que 77% dos passageiros não apresentam informação sobre em qual cabine eles estavam alojados. Essa informação pode ser útil para análise posterior mas, por enquanto, vamos descartar essa coluna:
In [5]:
raw_data.drop('Cabin', axis='columns', inplace=True)
raw_data.info()
A coluna Embarked, que informa em qual porto o passageiro embarcou, possui apenas algumas poucas linhas em branoc. Como a quantidade de passageiros sem essa informação é pequena, é razoável assumir que eles podem ser descartados do dataset sem grandes prejuízos:
In [6]:
raw_data.dropna(subset=['Embarked'], inplace=True)
(raw_data.isnull().sum() / len(raw_data)) * 100.0
Out[6]:
Finalmente, cerca de 20% dos passageiros não possuem informação de idade. Não parece razoável exluir todos eles e tampouco descartar a coluna inteira, então uma solução possível é preenchermos os valores em branco dessa coluna com o valor mediano dela no dataset:
In [7]:
raw_data.fillna({'Age': raw_data.Age.median()}, inplace=True)
(raw_data.isnull().sum() / len(raw_data)) * 100.0
Out[7]:
A mediana representa uma estatística robusta. Uma estatística é um número que resume um conjunto de valores, enquanto que uma estatística é considerada robusta se ela não for afetada significativamente por variações nos dados.
Suponha, por exemplo, que temos um grupo de pessoas cujas idades sejam [15, 16, 14, 15, 15, 19, 14, 17]. A média de idades nesse grupo é de 15.625. Se uma pessoa de 80 anos for adicionada a esse grupo, a média de idades será agora 22.77, o que não parece representar bem o perfil de idades prevalente desse grupo. A mediana nesses dois exemplos, por sua vez, é de 15 anos - isto é, o valor da mediana não é afetado pela presença de um outlier nos dados, o que a torna uma estatística robusta para as idades desse grupo.
Agora que todas as informações sobre os passageiros no conjunto de dados foram "limpas", podemos começar a analisar os dados.
Vamos começar explorando quantas pessoas nesse dataset sobreviveram ao Titanic:
In [8]:
import matplotlib.pyplot as plt
%matplotlib inline
In [9]:
overall_fig = raw_data.Survived.value_counts().plot(kind='bar')
overall_fig.set_xlabel('Survived')
overall_fig.set_ylabel('Amount')
Out[9]:
No geral, 38% dos passageiros sobreviveram.
Vamos agora segmentar a proporção de pessoas que sobreviveram ao longo de diferentes recortes (o código usado para gerar os gráficos abaixo foram retirados desse link).
In [10]:
survived_sex = raw_data[raw_data['Survived']==1]['Sex'].value_counts()
dead_sex = raw_data[raw_data['Survived']==0]['Sex'].value_counts()
df = pd.DataFrame([survived_sex,dead_sex])
df.index = ['Survivors','Non-survivors']
df.plot(kind='bar',stacked=True, figsize=(15,8));
In [11]:
figure = plt.figure(figsize=(15,8))
plt.hist([raw_data[raw_data['Survived']==1]['Age'], raw_data[raw_data['Survived']==0]['Age']],
stacked=True, color=['g','r'],
bins=30, label=['Survivors','Non-survivors'])
plt.xlabel('Idade')
plt.ylabel('No. passengers')
plt.legend();
In [12]:
import matplotlib.pyplot as plt
figure = plt.figure(figsize=(15,8))
plt.hist([raw_data[raw_data['Survived']==1]['Fare'], raw_data[raw_data['Survived']==0]['Fare']],
stacked=True, color=['g','r'],
bins=50, label=['Survivors','Non-survivors'])
plt.xlabel('Fare')
plt.ylabel('No. passengers')
plt.legend();
Os gráficos acima indicam que passageiros que sejam do gênero feminino, com menos de 20 anos de idade e que pagaram passsagens mais caras tiveram uma maior chance de ter sobrevivido.
Como podemos usar essa informação para tentar prever se um passageiro qualquer teria sobrevivido ao acidente?
Iniciemos então mantendo apenas a informação que queremos utilizar - os nomes de passageiros também serão mantidos para análise posterior:
In [13]:
data_for_prediction = raw_data[['Name', 'Sex', 'Age', 'Fare', 'Survived']]
data_for_prediction.is_copy = False
data_for_prediction.info()
In [14]:
data_for_prediction['Sex'] = data_for_prediction.Sex.map({'male': 0, 'female': 1})
data_for_prediction.info()
Para poder avaliar a capacidade preditiva do modelo, uma parte dos dados (nesse caso, 25%) deve ser separada para um conjunto de teste.
Um conjunto de teste é um dataset para o qual os valores a serem previstos são conhecidos mas que não são usados para treinar o modelo, sendo portanto usados para avaliar quantos acertos o modelo consegue fazer em um conjunto de exemplos que ele nunca viu durante o treinamento. Isso permite que avaliemos, de maneira não-enviesada, o quanto o modelo deve acertar ao ser aplicado a dados reais.
In [15]:
from sklearn.model_selection import train_test_split
train_data, test_data = train_test_split(data_for_prediction, test_size=0.25, random_state=254)
len(train_data), len(test_data)
Out[15]:
Usaremos um simples modelo de Árvore de Decisão para prever se um passageiro teria sobrevivido ao Titanic usando seu gênero, idade e preço de passagem.
In [16]:
from sklearn.tree import DecisionTreeClassifier
tree = DecisionTreeClassifier().fit(train_data[['Sex', 'Age', 'Fare']], train_data.Survived)
tree.score(test_data[['Sex', 'Age', 'Fare']], test_data.Survived)
Out[16]:
Com uma simples árvore de decisão, o resultado cima indica que seria possível prever corretamente a sobrevivência de cerca de 80% dos passageiros.
Um exercício interessante de se fazer após treinar um modelo é dar uma olhada nos casos em que ele erra:
In [17]:
test_data.is_copy = False
test_data['Predicted'] = tree.predict(test_data[['Sex', 'Age', 'Fare']])
test_data[test_data.Predicted != test_data.Survived]
Out[17]:
Um exemplo de previsão incorreta acima é o caso da passageira Mrs. Hudson J C Allison, que não sobreviveu ao acidente do Titanic apesar de ser uma mulher de 25 anos que pagou uma passagem cara. Uma busca na Encyclopedia Titanica mostra que ela foi informada, após já ter sido alocada em um bote salva-vidas, que seu filho seria embarcado em um outro bote que estava no lado oposto do navio - ela, então, fugiu do seu próprio bote em uma tentativa de se juntar a seu filho mas não obteve êxito.
Uma coleção de histórias particularmente interesantes relacionadas a passageiros do Titanic pode ser encontrada nesse post.