Neste tutorial iremos apresentar a implentação do algoritmo Naive Bayes usando aplicado a dados numéricos. Utilizaremos neste tutorial o conjunto de dador denominado Pima Inidians Diabetes, utilizado para predizer início de diabetes veja neste link.
Este problema é composto por 768 observações de detalhes médicos de pacientes indianas. Os registros descrevem as medidas instantâneas tomadas do paciente, como sua idade, o número de vezes grávidas e o tratamento do sangue. Todos os pacientes são mulheres com idade igual ou superior a 21 anos. Todos os atributos são numéricos, e suas unidades variam de atributo a atributo.
Cada registro tem um valor de classe que indica se o paciente sofreu um início de diabetes dentro de 5 anos de quando as medidas foram tomadas (1) ou não (0).
Este é um conjunto de dados padrão que tem sido estudado muito na literatura de aprendizagem de máquinas. Uma boa precisão de predição é de 70% a 76%.
A primeira coisa que precisamos fazer é carregar nosso arquivo de dados. Os dados estão no formato CSV sem linha de cabeçalho. Podemos abrir o arquivo com a função open e ler as linhas de dados usando a função de leitor no módulo csv.
Também precisamos converter os atributos que foram carregados como strings em números para que possamos trabalhar com eles. Abaixo está a função loadCsv () para carregar o conjunto de dados Pima indians.
In [13]:
import csv
def loadCsv(filename):
lines = csv.reader(open(filename, "r"))
dataset = list(lines)
for i in range(len(dataset)):
dataset[i] = [float(x) for x in dataset[i]]
return dataset
In [14]:
### COLOQUE SUA RESPOSTA AQUI
Em seguida, precisamos dividir os dados em um conjunto de dados de treinamento, o qual possa ser usado pelo Naive Bayes para fazer previsões e um conjunto de dados de teste para que possamos usar para avaliar a precisão do modelo. Precisamos dividir o conjunto de dados aleatoriamente em treino e teste, em conjuntos de dados com uma proporção de 67% de treinamento e 33% de teste (esta é uma razão comum para testar um algoritmo em um conjunto de dados).
Abaixo está a função splitDataset () que dividirá um determinado conjunto de dados em uma proporção de divisão determinada.
In [15]:
import random
def splitDataset(dataset, splitRatio):
trainSize = int(len(dataset) * splitRatio)
trainSet = []
copy = list(dataset)
while len(trainSet) < trainSize:
index = random.randrange(len(copy))
trainSet.append(copy.pop(index))
return [trainSet, copy]
In [16]:
### COLOQUE SUA RESPOSTA AQUI
O modelo do Naive Bayes é composto basicamente pela sumarização do conjunto de dados de treinamento. Este sumário é então usado ao fazer previsões.
O resumo dos dados de treinamento coletados envolve a média e o desvio padrão para cada atributo, pelo valor da classe. Por exemplo, se houver dois valores de classe e 7 atributos numéricos, então precisamos de um desvio padrão e médio para cada combinação de atributo (7) e valor de classe (2), ou seja, 14 resumos de atributos. Estes são necessários ao fazer previsões para calcular a probabilidade de valores de atributos específicos pertencentes a cada valor de classe.
Para sumarizar os dados criamos as seguintes subtarefas:
A primeira tarefa é separar as instâncias do conjunto de dados de treinamento pelo valor da classe para que possamos calcular as estatísticas para cada classe. Podemos fazer isso criando um mapa de cada valor de classe para uma lista de instâncias que pertencem a essa classe e classificar todo o conjunto de dados de instâncias nas listas apropriadas.
A função separadaByClass () abaixo faz isso.
In [17]:
def separateByClass(dataset):
separated = {}
for i in range(len(dataset)):
vector = dataset[i]
if (vector[-1] not in separated):
separated[vector[-1]] = []
separated[vector[-1]].append(vector)
return separated
Teste este função com alguns exemplos de dados sintéticos e imprima as classes separadas com seus respectivas instancias. Perceba no exemplo acima que a classe se refere ao último elemento do vetor. Segue um exemplo de saída:
"Instancias separadas por classes: {1: [[1, 20, 1], [3, 22, 1]], 0: [[2, 21, 0]]}"
In [18]:
### COLOQUE SUA RESPOSTA AQUI
Precisamos calcular a média de cada atributo para um valor de classe. A média é a tendência central central ou central dos dados, e vamos usá-lo como meio de nossa distribuição gaussiana ao calcular probabilidades.
Também precisamos calcular o desvio padrão de cada atributo para um valor de classe. O desvio padrão descreve a variação da disseminação dos dados, e vamos usá-lo para caracterizar a propagação esperada de cada atributo em nossa distribuição gaussiana ao calcular probabilidades.
O desvio padrão é calculado como a raiz quadrada da variância. A variância é calculada como a média das diferenças quadradas para cada valor de atributo da média. Observe que estamos usando o método N-1, que subtrai 1 do número de valores de atributo ao calcular a variância.
In [19]:
import math
def mean(numbers):
return sum(numbers)/float(len(numbers))
def stdev(numbers):
avg = mean(numbers)
variance = sum([pow(x-avg,2) for x in numbers])/float(len(numbers)-1)
return math.sqrt(variance)
In [20]:
### COLOQUE SUA RESPOSTA AQUI
Agora temos as ferramentas para resumir um conjunto de dados. Para uma determinada lista de instâncias (para um valor de classe), podemos calcular a média e o desvio padrão para cada atributo.
A função zip agrupa os valores de cada atributo em nossas instâncias de dados em suas próprias listas para que possamos calcular os valores de desvio padrão e média para o atributo.
In [21]:
def summarize(dataset):
summaries = [(mean(attribute), stdev(attribute)) for attribute in zip(*dataset)]
del summaries[-1]
return summaries
In [22]:
### COLOQUE SUA RESPOSTA AQUI
In [23]:
def summarizeByClass(dataset):
separated = separateByClass(dataset)
summaries = {}
for classValue, instances in separated.items():
summaries[classValue] = summarize(instances)
return summaries
In [24]:
### COLOQUE SUA RESPOSTA AQUI
Agora estamos prontos para fazer previsões usando os resumos preparados a partir dos nossos dados de treinamento. As previsões envolvem o cálculo da probabilidade de uma dada instância de dados pertencer a cada classe e a seleção da classe com a maior probabilidade de previsão.
Podemos usar uma função gaussiana para estimar a probabilidade de um determinado valor de atributo, dada a média conhecida e o desvio padrão para o atributo estimado a partir dos dados de treinamento.
Dado que os resumos de atributos para cada atributo e valor de classe, o resultado é a probabilidade condicional de um determinado valor de atributo dado um valor de classe.
Veja as referências para os detalhes desta equação para a função de densidade de probabilidade gaussiana. Em resumo, estamos conectando nossos detalhes conhecidos ao Gauss (valor do atributo, média e desvio padrão) e recuperando a probabilidade de que nosso valor de atributo pertença à classe.
Na função calcularProbability (), calculamos o expoente primeiro, depois calculamos a divisão principal. Isso nos permite ajustar a equação bem em duas linhas.
In [25]:
def calculateProbability(x, mean, stdev):
exponent = math.exp(-(math.pow(x-mean,2)/(2*math.pow(stdev,2))))
return (1 / (math.sqrt(2*math.pi) * math.pow(stdev, 2))) * exponent
In [26]:
### COLOQUE SUA RESPOSTA AQUI
Neste momento, podemos calcular a probabilidade de um atributo pertencente a uma classe, podemos combinar as probabilidades de todos os valores dos atributos para uma instância de dados e apresentar uma probabilidade de toda a instância de dados pertencente à classe.
Combinamos as probabilidades juntas, multiplicando-as. Na função calculateClassProbabilities () abaixo, a probabilidade de uma determinada instância de dados é calculada multiplicando as probabilidades de atributo para cada classe. O resultado é um mapa de valores de classe para probabilidades.
In [27]:
def calculateClassProbabilities(summaries, inputVector):
probabilities = {}
for classValue, classSummaries in summaries.items():
probabilities[classValue] = 1
for i in range(len(classSummaries)):
mean, stdev = classSummaries[i]
x = inputVector[i]
probabilities[classValue] *= calculateProbability(x, mean, stdev)
return probabilities
In [28]:
### COLOQUE SUA RESPOSTA AQUI
In [29]:
def predict(summaries, inputVector):
probabilities = calculateClassProbabilities(summaries, inputVector)
bestLabel, bestProb = None, -1
for classValue, probability in probabilities.items():
if bestLabel is None or probability > bestProb:
bestProb = probability
bestLabel = classValue
return bestLabel
In [30]:
### COLOQUE SUA RESPOSTA AQUI
In [31]:
def getPredictions(summaries, testSet):
predictions = []
for i in range(len(testSet)):
result = predict(summaries, testSet[i])
predictions.append(result)
return predictions
In [32]:
### COLOQUE SUA RESPOSTA AQUI
In [33]:
def getAccuracy(testSet, predictions):
correct = 0
for i in range(len(testSet)):
if testSet[i][-1] == predictions[i]:
correct += 1
return (correct/float(len(testSet))) * 100.0
In [34]:
### COLOQUE SUA RESPOSTA AQUI
In [36]:
### COLOQUE SUA RESPOSTA AQUI
In [ ]: