Buscar

Apostila - Prática e Laboratório II

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você viu 3, do total de 98 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você viu 6, do total de 98 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você viu 9, do total de 98 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Prévia do material em texto

PRÁTICA E LABORATÓRIO II 1 
 
 
Prática e Laboratório II 
 
 
PRÁTICA E LABORATÓRIO II 2 
Prática e Laboratório II 
 
1. Orientação a Objetos 
 
1.1 Trabalhando com Classes 
 
O paradigma orientado a objetos considera o objeto como entidade fundamental de 
todo o processo de programação por reúso. Isto porque o objeto consegue responder 
a mensagens de acordo com suas características (atributos) e suas ações (métodos) 
que estão incorporados nele mesmo, caracterizando, portanto, um dos princípios 
básicos da POO, programação orientada a objetos, denominado “encapsulamento”. 
 
Outro princípio importante é a herança (este iremos destacar mais adiante), em que 
um objeto “filho” poderá ser criado baseado em um objeto “pai”, herdando todos os 
seus atributos e métodos, além de apresentar os seus próprios. 
 
Por fim, o outro princípio é denominado “polimorfismo”, que é caracterizado quando 
duas ou mais classes distintas têm métodos de mesmo nome, de forma que uma 
função possa utilizar um objeto de qualquer uma das classes polimórficas sem a 
necessidade de tratar de forma diferenciada cada classe do objeto. 
 
Neste contexto, surge outro termo importante no paradigma orientado a objetos: 
classes. 
 
Classes representam um conjunto de objetos com atributos e métodos semelhantes e 
que tenham um objetivo em comum. Por exemplo: na disciplina matemática existem 
45 alunos matriculados regularmente. A disciplina matemática seria a classe e os 45 
alunos matriculados nesta turma seriam os objetos dessa classe. 
 
Na linguagem de programação Phyton, uma classe é criada a partir da palavra 
reservada class. Observe a sintaxe: 
 
 
 
PRÁTICA E LABORATÓRIO II 3 
#Criando classe 
class Animal: 
 pass 
 
Neste exemplo, foi utilizada a palavra reservada pass, que expressa um bloco vazio, 
ou seja, sem função alguma. Note que a classe criada se inicia com letra maiúscula. 
Embora esteja vazia, a classe Animal seria criada: 
 
<class __main__.Animal at 0x00B04360> 
 
Mesmo vazia, a classe recém-criada já apresenta dois atributos: 
 
[‘__doc__’, ‘__module__’] 
 
Vejamos um exemplo prático: 
 
class Pessoa: 
 def __init__(self, nome, idade): 
 self.nome=nome 
 self.idade=idade 
 
 def obterNome(self): 
 return self.nome 
 
 def obterIdade(self): 
 return self.idade 
 
pessoa = Pessoa('Pedro', 49) 
print pessoa.obterNome( ) 
print pessoa.obterIdade( ) 
raw_input( ) 
 
 
PRÁTICA E LABORATÓRIO II 4 
No exemplo, criou-se a classe Pessoa, tendo sido definidos em sua inicialização os 
atributos Nome e Idade. Os métodos e/ou atributos da classe são obrigados a passar 
por parâmetro ou argumento a palavra self antes de mais nada. Isso é convencionado 
pelo próprio Phyton. 
 
Foram definidas duas funções, obterNome( ) e obterIdade( ), para, 
respectivamente, receberem um valor para o nome e para a idade. 
 
Vejamos o programa no exemplo abaixo que manipula classes e objetos em Phyton: 
 
class Gelatina: 
 def __init__(self, tam, cor, sabor): 
 self.tam=tam 
 self.cor=cor 
 self.sabor=sabor 
 
gel1 = Gelatina ("pequena", "vermelha", "morango") 
gel2 = Gelatina ("media", "amarela", "abacaxi") 
gel3 = Gelatina ("grande", "roxa", "uva") 
 
print gel1.tam, 
print gel1.cor, 
print gel1.sabor 
 
print gel2.tam, 
print gel2.cor, 
print gel2.sabor 
 
print gel3.tam, 
print gel3.cor, 
print gel3.sabor 
 
 
PRÁTICA E LABORATÓRIO II 5 
raw_input ( ) 
 
A saída produzida pelo programa é a seguinte: 
 
 
 
Vejamos outro exemplo prático de orientação a objetos, agora para permitir cadastro 
por meio de entrada de dados: 
 
class Produto: 
 def __init__(self, cod, nome, quant): 
 self.cod=cod 
 self.nome=nome 
 self.quant=quant 
 
codigo = raw_input('Entre com o Codigo: ') 
nome = raw_input('Nome do produto: ') 
quantidade = raw_input('Qual a quantidade? ') 
 
produt = Produto(codigo, nome, quantidade) 
 
print '\n' 
 
 
PRÁTICA E LABORATÓRIO II 6 
print 'Dados de Saida:\n' 
print 'Codigo: ' + produt.cod 
print 'Produto: ' + produt.nome 
print 'Quantidade: ' + produt.quant 
 
raw_input ( ) 
 
 
 
 
1.2 Herança 
 
As classes Phyton têm por propriedade herdar as características (atributos) e as ações 
(métodos) de outras classes. Assim, se uma classe “b” é criada a partir de uma classe 
“a”, dizemos que a classe “a” é a classe pai e a classe “b” é a classe filha, e, portanto, 
esta última herda os atributos e métodos da classe pai. 
 
Embora uma classe filha tenha por preceito herdar os atributos e métodos da classe 
pai, a classe filha também pode apresentar seus próprios atributos e métodos. 
 
 
 
PRÁTICA E LABORATÓRIO II 7 
 
 
Na figura anterior, pode-se observar que a classe Animal é a classe pai e as classes 
Cachorro, Papagaio e Mosca são classes filhas. Portanto, por exemplo, a classe filha 
Cachorro apresenta como atributos espécie e cor (herdadas da classe pai) e corPelo 
(próprio da classe). 
 
Tecnicamente falando, a classe pai é denominada Superclasse e a classe filha é 
denominada Subclasse. 
 
Dessa forma, podemos observar o seguinte exemplo: 
 
 
# definindo a classe Animal: 
class Animal: 
 def __init__(self): 
 # codigo para o init aqui 
 # metodos de Animal aqui 
 
#definindo a classe Mamifero, herdando de Animal 
class Mamifero(Animal): 
 def __init__(self): 
 
# definindo Felino 
 
 
PRÁTICA E LABORATÓRIO II 8 
class Felino(Mamifero): 
 
# definindo Gato 
class Gato(Felino): 
 
1.3 Importando módulos 
 
Um dos recursos importantes do Phyton é a importação de módulos aos programas. 
Os módulos são carregados través da instrução import, como já foi apresentado ao 
longo do aprendizado da linguagem de programação Phyton. 
 
import <módulo_1> [ as nome_1 ] [, <módulo_2> 
 [ as nome_2]] ... 
 
from <módulo> import [<ident_1>, <ident_2>, ...] 
 
Qualquer forma utilizada é considerada uma sintaxe válida para o Phyton. Ainda 
podemos utilizar este recurso da forma mais simplificada, por meio do símbolo “*”, 
que, na verdade, indica a importação de todos os métodos, funções etc., para estarem 
disponíveis no programa fonte que fez a importação. 
 
from <módulo> import * 
 
>>> import fibonacci 
>>> fibonacci.fib(1000) 
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 
 
>>> dir() 
['__builtins__', '__doc__', '__name__', 'fibonacci'] 
 
 Importando tudo para o raiz, temos: 
>>> from fibonacci import * 
 
 
PRÁTICA E LABORATÓRIO II 9 
>>> fib(1000) 
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 
 
>>> dir() 
['__builtins__', '__doc__', '__name__', 'fib', 'fib2'] 
 
Através da instrução dir( ), foi permitido visualizar todos os detalhes acerca do módulo 
utilizado (métodos, funções etc.). 
 
A maioria dos programas de computador desenvolvidos em Phyton faz a importação 
de módulos, os quais, em outras linguagens de programação, por exemplo, C, 
denominam-se bibliotecas. 
 
A seguir, iremos explorar um pouco mais o recurso de módulos, permitindo a 
visualização de alguns bem interessantes. 
 
1.4 Módulos sys e re 
 
O módulo sys possui várias funções, o que permite que haja uma interação com o 
próprio interpretador Phyton. Podemos visualizar inicialmente as funções ps1 e ps2, 
que têm por objetivo definir os prompts utilizados pelo interpretador Phyton (“>>>” 
e “...”). 
 
>>>import sys 
>>> sys.ps1 = '>' 
> sys.ps2 = '. ' 
> for i in range(10) 
. print i 
 
Neste exemplo, o prompt “>>>” foi substituído por “>” (sys.ps1) e o prompt “...” foi 
substituído por “.” (sys.ps2). Só para enfatizar, o padrão seria da seguinte forma: 
 
 
 
PRÁTICA E LABORATÓRIO II 10 
>>> for i in range(10) 
... print i 
 
No exemplo a seguir, iremos utilizar a função argv, que tem por objetivo armazenar 
os argumentos passados pela linha de comandos na lista de strings argv[], onde o 
primeiro elemento é o nome do programa chamado, seguido pelos outros argumentos 
que sejam necessários para o carregamento do programa. 
 
# Modulo args.py 
from sys import argv 
 print sys.argv 
 
Então, o primeiro argumento seria o nome do programa, neste caso, args.py, e os 
demais argumentos seriam eventuais valores que seriam utilizados, por exemplo, em 
um programa Phyton. 
 
$ python args.py 2 5 -3 
['args.py', '2', '5', '-3'] 
 
Outro recurso interessante é a função path, cujo objetivo é apresentar os caminhos 
utilizados pelo Phyton para buscar os módulos solicitados pela instrução import. 
Dessa forma, teremos: 
 
>>> sys.path 
['', '/usr/lib64/python25.zip', '/usr/lib64/python2.5', 
'/usr/lib64/python2.5/plat-linux2', '/usr/lib64/python2.5/libtk', 
'/usr/lib64/python2.5/lib-dynload', 
'/usr/lib64/python2.5/site-packages', 
'/usr/lib64/python2.5/site-packages/gtk-2.0'] 
 
 
 
PRÁTICA E LABORATÓRIO II 11 
Caso você queira ter acesso a informações do Phyton, como parâmetros de instalação, 
por exemplo, podemos visualizar plataforma, prefixo e versão do interpretador Phyton 
utilizada. Observe o código a seguir: 
 
>>> sys.platform, sys.prefix, sys.version 
('linux2', '/usr', '2.5.1 (r251:54863, Jan 4 2017, 19:00:19) \n[GCC 4.1.2]') 
 
Outro recurso interessante está na redefinição dos dispositivos padrões de entrada e 
saída do programa. Para tanto, existem as funções stdin, stdout e stderr. Vejamos 
o exemplo a seguir: 
 
>>> sys.stdout.write('Interpretador Phyton') 
Interpretador Phyton>>> 
 
A função exit pode ser utilizada para encerrar uma seção do programa Phyton 
diretamente. Observe a seguir: 
 
>>> sys.exit() 
$ _ 
 
Quanto ao módulo re (regular expression), ele tem por objetivo fornecer ferramentas 
para realizar a filtragem de strings através de expressões regulares. A primeira função 
interessante desse módulo é conhecida como findall, que permite encontrar a 
ocorrência de certa string, filtrando-a através de uma expressão regular. Vejamos o 
exemplo abaixo: 
 
>>> import re 
>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell 
fastest') 
['foot', 'fell', 'fastest'] 
 
 
 
PRÁTICA E LABORATÓRIO II 12 
Outra função interessante é conhecida como sub, cujo objetivo é substituir uma 
ocorrência de certa string por outra qualquer. Observe: 
 
>>> re.sub(r'\bAMD', r'AuthenticAMD', 'AMD Turion(tm) 64 X2 
Mobile') 
'AuthenticAMD Turion(tm) 64 X2 Mobile' 
 
A função sub permite substituir duas ocorrências de uma string, assumindo apenas 
uma delas. Veja: 
 
>>> re.sub(r'(\b[a-z]+) \1', r'\1', 'Hoje esta um dia dia ensolarado') 
'Hoje esta um dia ensolarado' 
 
1.5 Módulos math e random 
 
O módulo math, como já foi visto no estudo da linguagem de programação Phyton, 
permite que sejam acessadas diversas funções matemáticas e constantes numéricas 
para o programa que esteja sendo utilizado. Para visualizar as diversas funções 
matemáticas que existem associadas ao módulo math, utilizaremos a instrução dir( 
). 
 
>>> dir(math) 
['__doc__', '__file__', '__name__', 'acos', 'asin', 'atan', 
'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp', 'fabs', 
'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 
'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 
'tanh'] 
 
Vamos recordar, através do programa exemplo a seguir, uma aplicação que utiliza uma 
função matemática, neste caso, o seno de um número. 
 
 
 
 
PRÁTICA E LABORATÓRIO II 13 
import math 
def Sin(a): 
# Calcula seno de angulo em graus 
ang = a*math.pi/180. # mesmo que radians() 
return math.sin(ang) 
 
Dessa forma, ao utilizar a função seno passando como parâmetro um número para 
que este seno seja calculado, o mesmo será efetivado. 
 
>>> Sin(30) 
0.49999999999999994 
>>> Sin(60) 
0.8660254037844386 
 
Podemos também manipular o módulo random, cujo objetivo é permitir a geração de 
números aleatórios. A função choice( ) permite que seja escolhido de forma aleatória 
um elemento da lista. Observe o programa exemplo a seguir: 
 
>>> import random 
>>> random.choice(['goiaba', 'laranja', 'abacate', 'pera']) 
'pera' 
 
 Ao executar o mesmo programa outra vez, nada impede que a mesma saída aconteça. 
No entanto, outra saída diferente também será possível. Veja o exemplo: 
 
>>> import random 
>>> random.choice(['goiaba', 'laranja', 'abacate', 'pera']) 
'goiaba' 
 
Outra função interessante é a randrange( ), cujo objetivo é gerar um número inteiro 
aleatório, considerando certo intervalo, no nosso caso, 0 e n-1, onde n=10: 
 
 
PRÁTICA E LABORATÓRIO II 14 
 
>>> random.randrange(10) 
3 
 
1.6 Módulo para internet – urllib2 e smtplib 
 
A linguagem de programação Phyton oferece módulos especiais para manipulação de 
internet. O urllib2( ) permite criar modos de navegação na internet, carregar páginas 
web, realizar pesquisas etc. 
 
>>> import urllib2 
>>> for line in 
urllib2.urlopen(’http://tycho.usno.navy.mil/cgibin/ 
timer.pl’): 
... if ’EST’ in line: # look for Eastern Standard Time 
... print line 
<BR>Jan. 05, 09:43:38 PM EST 
 
Outra função interessante é o smtplib( ), que permite o envio de e-mails através de 
um servidor smtp. 
 
>>> import smtplib 
>>> server = smtplib.SMTP(’localhost’) 
>>> server.sendmail(’professor@boente.eti.br’, 
’alfredo.boente@estacio.br’, 
"""To: alfredo.boente@estacio.br 
From: professor@boente.eti.br 
Envio de e-mail. 
""") 
>>> server.quit() 
 
 
 
 
PRÁTICA E LABORATÓRIO II 15 
1.7 Módulo datetime 
 
O módulo datetime fornece classes para manipulação de datas e horas nos mais 
variados formatos possíveis. 
 
A função date (ano, mês, dia) cria um objeto do tipo data. Observe o código em 
Phyton a seguir: 
 
>>> from datetime import date 
>>> hoje = date.today() 
>>> nascimento = date(1968, 12, 25) 
>>> idade = hoje – nascimento 
>>> print ‘Sua idade e %d anos’ % int(idade.days/365) 
 
A resposta será: “Sua idade é 49 anos”. 
 
1.8 Módulos zlib e timeit 
 
O módulo zlib permite trabalhar com dados comprimidos, comprimindo e 
descomprimindo sempre que necessário. A função compress(string) serve para 
comprimir dados, e a função decompress(string) serve para descomprimir dados. Veja 
o exemplo: 
 
>>> from zlib import compress, decompress 
>>> s = “Em 23 de outubro de 1906, o brasileiro de Minas Gerais Alberto 
Santos Dumont voou cerca de 60 metros e a uma altura de dois a tres metros 
com seu 14 Bis, no Campo de Bagatelle em Paris.” 
>>>len(s) 
 
A resposta será 187 caracteres. Vamos comprimir a mensagem e reduzir de 187 para 
143 caracteres. Observe: 
 
 
 
PRÁTICA E LABORATÓRIO II 16 
>>> z = compress(s) 
>>> len(z) 
 
2. Árvores de Decisão e Redes Neurais 
 
2.1 Entendendo a Árvore de Decisão 
 
Uma árvore de decisão é uma estrutura em forma de árvore usada para representar 
um número de possíveis caminhos de decisão. Cada um desses caminhos leva a um 
resultado específico.Trata-se de um dos modelos mais práticos e mais usados em inferência indutiva, um 
dos métodos preferidos dos cientistas de dados. 
 
As árvores de decisão são treinadas de acordo com um conjunto de regras de 
aprendizagem, e posteriormente outros exemplos são classificados de acordo com 
elas. 
 
Vamos considerar o clássico exemplo da construção de uma árvore de decisão de jogar 
tênis, que utiliza como parâmetros de decisão dias passados nos quais treinos de tênis 
foram realizados. 
 
 
 
PRÁTICA E LABORATÓRIO II 17 
 
 
Através desse simples exemplo, é possível construir a seguinte árvore de decisão: 
 
 
 
A relação existente entre os elementos da árvore, nó e folhas, e entre os atributos, 
valores e classificações pode ser compreendida da seguinte forma: 
 
 
 
PRÁTICA E LABORATÓRIO II 18 
 
 
 Então, a classificação de um exemplo, de acordo com esta árvore, é feita da seguinte 
maneira: 
 
 
 
O atributo “aspecto” tem como valor “sol”, e o atributo “humidade” tem como valor 
“elevada”. O evento em si é classificado como “não”, ou seja, quando teve sol e 
humidade elevada, não teve treino de tênis. Note que neste exemplo os atributos 
 
 
PRÁTICA E LABORATÓRIO II 19 
“temperatura” e “vento” não foram considerados, pois não são relevantes, já que não 
houve treino de tênis. 
 
Também é possível o uso de conectivos lógicos, como representar conjunções e 
disjunções de atributos. Vamos então visualizar o exemplo de árvore de decisão no 
qual os atributos aspecto “sol” e vento “fraco” são considerados. 
 
 
 
Se alterarmos simplesmente o conectivo lógico de conjunção para disjunção, teremos 
então como resposta a seguinte árvore de decisão. 
 
 
 
 
PRÁTICA E LABORATÓRIO II 20 
 
Árvores de decisão, portanto, podem ser utilizadas para auxiliar no processo de 
tomada de decisão em qualquer situação que envolva o processo decisório. 
 
É importante saber que para construirmos uma árvore de decisão é necessário saber 
quais perguntas fazer e em que ordem. 
 
Em Phyton, basta definir uma função e colocar tudo o quer que seja parametrizado 
dentro dela. Veja o exemplo abaixo: 
 
def entropia(class_probabilidades): 
 ””” dada a lista de probabilidades de classes, compute a entopia ””” 
 return sum(-p*math.log(p, 2) 
 for p in class_probabilidades 
 
2.2 Particionamento de Árvore de Decisão 
 
Matematicamente, segundo Grus (2016), se um dado S é dividido em subconjuntos 
s1, s2... sn contendo porções de dados q1, q1... qn, então estamos computando a 
entropia da partição como uma soma ponderada. 
 
Observe o código Phyton abaixo, que cria a entropia, as probabilidades e as partições 
necessárias para o nosso programa: 
 
def entropy(class_probabilities): 
 """given a list of class probabilities, compute the entropy""" 
 return sum(-p * math.log(p, 2) for p in class_probabilities if p) 
 
def class_probabilities(labels): 
 total_count = len(labels) 
 return [count / total_count 
 for count in Counter(labels).values()] 
 
 
PRÁTICA E LABORATÓRIO II 21 
def data_entropy(labeled_data): 
 labels = [label for _, label in labeled_data] 
 probabilities = class_probabilities(labels) 
 return entropy(probabilities) 
 
def partition_entropy(subsets): 
 """find the entropy from this partition of data into subsets""" 
 total_count = sum(len(subset) for subset in subsets) 
 
 return sum( data_entropy(subset) * len(subset) / total_count 
 for subset in subsets ) 
 
2.3 Criando Árvores de Decisão 
 
Para a criação da árvore de decisão, é necessário ter uma boa base de dados para 
poder manipular. Segue um exemplo utilizado por Grus (2016): 
 
print ("ARVORE DE DECISAO PHYTON\n") 
 
if __name__ == "__main__": 
 
 inputs = [ 
 ({'level':'Senior','lang':'Java','tweets':'no','phd':'no'}, False), 
 ({'level':'Senior','lang':'Java','tweets':'no','phd':'yes'}, False), 
 ({'level':'Mid','lang':'Python','tweets':'no','phd':'no'}, True), 
 ({'level':'Junior','lang':'Python','tweets':'no','phd':'no'}, True), 
 ({'level':'Junior','lang':'R','tweets':'yes','phd':'no'}, True), 
 ({'level':'Junior','lang':'R','tweets':'yes','phd':'yes'}, False), 
 ({'level':'Mid','lang':'R','tweets':'yes','phd':'yes'}, True), 
 ({'level':'Senior','lang':'Python','tweets':'no','phd':'no'}, False), 
 ({'level':'Senior','lang':'R','tweets':'yes','phd':'no'}, True), 
 ({'level':'Junior','lang':'Python','tweets':'yes','phd':'no'}, True), 
 
 
PRÁTICA E LABORATÓRIO II 22 
 ({'level':'Senior','lang':'Python','tweets':'yes','phd':'yes'},True), 
 ({'level':'Mid','lang':'Python','tweets':'no','phd':'yes'}, True), 
 ({'level':'Mid','lang':'Java','tweets':'yes','phd':'no'}, True), 
 ({'level':'Junior','lang':'Python','tweets':'no','phd':'yes'},False) 
 ] 
 
A partir daí, precisamos encontrar a partição com entropia mínima para todos os 
conjuntos de dados: 
 
for key in ['level','lang','tweets','phd']: 
 print key, partition_entropy_by(inputs, key) 
 
A menor entropia vem da divisão baseada em level, então precisamos fazer uma 
subárvore para cada valor level possível. 
 
senior_inputs = [(input, label) 
 for input, label in inputs if input["level"] == "Senior"] 
 
 for key in ['lang', 'tweets', 'phd']: 
 print key, partition_entropy_by(senior_inputs, key) 
 
 
2.4 Trabalhando com Floresta Aleatória 
 
Considerando que árvores de decisão podem se ajustar quase que perfeitamente, seus 
dados em treinamento, não nos surpreende quando eles tentam se reajustar. 
 
Vejamos o código completo do programa que implementa uma solução de árvore de 
decisão: 
 
from __future__ import division 
from collections import Counter, defaultdict 
 
 
PRÁTICA E LABORATÓRIO II 23 
from functools import partial 
import math, random 
 
def entropy(class_probabilities): 
 """given a list of class probabilities, compute the entropy""" 
 return sum(-p * math.log(p, 2) for p in class_probabilities if p) 
 
def class_probabilities(labels): 
 total_count = len(labels) 
 return [count / total_count 
 for count in Counter(labels).values()] 
 
def data_entropy(labeled_data): 
 labels = [label for _, label in labeled_data] 
 probabilities = class_probabilities(labels) 
 return entropy(probabilities) 
 
def partition_entropy(subsets): 
 """find the entropy from this partition of data into subsets""" 
 total_count = sum(len(subset) for subset in subsets) 
 
 return sum( data_entropy(subset) * len(subset) / total_count 
 for subset in subsets ) 
 
def group_by(items, key_fn): 
 """returns a defaultdict(list), where each input item 
 is in the list whose key is key_fn(item)""" 
 groups = defaultdict(list) 
 for item in items: 
 key = key_fn(item) 
 groups[key].append(item) 
 
 
PRÁTICA E LABORATÓRIO II 24 
 return groups 
 
def partition_by(inputs, attribute): 
 """returns a dict of inputs partitioned by the attribute 
 each input is a pair (attribute_dict, label)""" 
 return group_by(inputs, lambda x: x[0][attribute]) 
 
def partition_entropy_by(inputs,attribute): 
 """computes the entropy corresponding to the given partition""" 
 partitions = partition_by(inputs, attribute) 
 returnpartition_entropy(partitions.values()) 
 
def classify(tree, input): 
 """classify the input using the given decision tree""" 
 
 # if this is a leaf node, return its value 
 if tree in [True, False]: 
 return tree 
 
 # otherwise find the correct subtree 
 attribute, subtree_dict = tree 
 
 subtree_key = input.get(attribute) # None if input is missing attribute 
 
 if subtree_key not in subtree_dict: # if no subtree for key, 
 subtree_key = None # we'll use the None subtree 
 
 subtree = subtree_dict[subtree_key] # choose the appropriate subtree 
 return classify(subtree, input) # and use it to classify the input 
 
def build_tree_id3(inputs, split_candidates=None): 
 
 
PRÁTICA E LABORATÓRIO II 25 
 
 # if this is our first pass, 
 # all keys of the first input are split candidates 
 if split_candidates is None: 
 split_candidates = inputs[0][0].keys() 
 
 # count Trues and Falses in the inputs 
 num_inputs = len(inputs) 
 num_trues = len([label for item, label in inputs if label]) 
 num_falses = num_inputs - num_trues 
 
 if num_trues == 0: # if only Falses are left 
 return False # return a "False" leaf 
 
 if num_falses == 0: # if only Trues are left 
 return True # return a "True" leaf 
 
 if not split_candidates: # if no split candidates left 
 return num_trues >= num_falses # return the majority leaf 
 
 # otherwise, split on the best attribute 
 best_attribute = min(split_candidates, 
 key=partial(partition_entropy_by, inputs)) 
 
 partitions = partition_by(inputs, best_attribute) 
 new_candidates = [a for a in split_candidates 
 if a != best_attribute] 
 
 # recursively build the subtrees 
 subtrees = { attribute : build_tree_id3(subset, new_candidates) 
 for attribute, subset in partitions.iteritems() } 
 
 
PRÁTICA E LABORATÓRIO II 26 
 
 subtrees[None] = num_trues > num_falses # default case 
 
 return (best_attribute, subtrees) 
 
def forest_classify(trees, input): 
 votes = [classify(tree, input) for tree in trees] 
 vote_counts = Counter(votes) 
 return vote_counts.most_common(1)[0][0] 
 
print ("ARVORE DE DECISAO PHYTON\n") 
 
if __name__ == "__main__": 
 
 inputs = [ 
 ({'level':'Senior','lang':'Java','tweets':'no','phd':'no'}, False), 
 ({'level':'Senior','lang':'Java','tweets':'no','phd':'yes'}, False), 
 ({'level':'Mid','lang':'Python','tweets':'no','phd':'no'}, True), 
 ({'level':'Junior','lang':'Python','tweets':'no','phd':'no'}, True), 
 ({'level':'Junior','lang':'R','tweets':'yes','phd':'no'}, True), 
 ({'level':'Junior','lang':'R','tweets':'yes','phd':'yes'}, False), 
 ({'level':'Mid','lang':'R','tweets':'yes','phd':'yes'}, True), 
 ({'level':'Senior','lang':'Python','tweets':'no','phd':'no'}, False), 
 ({'level':'Senior','lang':'R','tweets':'yes','phd':'no'}, True), 
 ({'level':'Junior','lang':'Python','tweets':'yes','phd':'no'}, True), 
 ({'level':'Senior','lang':'Python','tweets':'yes','phd':'yes'},True), 
 ({'level':'Mid','lang':'Python','tweets':'no','phd':'yes'}, True), 
 ({'level':'Mid','lang':'Java','tweets':'yes','phd':'no'}, True), 
 ({'level':'Junior','lang':'Python','tweets':'no','phd':'yes'},False) 
 ] 
 
 
 
PRÁTICA E LABORATÓRIO II 27 
 for key in ['level','lang','tweets','phd']: 
 print key, partition_entropy_by(inputs, key) 
 print 
 
 senior_inputs = [(input, label) 
 for input, label in inputs if input["level"] == "Senior"] 
 
 for key in ['lang', 'tweets', 'phd']: 
 print key, partition_entropy_by(senior_inputs, key) 
 print 
 
 print "building the tree" 
 tree = build_tree_id3(inputs) 
 print tree 
 
 print "Junior / Java / tweets / no phd", classify(tree, 
 { "level" : "Junior", 
 "lang" : "Java", 
 "tweets" : "yes", 
 "phd" : "no"} ) 
 
 print "Junior / Java / tweets / phd", classify(tree, 
 { "level" : "Junior", 
 "lang" : "Java", 
 "tweets" : "yes", 
 "phd" : "yes"} ) 
 
 print "Intern", classify(tree, { "level" : "Intern" } ) 
 print "Senior", classify(tree, { "level" : "Senior" } ) 
 
raw_input( ) 
 
 
PRÁTICA E LABORATÓRIO II 28 
Observe a saída do programa: 
 
 
 
Neste caso, através da técnica floresta aleatória, podemos construir várias árvores de 
decisão, deixando-as escolher como classificar as entradas possíveis. 
 
def florest_classify(trees, input): 
 votes = [classify(tree, input) for tree in trees] 
 vote_counts = Counter(votes) 
 return vote_counts.most_common(1)[0][0] 
 
 
2.5 Entendendo Redes Neurais 
 
Uma rede neural artificial é um modelo preditivo motivado pela forma como o cérebro 
humano funciona. (GRUS, 2016). 
 
 
 
PRÁTICA E LABORATÓRIO II 29 
 
 
Redes neurais artificiais consistem em neurônios artificiais que desenvolvem cálculos 
similares acerca de suas entradas. Esse tipo de estrutura é muito útil para os cientistas 
de dados, pois podem resolver uma grande variedade de problemas, como 
reconhecimento de caligrafia, detecção facial etc. 
 
 
2.6 Perceptrons 
 
A rede neural mais simples é tecnicamente denominada perceptron, que aproxima 
um único neurônio com n entradas binárias. Ela computa a soma ponderada de suas 
entradas e “starta” se essa soma for maior ou igual a zero. 
Vejamos o código fonte a seguir: 
 
#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
 
# aplicativo para verificar se o ser vivo eh quadrupede ou bipede 
# quadrupede = 1, bipede = -1 
# cao = [-1,-1,1,1] | resposta = 1 
# gato = [1,1,1,1] | resposta = 1 
# cavalo = [1,1,-1,1] | resposta = 1 
 
 
PRÁTICA E LABORATÓRIO II 30 
# homem = [-1,-1,-1,1] | resposta = -1 
 
# pesos (sinapses) 
w = [0,0,0,0] 
# entradas 
x = [[-1,-1,1,1], 
 [1,1,1,1], 
 [1,1,-1,1], 
 [-1,-1,-1,1]] 
# respostas esperadas 
t = [1,1,1,-1] 
# bias (ajuste fino) 
b = 0 
#saida 
y = 0 
# numero maximo de interacoes 
max_int = 10 
# taxa de aprendizado 
taxa_aprendizado = 1 
#soma 
soma = 0 
#theshold 
threshold = 1 
# nome do animal 
animal = "" 
# resposta = acerto ou falha 
resposta = "" 
 
# dicionario de dados 
d = {'-1,-1,1,1' : 'cao', 
 '1,1,1,1' : 'gato', 
 
 
PRÁTICA E LABORATÓRIO II 31 
 '1,1,-1,1' : 'cavalo', 
 '-1,-1,-1,1' : 'homem' } 
 
print("APRENDIZADO COM REDES NEURAIS ARTIFICIAIS - Perceptrons") 
print("Treinando") 
print(" ") 
 
# funcao para converter listas em strings 
def listToString(list): 
 s = str(list).strip('[]') 
 s = s.replace(' ', '') 
 return s 
 
# inicio do algoritmo 
for k in range(1,max_int): 
 acertos = 0 
 print("INTERACAO "+str(k)+"-------------------------") 
 for i in range(0,len(x)): 
 soma = 0 
 
 # pega o nome do animal no dicionário 
 if d.has_key(listToString(x[i])): 
 animal = d[listToString(x[i])] 
 else: 
 animal = "" 
 
 # para calcular a saida do perceptron, cada entradade x eh 
multiplicada 
 # pelo seu peso w correspondente 
 for j in range(0,len(x[i])): 
 soma += x[i][j] * w[j] 
 
 
PRÁTICA E LABORATÓRIO II 32 
 # a saida eh igual a adicao do bias com a soma anterior 
 y_in = b + soma 
 #print("y_in = ",str(y_in)) 
 
 # funcao de saida eh determinada pelo threshold 
 if y_in > threshold: 
 y = 1 
 elif y_in >= -threshold and y_in <= threshold: 
 y = 0 
 else: 
 y = -1 
 
 # atualiza os pesos caso a saida nao corresponda ao valor esperado 
 if y == t[i]: 
 acertos+=1 
 resposta = "acerto" 
 else: 
 for j in range (0,len(w)): 
 w[j] = w[j] + (taxa_aprendizado * t[i] * x[i][j]) 
 b = b + taxa_aprendizado * t[i] 
 resposta = "Falha - Peso atualizado" 
 
 #imprime a resposta 
 if y == 1: 
 print(animal+" = quadrupede = "+resposta) 
 elif y == 0: 
 print(animal+" = padrao nao identificado = "+resposta) 
 elif y == -1: 
 print(animal+" = bipede = "+resposta) 
 
 if acertos == len(x): 
 
 
PRÁTICA E LABORATÓRIO II 33 
 print("\nFuncionalidade aprendida com "+str(k)+" interacoes") 
 break; 
 print("") 
print("\nFinalizado com Sucesso") 
raw_input( ) 
 
A saída produzida pelo programa é a seguinte: 
 
 
 
 
2.7 Redes Neurais Feed-Forward 
 
Como a topologia do cérebro é demasiadamente complicada, segundo Grus (2016, p. 
215), é normal aproximá-la como uma rede neural feed-forward idealizada, que 
consiste de camadas discretas de neurônios, cada uma conectada à seguinte camada 
disponível. 
 
Assim como o perceptron, deve-se somar os produtos de suas entradas com seus 
respectivos pesos. Observe o código Phyton a seguir: 
 
#!/usr/bin/env python 
 
 
PRÁTICA E LABORATÓRIO II 34 
# -*- coding: utf-8 -*- 
 
# aplicativo para analise de portas OR 
# falso = 0, verdadeiro = 1 
 
# [0,0] | resposta = 0 
# [0,1] | resposta = 1 
# [1,0] | resposta = 1 
# [1,1] | resposta = 1 
 
# numero maximo de interacoes 
max_int = 20 
 
# threshold (limiar) 
threshold = 0 
 
# peso 0 
w_0 = -threshold 
 
# entrada 0 
x_0 = 1 
 
# entradas 
x = [[x_0,0,0], 
 [x_0,0,1], 
 [x_0,1,0], 
 [x_0,1,1]] 
 
# quantos itens tem o vetor x (4) 
tamanho_x = len(x) 
# quantos itens estão em cada posicao do vetor x 
 
 
PRÁTICA E LABORATÓRIO II 35 
qtde_itens_x = len(x[0]) 
 
# pesos (sinapses) 
w = [w_0,0,0] 
 
# quantos itens tem o vetor w (3) 
tamanho_w = len(w) 
 
# respostas desejadas 
d = [0,1,1,1] 
 
# taxa de aprendizado (n) 
taxa_aprendizado = 0.5 
 
#saida 
y = 0 
 
# resposta = acerto ou falha 
resposta = "" 
 
# soma 
u = 0 
 
#erro 
e = 0 
 
print("REDES NEURAIS ARTIFICIAIS - Feed-Forward\n") 
 
# inicio do algoritmo 
for k in range(1,max_int): 
 acertos = 0 
 
 
PRÁTICA E LABORATÓRIO II 36 
 e = 0 
 print("INTERACAO "+str(k)+"-------------------------") 
 for t in range(0,tamanho_x): 
 u = 0 
 
 # para calcular a saida do perceptron, cada entrada de x eh 
multiplicada 
 # pelo seu peso w correspondente 
 for j in range(0,qtde_itens_x): 
 u += x[t][j] * w[j] 
 
 # funcao de saida 
 if u > 0: 
 y = 1 
 else: 
 y = 0 
 
 # atualiza os pesos caso a saida nao corresponda ao valor esperado 
 if y == d[t]: 
 resposta = "acerto" 
 acertos += 1 
 e = 0 
 else: 
 resposta = "erro" 
 # calculando o erro 
 e = d[t] - y 
 # atualizando os pesos 
 for j in range (0,tamanho_w): 
 w[j] = w[j] + (taxa_aprendizado * e * x[t][j]) 
 
 print(resposta + " >>> u = "+str(u)+ ", y = "+ str(y)+ ", e = "+str(e)) 
 
 
PRÁTICA E LABORATÓRIO II 37 
 
 if acertos == tamanho_x: 
 print("\nFuncionalidade aprendida com "+str(k)+" interacoes") 
 print("\nPesos encontrados =============== ") 
 for j in range (0,tamanho_w): 
 print(w[j]) 
 break; 
 print("") 
 
print("Finalizado") 
 
raw_input( ) 
 
A saída produzida pelo programa é a seguinte: 
 
 
 
 
 
 
 
 
 
PRÁTICA E LABORATÓRIO II 38 
2.8 Backpropagation 
 
Uma das opções de redes neurais artificiais é trabalhar com o famoso algoritmo de 
backpropagation, cujas principais vantagens é trabalhar com multicamadas e 
resolver problemas “não linearmente separáveis” que alguns algoritmos não resolvem. 
 
 
 
Um problema “não linearmente separável”, conforme ilustra a figura anterior, é aquele 
em que não poderemos separar duas classes distintas no eixo cartesiano bidimensional 
apenas traçando uma reta. 
 
Segue um exemplo clássico do uso da rede neural backpropagation: 
 
print ("APRENDIZADO COM REDES NEURAIS ARTIFICIAIS - 
BACKPROPAGATION\n") 
 
import math 
import random 
import string 
 
class NN: 
 def __init__(self, NI, NH, NO): 
 
 
PRÁTICA E LABORATÓRIO II 39 
 # number of nodes in layers 
 self.ni = NI + 1 # +1 for bias 
 self.nh = NH 
 self.no = NO 
 
 # initialize node-activations 
 self.ai, self.ah, self.ao = [],[], [] 
 self.ai = [1.0]*self.ni 
 self.ah = [1.0]*self.nh 
 self.ao = [1.0]*self.no 
 
 # create node weight matrices 
 self.wi = makeMatrix (self.ni, self.nh) 
 self.wo = makeMatrix (self.nh, self.no) 
 # initialize node weights to random vals 
 randomizeMatrix ( self.wi, -0.2, 0.2 ) 
 randomizeMatrix ( self.wo, -2.0, 2.0 ) 
 # create last change in weights matrices for momentum 
 self.ci = makeMatrix (self.ni, self.nh) 
 self.co = makeMatrix (self.nh, self.no) 
 
 def runNN (self, inputs): 
 if len(inputs) != self.ni-1: 
 print 'incorrect number of inputs' 
 
 for i in range(self.ni-1): 
 self.ai[i] = inputs[i] 
 
 for j in range(self.nh): 
 sum = 0.0 
 for i in range(self.ni): 
 
 
PRÁTICA E LABORATÓRIO II 40 
 sum +=( self.ai[i] * self.wi[i][j] ) 
 self.ah[j] = sigmoid (sum) 
 
 for k in range(self.no): 
 sum = 0.0 
 for j in range(self.nh): 
 sum +=( self.ah[j] * self.wo[j][k] ) 
 self.ao[k] = sigmoid (sum) 
 
 return self.ao 
 
 
 def backPropagate (self, targets, N, M): 
 
 # calc output deltas 
 output_deltas = [0.0] * self.no 
 for k in range(self.no): 
 error = targets[k] - self.ao[k] 
 output_deltas[k] = error * dsigmoid(self.ao[k]) 
 
 # update output weights 
 for j in range(self.nh): 
 for k in range(self.no): 
 # output_deltas[k] * self.ah[j] is the full derivative of 
dError/dweight[j][k] 
 change = output_deltas[k] * self.ah[j] 
 self.wo[j][k] += N*change + M*self.co[j][k] 
 self.co[j][k] = change 
 
 # calc hidden deltas 
 hidden_deltas = [0.0] * self.nh 
 
 
PRÁTICA E LABORATÓRIO II 41 
 for j in range(self.nh): 
 error = 0.0 
 for k in range(self.no): 
 error += output_deltas[k]* self.wo[j][k] 
 hidden_deltas[j] = error * dsigmoid(self.ah[j]) 
 
 #update input weights 
 for i in range (self.ni): 
 for j in range (self.nh): 
 change = hidden_deltas[j] * self.ai[i] 
 #print 'activation',self.ai[i],'synapse',i,j,'change',change 
 self.wi[i][j] += N*change + M*self.ci[i][j] 
 self.ci[i][j] = change 
 
 # calc combined error 
 # 1/2 for differential convenience & **2 for modulus 
 error = 0.0 
 for k in range(len(targets)): 
 error = 0.5 * (targets[k]-self.ao[k])**2 
 return error 
 
 
 def weights(self): 
 print 'Input weights:' 
 for i in range(self.ni): 
 print self.wi[i] 
 print 
 print 'Output weights:' 
 for j in range(self.nh): 
 print self.wo[j] 
 print '' 
 
 
PRÁTICA E LABORATÓRIO II 42 
 
 def test(self, patterns): 
 for p in patterns: 
 inputs = p[0] 
 print 'Inputs:', p[0], '-->', self.runNN(inputs), '\tTarget', p[1] 
 
 def train (self, patterns, max_iterations = 1000, N=0.5, M=0.1): 
 for i in range(max_iterations): 
 for p in patterns: 
 inputs = p[0] 
 targets = p[1] 
 self.runNN(inputs) 
 error = self.backPropagate(targets, N, M) 
 if i % 50 == 0: 
 print 'Combined error', error 
 self.test(patterns) 
 
 
def sigmoid (x): 
 return math.tanh(x) 
 
# the derivative of the sigmoid function in terms of output 
# proof here: 
# http://www.math10.com/en/algebra/hyperbolic-functions/hyperbolic-
functions.html 
def dsigmoid (y): 
 return 1 - y**2 
 
def makeMatrix ( I, J, fill=0.0): 
 m = [] 
 for i in range(I): 
 
 
PRÁTICA E LABORATÓRIO II 43 
 m.append([fill]*J) 
 return m 
 
def randomizeMatrix ( matrix, a, b): 
 for i in range ( len (matrix) ): 
 for j in range ( len (matrix[0]) ): 
 matrix[i][j] = random.uniform(a,b) 
 
def main (): 
 pat = [ 
 [[0,0], [1]], 
 [[0,1], [1]], 
 [[1,0], [1]], 
 [[1,1], [0]] 
 ] 
 myNN = NN ( 2, 2, 1) 
 myNN.train(pat) 
 
if __name__ == "__main__": 
 main() 
 
raw_input( ) 
 
A saída produzida pelo programa será a seguinte: 
 
 
 
PRÁTICA E LABORATÓRIO II 44 
 
 
 
3. Processamento de Linguagem Natural 
 
3.1 Nuvens de Palavras 
 
Nuvens de palavras é uma atividade comum aos cientistas de dados, principalmente 
pelo simples fato de computar contagens. Segundo Grus (2016), eles não penam muito 
em nuvens de palavras, em grande parte porque a colocação das palavras não significa 
nada além de “este é um espaço onde eu consigo encaixar uma palavra”. 
 
Quando cientistas de dados têm que criar nuvens de palavras, em linhas gerais, devem 
pensar se querem fazer os eixos transmitirem alguma coisa com algum sentido lógico. 
Grus (2016, p. 239) cita um exemplo interessante quando supõe que para cada coleção 
de dados de jargões relacionados à ciência você tenha dois números entre 0 e 100 – 
o primeiro representando a frequência com que ele aparece em postagens de 
empregos, e o segundo a frequência com que aparece em currículos: 
 
data = [ ("big data", 100, 15), ("Hadoop", 95, 25), ("Python", 75, 50), 
 ("R", 50, 40), ("machine learning", 80, 20), ("statistics", 20, 60), 
 ("data science", 60, 70), ("analytics", 90, 3), 
 ("team player", 85, 85), ("dynamic", 2, 90), ("synergies", 70, 0), 
 
 
PRÁTICA E LABORATÓRIO II 45 
 ("actionable insights", 40, 30), ("think out of the box", 45, 10), 
 ("self-starter", 30, 50), ("customer focus", 65, 15), 
 ("thought leadership", 35, 35)] 
 
 A abordagem nuvens de palavras serve apenas para organizar as palavras na página 
usando certo tipo de fonte que, de certa forma, acaba chamando muito atenção. 
 
O interessante sobre nuvens de palavras é que elas têm uma abordagem de dispersão 
dessas palavras para que a posição horizontal possa indicar a popularidade de 
postagens, e a vertical, a popularidade de currículos, o que certamente, produziria 
uma visualização que transmitiria alguns insights. 
 
 
 
PRÁTICA E LABORATÓRIO II 46 
 
 
 def text_size(total): 
 """equals 8 if total is 0, 28 if total is 200""" 
 return 8 + total / 200 * 20 
 
 for word, job_popularity, resume_popularity in data: 
 plt.text(job_popularity, resume_popularity, word, 
 ha='center', va='center', 
 size=text_size(job_popularity + resume_popularity)) 
 plt.xlabel("Popularity on Job Postings") 
 plt.ylabel("Popularity on Resumes") 
 plt.axis([0, 100, 0, 100]) 
 plt.show() 
 
Dessa forma, teríamos uma nuvem de palavras com palavras mais significativas, 
embora aparentemente fosse menos atrativa. 
 
3.2 Modelo n-gramas 
 
Grus (2016) apresenta uma situação como exemplo para adentrar no estudo de 
modelos de n-gramas. Vamos a ela: 
“A vice-presidente de marketing de pesquisa quer que você crie milhares de páginas 
Web sobre Data Science para que seu site seja classificado no topo dos resultados de 
pesquisa para os termos relacionados”. Na verdade, ela não quer escrever milhares de 
 
 
PRÁTICA E LABORATÓRIO II 47 
páginas Web. Em vez disso, ela pergunta se você pode, de alguma forma, gerar estas 
páginas. 
 
Teremos que utilizar recursos de recuperação de dados, requests e BeautifulSoup. 
No entanto, existem alguns problemas nos quais devemos prestar muita atenção. 
 
O primeiro está relacionado aos apóstrofos no texto que, são representados pelo 
caractere Unicode u”\u2019”. Dessa forma, há necessidade de se criar uma função 
auxiliar para substituí-las por apóstrofos normais. 
 
# n-gram models 
def fix_unicode(text): 
 return text.replace(u"\u2019", "'") 
 
O segundo problema está relacionado com o texto da página Web, pois devemos 
dividi-lo em sequências de palavras e pontos para que possamos dizer onde se inicia 
e termina uma sentença. Podemos fazer isto usando a função findall( ) do módulo 
re: 
 
from bs4 import BeautifulSoup 
import request 
url = "http://radar.oreilly.com/2010/06/what-is-data-science.html" 
 html = requests.get(url).text 
 soup = BeautifulSoup(html, 'html5lib') 
 
 content = soup.find("div", "article-body") 
 # encontra conteúdo de entrada div 
 regex = r"[\w']+|[\.]" 
 # combina uma palavra ou um ponto 
 
 document = [] 
 
 
PRÁTICA E LABORATÓRIO II 48 
 for paragraph in content("p"): 
 words = re.findall(regex, fix_unicode(paragraph.text)) 
 document.extend(words) 
 
 return document 
 
Certamente, você, como cientista de dados, poderia e deveria limpar um pouco mais 
esses dados. Ainda existe uma grande quantidade de textos extrínsecos no 
documento. 
 
Agora que o texto disponível é uma sequência de palavras, podemos modelar uma 
linguagem da seguinte forma: dada alguma palavra inicial, procura-se a partir de todas 
as demais palavras, nos documentos-fonte, a próxima que nos interessa, de acordo 
com a nossa necessidade. A partir daí, deve-se escolher aleatoriamente uma dessas 
palavras para ser, portanto, a próxima palavra, e assim por diante, até que cheguemos 
ao ponto, que expressa o final da sentença. Tecnicamente, essa técnica é denominada 
modelo bigrama e pode ser determinada completamente por sequências de 
bigramas nos dados originais.Pode surgir a seguinte dúvida: por qual palavra começar? Deve-se começar a computar 
as possíveis transições de palavras. Observe o trecho de código a seguir: 
 
bigrams = zip(document, document[1:]) 
 transitions = defaultdict(list) 
 for prev, current in bigrams: 
 transitions[prev].append(current) 
 
A partir de então, tem-se acesso aos pares de elementos consecutivos do documento. 
Então, já estamos prontos para gerar sentenças: 
 
def generate_using_bigrams(transitions): 
 
 
PRÁTICA E LABORATÓRIO II 49 
 current = "." # a próxima palavra sera uma sentenca 
 result = [] 
 while True: 
 next_word_candidates = transitions[current] # bigramas 
 current = random.choice(next_word_candidates) 
 # escolhe um de forma aleatória 
 result.append(current) # anexa aos resultados 
 if current == ".": return " ".join(result) 
 # se "." então terminamos 
 
As sentenças que produz são “besteiras”, mas são o tipo de bobagem que você deveria 
colocar no seu web site, se está tentando fazer parecer com Data Science. 
 
3.3 Gramáticas 
 
Uma abordagem diferente para modelar linguagem é através do uso de gramáticas, 
regras para gerar sentenças aceitáveis. Seremos, portanto, obrigados a definir uma 
gramática independentemente da complexidade dada a ela: 
 
grammar = { 
 "_S" : ["_NP _VP"], 
 "_NP" : ["_N", 
 "_A _NP _P _A _N"], 
 "_VP" : ["_V", 
 "_V _NP"], 
 "_N" : ["data science", "Python", "regression"], 
 "_A" : ["big", "linear", "logistic"], 
 "_P" : ["about", "near"], 
 "_V" : ["learns", "trains", "tests", "is"] 
 } 
 
 
 
PRÁTICA E LABORATÓRIO II 50 
Depois de tudo, sentenças poderão ser geradas com base na gramática a partir de 
então. 
 
def generate_sentence(grammar): 
 return expand(grammar, [“_S”]) 
 
As gramáticas são mais interessantes quando usadas em outra direção. Assim, dada 
uma sentença, podemos usar uma gramática para analisá-la. Isso permite que 
possamos identificar sujeitos e verbos que nos auxiliarão a compreender a sentença. 
 
Utilizar ciência de dados para gerar textos é um truque esperto; usá-las para entender 
o texto é mais esperto ainda. 
 
3.4 Amostragem Gibbs 
 
Grus (2016) afirma que gerar abordagens de algumas distribuições é fácil. Devemos 
seguir variáveis aleatórias e uniformes. No entanto, algumas distribuições são mais 
difíceis de criar amostras. 
 
A amostragem de Gibbs nada mais é que uma técnica para gerar amostras de 
distribuição multidimensionais quando apenas conhecemos algumas das distribuições 
condicionais. Observe um trecho de código Phyton com tal abordagem: 
 
# Exemplo Amostragem Gibbs 
def roll_a_die(): 
 return random.choice([1,2,3,4,5,6]) 
 
def direct_sample(): 
 d1 = roll_a_die() 
 d2 = roll_a_die() 
 return d1, d1 + d2 
 
 
 
PRÁTICA E LABORATÓRIO II 51 
def random_y_given_x(x): 
 """equally likely to be x + 1, x + 2, ... , x + 6""" 
 return x + roll_a_die() 
 
def random_x_given_y(y): 
 if y &lt;= 7: 
 # se o total for 7 ou menos, o primeiro dado e igualmente 
 # 1, 2, ..., (total - 1) 
 return random.randrange(1, y) 
 else: 
 # se o total for 7 ou mais, o primeiro dado e igualmente 
 # (total - 6), (total - 5), ..., 6 
 return random.randrange(y - 6, 7) 
 
def gibbs_sample(num_iters=100): 
 x, y = 1, 2 # doesn't really matter 
 for _ in range(num_iters): 
 x = random_x_given_y(y) 
 y = random_y_given_x(x) 
 return x, y 
 
def compare_distributions(num_samples=1000): 
 counts = defaultdict(lambda: [0, 0]) 
 for _ in range(num_samples): 
 counts[gibbs_sample()][0] += 1 
 counts[direct_sample()][1] += 1 
 return counts 
 
A forma como a amostragem Gibbs funciona é que se começarmos com qualquer 
valor considerado válido para x e y, e então repetida e alternadamente substituímos x 
 
 
PRÁTICA E LABORATÓRIO II 52 
por um valor aleatório escolhido condicionado a y por um valor aleatório escolhido a 
x. 
 
3.5 Modelagem de tópicos 
 
Os tópicos precisam ser definidos pelo cientista de dados antes de mais nada. Será 
necessária então uma função para escolher aleatoriamente um índice baseado num 
conjunto arbitrário de pesos. 
 
# TOPIC MODELING 
def sample_from(weights): 
 total = sum(weights) 
 rnd = total * random.random() # uniform entre 0 e total 
 for i, w in enumerate(weights): 
 rnd -= w # retorna o menor i tal que 
 if rnd <= 0: return i # sum(weights[:(i+1)]) >= rnd 
 
Nossos documentos são os interesses de nossos usuários, que podem ser definidos, 
por exemplo, como: 
 
documents = [ 
 ["Hadoop", "Big Data", "HBase", "Java", "Spark", "Storm", "Cassandra"], 
 ["NoSQL", "MongoDB", "Cassandra", "HBase", "Postgres"], 
 ["Python", "scikit-learn", "scipy", "numpy", "statsmodels", "pandas"], 
 ["R", "Python", "statistics", "regression", "probability"], 
 ["machine learning", "regression", "decision trees", "libsvm"], 
 ["Python", "R", "Java", "C++", "Haskell", "programming languages"], 
 ["statistics", "probability", "mathematics", "theory"], 
 ["machine learning", "scikit-learn", "Mahout", "neural networks"], 
 ["neural networks", "deep learning", "Big Data", "artificial intelligence"], 
 ["Hadoop", "Java", "MapReduce", "Big Data"], 
 ["statistics", "R", "statsmodels"], 
 
 
PRÁTICA E LABORATÓRIO II 53 
 ["C++", "deep learning", "artificial intelligence", "probability"], 
 ["pandas", "R", "Python"], 
 ["databases", "HBase", "Postgres", "MySQL", "MongoDB"], 
 ["libsvm", "regression", "support vector machines"] 
] 
 
Depois do entendimento de todas essas engrenagens necessárias, segue o programa 
exemplo completo para processamento de linguagem natural: 
 
# Programa exemplo disponibilizado por Grus (2016) 
from __future__ import division 
import math, random, re 
from collections import defaultdict, Counter 
from bs4 import BeautifulSoup 
import requests 
def plot_resumes(plt): 
 data = [ ("big data", 100, 15), ("Hadoop", 95, 25), ("Python", 75, 50), 
 ("R", 50, 40), ("machine learning", 80, 20), ("statistics", 20, 60), 
 ("data science", 60, 70), ("analytics", 90, 3), 
 ("team player", 85, 85), ("dynamic", 2, 90), ("synergies", 70, 0), 
 ("actionable insights", 40, 30), ("think out of the box", 45, 10), 
 ("self-starter", 30, 50), ("customer focus", 65, 15), 
 ("thought leadership", 35, 35)] 
 
 def text_size(total): 
 """equals 8 if total is 0, 28 if total is 200""" 
 return 8 + total / 200 * 20 
 
 for word, job_popularity, resume_popularity in data: 
 plt.text(job_popularity, resume_popularity, word, 
 ha='center', va='center', 
 
 
PRÁTICA E LABORATÓRIO II 54 
 size=text_size(job_popularity + resume_popularity)) 
 plt.xlabel("Popularity on Job Postings") 
 plt.ylabel("Popularity on Resumes") 
 plt.axis([0, 100, 0, 100]) 
 plt.show() 
 
# 
# n-gram models 
# 
 
def fix_unicode(text): 
 return text.replace(u"\u2019", "'") 
 
def get_document(): 
 
 url = "http://radar.oreilly.com/2010/06/what-is-data-science.html" 
 html = requests.get(url).text 
 soup= BeautifulSoup(html, 'html5lib') 
 
 content = soup.find("div", "article-body") # find article-body div 
 regex = r"[\w']+|[\.]" # matches a word or a period 
 
 document = [] 
 
 
 for paragraph in content("p"): 
 words = re.findall(regex, fix_unicode(paragraph.text)) 
 document.extend(words) 
 
 return document 
 
 
 
PRÁTICA E LABORATÓRIO II 55 
def generate_using_bigrams(transitions): 
 current = "." # this means the next word will start a sentence 
 result = [] 
 while True: 
 next_word_candidates = transitions[current] # bigrams (current, _) 
 current = random.choice(next_word_candidates) # choose one at 
random 
 result.append(current) # append it to results 
 if current == ".": return " ".join(result) # if "." we're done 
 
def generate_using_trigrams(starts, trigram_transitions): 
 current = random.choice(starts) # choose a random starting word 
 prev = "." # and precede it with a '.' 
 result = [current] 
 while True: 
 next_word_candidates = trigram_transitions[(prev, current)] 
 next = random.choice(next_word_candidates) 
 
 prev, current = current, next 
 result.append(current) 
 
 if current == ".": 
 return " ".join(result) 
 
def is_terminal(token): 
 return token[0] != "_" 
 
def expand(grammar, tokens): 
 for i, token in enumerate(tokens): 
 
 # ignore terminals 
 
 
PRÁTICA E LABORATÓRIO II 56 
 if is_terminal(token): continue 
 
 # choose a replacement at random 
 replacement = random.choice(grammar[token]) 
 
 if is_terminal(replacement): 
 tokens[i] = replacement 
 else: 
 tokens = tokens[:i] + replacement.split() + tokens[(i+1):] 
 return expand(grammar, tokens) 
 
 # if we get here we had all terminals and are done 
 return tokens 
 
def generate_sentence(grammar): 
 return expand(grammar, ["_S"]) 
 
# 
# Gibbs Sampling 
# 
 
def roll_a_die(): 
 return random.choice([1,2,3,4,5,6]) 
 
def direct_sample(): 
 d1 = roll_a_die() 
 d2 = roll_a_die() 
 return d1, d1 + d2 
 
def random_y_given_x(x): 
 """equally likely to be x + 1, x + 2, ... , x + 6""" 
 
 
PRÁTICA E LABORATÓRIO II 57 
 return x + roll_a_die() 
 
def random_x_given_y(y): 
 if y <= 7: 
 # if the total is 7 or less, the first die is equally likely to be 
 # 1, 2, ..., (total - 1) 
 return random.randrange(1, y) 
 else: 
 # if the total is 7 or more, the first die is equally likely to be 
 # (total - 6), (total - 5), ..., 6 
 return random.randrange(y - 6, 7) 
 
def gibbs_sample(num_iters=100): 
 x, y = 1, 2 # doesn't really matter 
 for _ in range(num_iters): 
 x = random_x_given_y(y) 
 y = random_y_given_x(x) 
 return x, y 
 
def compare_distributions(num_samples=1000): 
 counts = defaultdict(lambda: [0, 0]) 
 for _ in range(num_samples): 
 counts[gibbs_sample()][0] += 1 
 counts[direct_sample()][1] += 1 
 return counts 
 
# 
# TOPIC MODELING 
# 
 
def sample_from(weights): 
 
 
PRÁTICA E LABORATÓRIO II 58 
 total = sum(weights) 
 rnd = total * random.random() # uniform between 0 and total 
 for i, w in enumerate(weights): 
 rnd -= w # return the smallest i such that 
 if rnd <= 0: return i # sum(weights[:(i+1)]) >= rnd 
 
documents = [ 
 ["Hadoop", "Big Data", "HBase", "Java", "Spark", "Storm", "Cassandra"], 
 ["NoSQL", "MongoDB", "Cassandra", "HBase", "Postgres"], 
 ["Python", "scikit-learn", "scipy", "numpy", "statsmodels", "pandas"], 
 ["R", "Python", "statistics", "regression", "probability"], 
 ["machine learning", "regression", "decision trees", "libsvm"], 
 ["Python", "R", "Java", "C++", "Haskell", "programming languages"], 
 ["statistics", "probability", "mathematics", "theory"], 
 ["machine learning", "scikit-learn", "Mahout", "neural networks"], 
 ["neural networks", "deep learning", "Big Data", "artificial intelligence"], 
 ["Hadoop", "Java", "MapReduce", "Big Data"], 
 ["statistics", "R", "statsmodels"], 
 ["C++", "deep learning", "artificial intelligence", "probability"], 
 ["pandas", "R", "Python"], 
 ["databases", "HBase", "Postgres", "MySQL", "MongoDB"], 
 ["libsvm", "regression", "support vector machines"] 
] 
 
K = 4 
 
document_topic_counts = [Counter() 
 for _ in documents] 
 
topic_word_counts = [Counter() for _ in range(K)] 
 
 
 
PRÁTICA E LABORATÓRIO II 59 
topic_counts = [0 for _ in range(K)] 
 
document_lengths = map(len, documents) 
 
distinct_words = set(word for document in documents for word in 
document) 
W = len(distinct_words) 
 
D = len(documents) 
 
def p_topic_given_document(topic, d, alpha=0.1): 
 """the fraction of words in document _d_ 
 that are assigned to _topic_ (plus some smoothing)""" 
 
 return ((document_topic_counts[d][topic] + alpha) / 
 (document_lengths[d] + K * alpha)) 
 
def p_word_given_topic(word, topic, beta=0.1): 
 """the fraction of words assigned to _topic_ 
 that equal _word_ (plus some smoothing)""" 
 
 return ((topic_word_counts[topic][word] + beta) / 
 (topic_counts[topic] + W * beta)) 
 
def topic_weight(d, word, k): 
 """given a document and a word in that document, 
 return the weight for the k-th topic""" 
 
 return p_word_given_topic(word, k) * p_topic_given_document(k, d) 
 
def choose_new_topic(d, word): 
 
 
PRÁTICA E LABORATÓRIO II 60 
 return sample_from([topic_weight(d, word, k) 
 for k in range(K)]) 
 
 
random.seed(0) 
document_topics = [[random.randrange(K) for word in document] 
 for document in documents] 
 
for d in range(D): 
 for word, topic in zip(documents[d], document_topics[d]): 
 document_topic_counts[d][topic] += 1 
 topic_word_counts[topic][word] += 1 
 topic_counts[topic] += 1 
 
for iter in range(1000): 
 for d in range(D): 
 for i, (word, topic) in enumerate(zip(documents[d], 
 document_topics[d])): 
 
 # remove this word / topic from the counts 
 # so that it doesn't influence the weights 
 document_topic_counts[d][topic] -= 1 
 topic_word_counts[topic][word] -= 1 
 topic_counts[topic] -= 1 
 document_lengths[d] -= 1 
 
 # choose a new topic based on the weights 
 new_topic = choose_new_topic(d, word) 
 document_topics[d][i] = new_topic 
 
 # and now add it back to the counts 
 
 
PRÁTICA E LABORATÓRIO II 61 
 document_topic_counts[d][new_topic] += 1 
 topic_word_counts[new_topic][word] += 1 
 topic_counts[new_topic] += 1 
 document_lengths[d] += 1 
 
if __name__ == "__main__": 
 
 document = get_document() 
 
 bigrams = zip(document, document[1:]) 
 transitions = defaultdict(list) 
 for prev, current in bigrams: 
 transitions[prev].append(current) 
 
 random.seed(0) 
 print "bigram sentences" 
 for i in range(10):print i, generate_using_bigrams(transitions) 
 print 
 
 # trigrams 
 
 trigrams = zip(document, document[1:], document[2:]) 
 trigram_transitions = defaultdict(list) 
 starts = [] 
 
 for prev, current, next in trigrams: 
 
 if prev == ".": # if the previous "word" was a period 
 starts.append(current) # then this is a start word 
 
 
 
PRÁTICA E LABORATÓRIO II 62 
 trigram_transitions[(prev, current)].append(next) 
 
 print "trigram sentences" 
 for i in range(10): 
 print i, generate_using_trigrams(starts, trigram_transitions) 
 print 
 
 grammar = { 
 "_S" : ["_NP _VP"], 
 "_NP" : ["_N", 
 "_A _NP _P _A _N"], 
 "_VP" : ["_V", 
 "_V _NP"], 
 "_N" : ["data science", "Python", "regression"], 
 "_A" : ["big", "linear", "logistic"], 
 "_P" : ["about", "near"], 
 "_V" : ["learns", "trains", "tests", "is"] 
 } 
 
 print "grammar sentences" 
 for i in range(10): 
 print i, " ".join(generate_sentence(grammar)) 
 print 
 
 print "gibbs sampling" 
 comparison = compare_distributions() 
 for roll, (gibbs, direct) in comparison.iteritems(): 
 print roll, gibbs, direct 
 
 
 # topic MODELING 
 
 
PRÁTICA E LABORATÓRIO II 63 
 
 for k, word_counts in enumerate(topic_word_counts): 
 for word, count in word_counts.most_common(): 
 if count > 0: print k, word, count 
 
 topic_names = ["Big Data and programming languages", 
 "Python and statistics", 
 "databases", 
 "machine learning"] 
 
 for document, topic_counts in zip(documents, document_topic_counts): 
 print document 
 for topic, count in topic_counts.most_common(): 
 if count > 0: 
 print topic_names[topic], count, 
 print 
 
3.6 Explorando Big Data e Clound Computing 
 
Depois de aprimorarmos todas essas técnicas, é hora de começarmos a utilizar a 
ciência de dados a partir da exploração de Big Data e de Cloud Computing. 
Uma técnica utilizada é o mapreduce, que nada mais é que um modelo de 
programação proposto pelo Google para facilitar o processamento de grandes volumes 
de dados a partir de Big Data. 
 
 
 
PRÁTICA E LABORATÓRIO II 64 
 
 
A partir de um paradigma inspirado em primitivas de programação funcional, foi criado 
um framework que permite a manipulação de grande volume de dados de forma 
paralela e distribuída, além de prover tolerância à falha, escalonamento de I/O e 
monitoramento. 
 
Um grande número de aplicações reais pode ser expresso nesse modelo de 
programação, que consiste na construção de um programa formado por duas 
operações básicas: map e reduce. 
 
A operação de map recebe um par chave/valor e gera um conjunto intermediário de 
dados também no formato chave/valor. 
 
A operação de reduce é executada para cada chave intermediária, com todos os 
conjuntos de valores intermediários associados àquela chave, combinados. 
Os dados podem estar disponíveis 24 horas por dia, 7 dias por semana e por todas as 
semanas no ano, através do recurso de Cloud Computing. 
 
 
map(String input_key, String input_value): 
 // input_key: document name 
 // input_value: document contents 
 for each word w in input_value: 
 
 
PRÁTICA E LABORATÓRIO II 65 
 EmitIntermediate(w, "1"); 
 
reduce(String output_key, Iterator intermediate_values): 
 // output_key: a word 
 // output_values: a list of counts 
 int result = 0; 
 for each v in intermediate_values: 
 result += ParseInt(v); 
 Emit(AsString(result)); 
 
Para cara palavra do documento de entrada, a função map emite o valor ‘1’ associado 
à chave que representa a palavra em questão. A função de reduce soma todas as 
contagens emitidas para uma mesma chave, ou seja, uma mesma palavra. 
 
Em geral a operação de map é usada para encontrar algo, e a operação de reduce é 
usada para fazer a sumarização do resultado. 
 
Segue um exemplo completo de operação com mapreduce a partir de Big Data: 
 
# Big Data com mapreduce 
from __future__ import division 
import math, random, re, datetime 
from collections import defaultdict, Counter 
from functools import partial 
from naive_bayes import tokenize 
 
def word_count_old(documents): 
 """word count not using MapReduce""" 
 return Counter(word 
 for document in documents 
 for word in tokenize(document)) 
 
 
PRÁTICA E LABORATÓRIO II 66 
 
def wc_mapper(document): 
 """for each word in the document, emit (word,1)""" 
 for word in tokenize(document): 
 yield (word, 1) 
 
def wc_reducer(word, counts): 
 """sum up the counts for a word""" 
 yield (word, sum(counts)) 
 
def word_count(documents): 
 """count the words in the input documents using MapReduce""" 
 
 # place to store grouped values 
 collector = defaultdict(list) 
 
 for document in documents: 
 for word, count in wc_mapper(document): 
 collector[word].append(count) 
 
 return [output 
 for word, counts in collector.iteritems() 
 for output in wc_reducer(word, counts)] 
 
def map_reduce(inputs, mapper, reducer): 
 """runs MapReduce on the inputs using mapper and reducer""" 
 collector = defaultdict(list) 
 
 for input in inputs: 
 for key, value in mapper(input): 
 collector[key].append(value) 
 
 
PRÁTICA E LABORATÓRIO II 67 
 return [output 
 for key, values in collector.iteritems() 
 for output in reducer(key,values)] 
 
def reduce_with(aggregation_fn, key, values): 
 """reduces a key-values pair by applying aggregation_fn to the values""" 
 yield (key, aggregation_fn(values)) 
 
def values_reducer(aggregation_fn): 
 """turns a function (values -> output) into a reducer""" 
 return partial(reduce_with, aggregation_fn) 
 
sum_reducer = values_reducer(sum) 
max_reducer = values_reducer(max) 
min_reducer = values_reducer(min) 
count_distinct_reducer = values_reducer(lambda values: len(set(values))) 
 
# 
# Analyzing Status Updates 
# 
 
status_updates = [ 
 {"id": 1, 
 "username" : "joelgrus", 
 "text" : "Is anyone interested in a data science book?", 
 "created_at" : datetime.datetime(2013, 12, 21, 11, 47, 0), 
 "liked_by" : ["data_guy", "data_gal", "bill"] }, 
 # add your own 
] 
 
def data_science_day_mapper(status_update): 
 
 
PRÁTICA E LABORATÓRIO II 68 
 """yields (day_of_week, 1) if status_update contains "data science" """ 
 if "data science" in status_update["text"].lower(): 
 day_of_week = status_update["created_at"].weekday() 
 yield (day_of_week, 1) 
 
data_science_days = map_reduce(status_updates, 
 data_science_day_mapper, 
 sum_reducer) 
 
def words_per_user_mapper(status_update): 
 user = status_update["username"] 
 for word in tokenize(status_update["text"]): 
 yield (user, (word, 1)) 
 
def most_popular_word_reducer(user, words_and_counts): 
 """given a sequence of (word, count) pairs, 
 return the word with the highest total count""" 
 
 word_counts = Counter() 
 for word, count in words_and_counts:word_counts[word] += count 
 
 word, count = word_counts.most_common(1)[0] 
 
 yield (user, (word, count)) 
 
user_words = map_reduce(status_updates, 
 words_per_user_mapper, 
 most_popular_word_reducer) 
 
def liker_mapper(status_update): 
 
 
PRÁTICA E LABORATÓRIO II 69 
 user = status_update["username"] 
 for liker in status_update["liked_by"]: 
 yield (user, liker) 
 
distinct_likers_per_user = map_reduce(status_updates, 
 liker_mapper, 
 count_distinct_reducer) 
 
 
# 
# matrix multiplication 
# 
 
def matrix_multiply_mapper(m, element): 
 """m is the common dimension (columns of A, rows of B) 
 element is a tuple (matrix_name, i, j, value)""" 
 matrix, i, j, value = element 
 
 if matrix == "A": 
 for column in range(m): 
 # A_ij is the jth entry in the sum for each C_i_column 
 yield((i, column), (j, value)) 
 else: 
 for row in range(m): 
 # B_ij is the ith entry in the sum for each C_row_j 
 yield((row, j), (i, value)) 
 
def matrix_multiply_reducer(m, key, indexed_values): 
 results_by_index = defaultdict(list) 
 for index, value in indexed_values: 
 results_by_index[index].append(value) 
 
 
PRÁTICA E LABORATÓRIO II 70 
 
 # sum up all the products of the positions with two results 
 sum_product = sum(results[0] * results[1] 
 for results in results_by_index.values() 
 if len(results) == 2) 
 
 if sum_product != 0.0: 
 yield (key, sum_product) 
 
if __name__ == "__main__": 
 
 documents = ["data science", "big data", "science fiction"] 
 
 wc_mapper_results = [result 
 for document in documents 
 for result in wc_mapper(document)] 
 
 print "wc_mapper results" 
 print wc_mapper_results 
 print 
 
 print "word count results" 
 print word_count(documents) 
 print 
 
 print "word count using map_reduce function" 
 print map_reduce(documents, wc_mapper, wc_reducer) 
 print 
 
 print "data science days" 
 print data_science_days 
 
 
PRÁTICA E LABORATÓRIO II 71 
 print 
 
 print "user words" 
 print user_words 
 print 
 
 print "distinct likers" 
 print distinct_likers_per_user 
 print 
 
 # matrix multiplication 
 
 entries = [("A", 0, 0, 3), ("A", 0, 1, 2), 
 ("B", 0, 0, 4), ("B", 0, 1, -1), ("B", 1, 0, 10)] 
 mapper = partial(matrix_multiply_mapper, 3) 
 reducer = partial(matrix_multiply_reducer, 3) 
 
 print "map-reduce matrix multiplication" 
 print "entries:", entries 
 print "result:", map_reduce(entries, mapper, reducer) 
 
 raw_input( ) 
 
 
 
 
 
 
 
 
PRÁTICA E LABORATÓRIO II 72 
 
 
A operação deverá ser realiza a partir de um a plataforma de software especial 
denominada Hadoop. 
 
Hadoop é, portanto, uma plataforma de software de computação distribuída voltada 
para clusters e processamento de grandes massas de dados (Big Data). 
 
Foi inspirada no mapreduce e no GoogleFS – GFS (sistema de arquivos escalável para 
aplicações de distribuição intensiva de dados). 
 
O framework do Apache Hadoop é composto dos módulos seguintes na versão 
2.2.x: 
 
Hadoop Common – Contém as bibliotecas e arquivos comuns e necessários para 
todos os módulos Hadoop. 
 
Hadoop Distributed File System (HDFS) – Sistema de arquivos distribuídos que 
armazena dados em máquinas dentro do cluster, sob demanda, permitindo uma 
largura de banda muito grande em todo o cluster. 
 
Hadoop Yarn – Trata-se de uma plataforma de gerenciamento de recursos 
responsável pelo gerenciamento dos recursos computacionais em cluster, bem como 
pelo agendamento dos recursos. 
 
Hadoop MapReduce – É um modelo de programação para processamento em larga 
escala (Big Data e Cloud Computing). 
 
 
PRÁTICA E LABORATÓRIO II 73 
Todos os módulos do Hadoop são desenhados com a premissa fundamental de que 
falhas em hardware são comuns, sejam elas máquinas individuais ou um conjunto 
inteiro de máquinas em racks, e devem, portanto, ser automaticamente tratadas por 
software pelo framework. 
 
hduser@ubuntu:/usr/local/hadoop$ bin/hadoop dfs -ls 
/user/hduser/gutenberg-output 
Found 1 items 
/user/hduser/gutenberg-output/part-00000 &lt;r 1&gt; 903193 2007-
09-21 13:00 
hduser@ubuntu:/usr/local/hadoop$ 
 
 
4. Análise de rede e sistemas de recomendação 
 
4.1 Analisando redes 
 
Muitos problemas de dados interessantes podem ser lucrativos em termos de redes 
consistentes de nós de algum tipo e vínculos que as juntam. 
 
A partir de diversas redes sociais, como Facebook, Instagram, Linkedin, Twitter etc., 
pode-se buscar esses possíveis vínculos a fim de se analisar dados a partir da rede 
mundial de computadores. 
 
No estudo da linguagem de programação Phyton, você aprendeu a computar os 
conectores de chave na rede DataSciencester contando o número de amigos que cada 
usuário tinha. 
 
 
 
PRÁTICA E LABORATÓRIO II 74 
 
 
Então, já temos maquinário suficiente para fazer outras abordagens em rede. 
Lembre-se de que a rede engloba diversos usuários: 
 
users = [ 
 { “id”: 0, “name”: “Hero” }, 
 { “id”: 1, “name”: “Dunn” }, 
 { “id”: 2, “name”: “Sue” }, 
 { “id”: 3, “name”: “Chi” }, 
 { “id”: 4, “name”: “Thor” }, 
 { “id”: 5, “name”: “Clive” }, 
 { “id”: 6, “name”: “Hicks” }, 
 { “id”: 7, “name”: “Devin” }, 
 { “id”: 8, “name”: “Keite” }, 
 { “id”: 9, “name”: “Klein” } 
 ] 
 
 E também amizades: 
 
friendships = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (3, 4), (4, 5), (5, 6), (5, 7), 
(6, 8), (7, 8), (8, 9)] 
 
 
 
PRÁTICA E LABORATÓRIO II 75 
 
 
A figura reporta, portanto, a rede social de cientistas de dados DataSciencester. Além 
disso, também adicionamos listas de amigos para cada dict de usuário: 
 
for user in users: 
 user[“friends”] = [ ] 
 
for i, j in friendships: 
 users[i][“friends”].append(users[j]) 
 #adiciona i como amigo de j 
 users[j][“friends”].append(users[i]) 
 #adiciona j como amigo de i 
 
Quando começamos nossos estudos na linguagem de programação Phyton, ainda 
estávamos insatisfeitos com a nossa noção de grau de centralidade, que não 
concordava com a nossa intuição sobre quem eram os conectores-chave da rede. 
 
Uma alternativa métrica é a centralidade de intermediação, conforme ilustra a próxima 
figura, que indica pessoas que frequentemente estão no menor caminho entre pares 
de outras pessoas. 
 
 
 
PRÁTICA E LABORATÓRIO II 76 
 
 
4.2 Centralidade de vetor próprio 
 
Grus (2016, p.260) afirma que para falar de centralidade de vetor próprio é necessário 
falar sobre vetores próprios, e para falar sobre vetores próprios temos que falar sobre 
multiplicidade de matrizes. 
 
Para entender a multiplicidade de matrizes, devemos analisar se A é uma matriz n1 x 
k1 e B é uma matriz n2 x k2, e se k1 = n2, então o produto AB deles é a matriz n1 x k2, 
cuja entrada (i, j) é: 
 
Ai1B1j + Ai2B2j + ...+ AikBkj 
 
Que na verdade

Outros materiais