Probabilidade Condicional e o Teorema de Bayes

Seguindo a linha de obtenção da probabilidade quando temos mais de um evento, muitas vezes vamos querer saber a probabilidade de algo acontecer, dada alguma condição. Por exemplo, em uma escola podemos querer calcular a probabilidade do aluno ter nota vermelha, dado que é menino. Essa probabilidade pode ser diferente da probabilidade de se ter nota vermelha, dado que é uma menina. Para melhor visualização, considere a tabela abaixo com os alunos aprovados e reprovados nas primeiras provas de cada disciplina (tabela gerada com o randbetween() do excel):

Se escolhermos aleatoriamente um aluno, qual a probabilidade dele estar aprovado em matemática dado que é um menino?

Temos um total de 13 meninos, sendo que 6 estão aprovados. Logo, a probabilidade é 6/13.

A mesma pergunta, aplicado ao caso de que tenha sido escolhida uma menina resultaria em 5/14.

Ou seja, precisamos fazer pequenos ajustes no que consideramos nosso espaço amostral.

Utilizando as notações adequadas, temos que dado dois eventos A e B, a probabilidade condicional de A dado B, denotada por P(A|B) é:

P(A|B) = P(A∩B) / P(B)

Ou seja, no nosso exemplo, queremos P(aprovado | menino) e a resposta será a interseção dos dois eventos dividido pela probabilidade de ser menino.

A probabilidade de ser homem e estar aprovado em matemática é 6/27, temos 6 meninos aprovados em matemática de um total de 27 alunos.

Como temos 13 meninos em uma sala de 27 alunos, a probabilidade de ser menino é 13/27.

Logo, P(aprovado|menino) = 6/27 ÷ 13/27 = 6/13.

Isso é o que chamamos de probabilidade condicional.

Um teorema muito importante quando se fala de probabilidade condicional é o Teorema de Bayes. O que este teorema nos fornece é uma forma de relacionar as probabilidades condicionais ao seu inverso. Por exemplo, se você precisa saber a probabilidade de um evento A ocorrer dado que ocorreu um evento B, e você sabe a probabilidade de um evento B ocorrer dado que o evento A ocorreu, o teorema vai te levar a resposta. A fórmula principal do teorema é:

P(A|B) = P(A) x P(B|A) /  P(B)

BÔNUS: Agora, e se quisermos saber a probabilidade de sair coroa em um lançamento de moeda, dado que no lançamento anterior saiu cara?

Essa é uma pergunta que confunde muitas pessoas. Nem todos responderiam 1/2, que é a resposta correta.

Pense comigo, se você está lançando uma moeda, independente do que já aconteceu no passado, a chance de cair coroa é 50%. O fato de ter saído cara, ou coroa, em um primeiro lançamento não alterou nada na moeda que faça com que ela agora tenha um peso diferente e provavelmente vai sair cara (ou coroa). Se você quiser saber a probabilidade de ocorrer coroa nos dois lançamentos consecutivos, isso sim altera nosso resultado final, pois estamos avaliando os dois eventos simultaneamente. Parece besta para quem entende, mas muita gente comete este erro.

 

Probabilidade: E vs. OU

Exemplo 1: Vamos supor que você tenha um dado de seis faces e uma moeda honesta. Você decide realizar apostas e quem acertar o resultado de ambos ganhará um prêmio. Seu amigo aposta que sairá o número seis E cara. Qual a probabilidade dele estar certo? E qual seria a probabilidade se você facilitasse o jogo um pouco para ele, e deixasse que ele levasse um prêmio se acertasse um dos dois apenas?

Para responder a pergunta, você trabalhará com dois tipos de eventos.

O primeiro é uma intersecção (https://pt.wikipedia.org/wiki/Interse%C3%A7%C3%A3o), ou seja, quando ocorrem dois eventos simultaneamente, no caso o lançamento do dado resultar no número seis e o da moeda em cara.

O segundo caso, em teoria dos conjuntos, é uma união. Ou seja, se qualquer um dos eventos ocorrer, já satisfaço a condição.

Considerando o espaço amostral do experimento, temos:

Ω = {(c, 1), (c, 2), (c, 3), (c, 4), (c, 5), (c, 6), (k, 1), (k, 2), (k, 3), (k, 4), (k, 5), (k, 6)}

No caso da interseção, apenas o resultado (cara, 6) satisfaz. Ou seja, a probabilidade é 1/12.

No caso da união, há um conjunto de resultados que satisfazem, para ser mais preciso, 7 resultados satisfazem a condição para que o jogador ganhe:

{(c,1), (c, 2), (c, 3), (c, 4), (c, 5), (c, 6), (k, 6)}

Ou seja, no segundo jogo as chances do seu amigo ganhar aumentam muito, para 7/12.

Uma outra forma de fazer isso seria utilizando a multiplicação para o primeiro caso e a soma para o segundo.

Interseção: P(cara e 6) = P(cara) * P(6) = 1/2 * 1/6 = 1/12

União: P(cara ou 6) = P(cara) + P(6) = 1/2 + 1/6 = 7/12

Exemplo 2: Um dado foi lançado 3 vezes. Qual a probabilidade de sair 3 caras? E de sair ao menos uma cara?

P(3 caras) = 1/2 * 1/2 * 1/2 = 1/8

P(ao menos uma cara) = 1 – P (3 coroas) = 1 – (1/2 * 1/2 * 1/2) =

Essa de pelo menos uma cara pode confundir alguns, por isso resolvi colocar. Alguns poderiam fazer 1/2 + 1/2 + 1/2 = 3/2 = 150%. Mas como é possível uma probabilidade de 150%? Lembre-se de que probabilidade é um valor entre 0 e 1, escrevendo de outra forma, entre 0 e 100%. Isso não é possível porque aqui, se tivermos cara no primeiro caso, a nossa condição já está satisfeita para as demais. Para resolver este exercício, apresento aqui o conceito de complementar.

Sendo A um evento, o evento complementar de A são todos os eventos do espaço amostral que não estão contidos em A. Ou seja, se o evento é ocorrer cara, o complementar é ocorrer coroa. Se o que buscamos é que ocorra pelo menos uma cara, se considerarmos todas as opções que temos de eventos, o complementar do evento ‘ao menos uma cara’ é quando só ocorre coroa nos três lançamentos.

Visualmente: Wikipedia – Complementar

 

Primeiros Passos em Probabilidade

O QUE É PROBABILIDADE?

Produzi muito mais material de programação do que de estatística, por motivos óbvios: mais da metade do tempo gasto no trabalho é tratando as bases de dados. Isso é normal para qualquer um que trabalhe com modelagem estatística ou qualquer outro trabalho que utilize um volume grande de dados.

Por causa disso, acabei deixando um tema muito importante de fora: probabilidade!

Probabilidade é uma medida que varia de zero a um e que indica a chance de um evento ocorrer. Sendo que zero indica que não há chances do evento ocorrer e um indica que o evento ocorrerá com certeza.

Para se medir a probabilidade de um evento específico ocorrer devemos medir o número de vezes que este evento pode ocorrer pelo número total de eventos que podem ocorrer.

Exemplo 1: Qual a probabilidade de sair cara em um lançamento de uma moeda honesta?

Temos o evento cara, ou seja, um evento. E temos um total de dois eventos, pois o lançamento pode resultar em cara ou coroa. Logo, a resposta é:

1/2 = 0,5

Exemplo 2: Qual a probabilidade de tirarmos um número par no lançamento de um dado honesto?

O número de vezes que o evento ocorrer são 3, pois tiraremos um número par quando obtivermos o número 2, 4 ou 6 no lançamento.

O total de eventos que pode ocorrer é 6, pois podemos tirar 1, 2, 3, 4, 5 ou 6 no lançamento.

Sendo assim, a resposta é 3/6 = 1/2 = 0,5.

ESPAÇO AMOSTRAL

Note que você foi introduzido – sem notar – a um conceito novo que é amplamente utilizados na estatística: o espaço amostral.

Espaço amostral é o conjunto de todos eventos que podem ocorrer em um experimento. Por exemplo, o espaço amostral no lançamento de uma moeda é um conjunto de 2 elementos: cara e coroa. No caso do lançamento de um dado, o espaço amostral possui 6 elementos, os números 1, 2, 3, 4, 5 e 6.

O espaço amostral é usualmente denotado pela letra grega omega: Ω. Porém, em alguns casos você pode encontrar a letra U também, derivada do conceito de Universo.

Dado um espaço amostral Ω = {ω1, ω2, … , ωn}, onde ωi se refere ao evento i do experimento, P(ω) é a probabilidade do evento ω ocorrer.

Exemplo 3: Temos uma caixa com 3 bolas vermelhas, 5 bolas amarelas e 7 bolas verdes dentro. Qual o espaço amostral do experimento? Qual a probabilidade de eu tirar uma bola vermelha? E uma amarela? E uma verde? Qual cor tem mais chance de sair em uma retirada?

Ω = {vermelha, vermelha, vermelha, amarela, amarela, amarela, amarela, amarela, verde, verde, verde, verde, verde, verde, verde}

P(vermelho) = 3 / (3+5+7) = 3/15 = 1/5

P(amarela) = 5 / (3+5+7) = 5/15 = 1/3

P(verde) = 3 / (3+5+7) = 7/15

Note que a probabilidade de sair verde é maior que as demais. O que é bem intuitivo, afinal temos mais bolas verdes na caixa.

Simples não?

Lembre-se sempre da fórmula abaixo:

P(A) = N° de vezes que A ocorre / N° Total de Eventos que ocorrem

Como obter a frequência de uma variável no SAS

Mencionei o comando proc freq do SAS no post Frequência no R utilizando o pacote Hmisc. Agora, vamos nos aprofundar um pouco e ver o que é possível fazer com este comando.

O proc freq traz a frequência das variáveis que você quer analisar ou fazer qualquer tipo de análise descritiva, ou seja, traz o número de vezes que determinado valor da variável aparece. A sintaxe mais simples do comando é:
proc freq data= base_de_dados; 
    table variavel1 variavel2 ... variaveln; 
run;
Vamos utilizar os dados de crédito german_credit_2 como exemplo.
Assim como já fizemos no R, no post Árvore de Decisão no R, vamos discretizar as variáveis Creditability e CreditAmount, para só depois gerarmos as frequências.
No caso de Creditability, a discretização serve para visualizar melhor quem é bom e quem é mau pagador. No caso de CreditAmount, não conseguimos gerar uma frequência que seja útil, pois a variável é contínua. Pior ainda, se a base for muito grande, o comando muito provavelmente não irá funcionar. Afinal de contas, você estará trazendo o número de vezes que cada valor aparece. Separar em intervalos é o ideal nesse caso.
Note que no meu caso, a base foi importada para o SAS com o nome german_credit_21.
**** discretiza variaveis creditability e amount ****;
data german_credit_21_v2;
    set german_credit_21;

    length d_creditability $4.;
    if creditability = 1 then
    d_creditability = 'good';
    else d_creditability = 'bad';

    length d_creditAmount $9.;
    if creditAmount <= 2500 then
    d_creditAmount = '0000-2500';
    else if creditAmount > 2500 and creditAmount <= 5000 then
    d_creditAmount = '2500-5000';
    else d_creditAmount = '+5000';

run;

**** Frequencia de Creditability e Amount ****;
proc freq data= german_credit_21_v2;
    table d_creditability d_creditAmount;
run;
Na primeira tabela é possível ver a frequência e qual o percentual que representa do todo. Temos 300 clientes maus, sendo que isso representa 30% da nossa população. Além disso, temos também a frequência acumulada. Temos, na segunda tabela, 537 clientes que possuem dívida entre 0 e 2500, e 812 clientes que possuem entre 0 e 5000, sendo que esses clientes representam 81,20% da nossa população.
É possível também obter a frequência cruzada, ou seja, quantos clientes bons e ruins há em cada faixa de dívida:
**** Frequencia Cruzada de Creditability e Amount ****;
proc freq data= german_credit_21_v2 ;
    table d_creditability*d_creditAmount;
run;
E se você quiser deixar a tabela um pouco menos poluída, mantendo apenas a frequência, utilize o norow, nocol e/ou nopercent:
**** Nao traz frequencia por linha, coluna nem percentual ****;
proc freq data= german_credit_21_v2;
    table d_creditability*d_creditAmount / norow nocol nopercent;
run;
Também é possível salvar a tabela de frequência utilizando o out:
**** Cria uma tabela de output chamada tabela_frequencia ****;
proc freq data= german_credit_21_v2;
    table d_creditability*d_creditAmount / out= tabela_frequencia norow nocol nopercent;
run;
E se você quiser ordenar a tabela de frequência, basta acrescentar o order = Freq:
**** Sem ordenar ****;
proc freq data= german_credit_21_v2 ;
    table Guarantors;
run;

**** Ordena pela frequencia ****;
proc freq data= german_credit_21_v2 order= freq;
    table Guarantors;
run;
Assim como fizemos para o Creditability, nós poderíamos ter atribuído nomes ao invés de índices ao Guarantors. Porém, para não alterarmos nossa base original, poderíamos simplesmente aplicar uma formatação:
**** formata o nome ****;
proc format;
   value formatacao
        1 = 'none'
        2 = 'co-applicant'
3 = 'guarantor';
run;

**** gera frequencia e apresenta com nome formatado ****;
proc freq data = german_credit_21;
   tables Guarantors;
   format Guarantors formatacao.; 
run;

Trabalhando com espaços e acentos no SAS

A pior coisa é utilizar campos com espaços em branco e acentos quando se está programando. Não é recomendável e muitas vezes resulta em erros. Porém, às vezes temos que lidar com isso porque alguém construiu uma base com campos dessa forma e não quer mudar.

No SAS é mais fácil lidar com isso, basta acrescentar aspas e a letra n. É bem semelhante quando você utiliza data, só que precisa trocar o ‘d’ por ‘n’.

Vamos supor que você receba os dados da turma de alunos do post Visualizando seus dados: histograma e queira criar uma marcação chamada Reprovação que receberá o número 1 para alunos que tiraram notas menor que 6, basta você criar o campo ‘Reprovação’n:

data dados_v2;
    set dados;
    if notas < 6 then 'Reprovação'n = 1;
    else 'Reprovação'n = 0;
run;

Poderíamos também cair em uma situação que seria necessário criar um campo Data de Atualização com a data do dia de hoje. Para isso, temos duas opções:

## primeira opcao:
data dados_v2;
    set dados;
    'Data de Atualização'n = today();
run;

## segunda opcao:
data dados_v2;
    set dados;
    'Data de Atualização'n = '13JUL2016'd;
run;

Contador e função oposta ao lag no SAS

Veja que exercício de lógica interessante:

Pense em uma base com clientes que possuem vários carros. Você tem linhas contendo o nome do cliente, o nome do carro que ele possui e a data de compra do veículo. Você precisa descobrir quais clientes possuem apenas um carro. A que eu vou demonstrar talvez não seja a mais eficiente, até porque eu precisei de alguns dados ao longo do estudo, como por exemplo qual a ordem em que o veículo foi comprado. Sem isso, não sei se eu teria pensado de outra forma. O legal da forma que foi feito o tratamento é que trabalha o raciocínio lógico e ainda apresenta alguns algoritmos úteis.

O passo a passo utilizado é o seguinte: ordene seus dados pelo nome e data de compra do veículo; crie um contador para representar se é o primeiro carro que aparece do cliente; crie uma coluna adicional para saber qual o contador da linha seguinte. Veja que se você tiver na linha 10 o valor 1 no contador, e na linha 11 você tiver o valor 2, é sinal de que o cliente possui pelo menos dois veículos. No entanto, se você tiver o valor 1 no contador da linha 10 e o valor 1 no contador da linha 11, o seu cliente da linha 10 possui apenas 1 carro.

Foi falado um pouco sobra a função lag() do SAS no post Média Móvel (Bônus: Código SAS e função lag). Ela simplesmente pega o valor da linha de cima da coluna que você quer. Por exemplo, se eu fizer lag(conta_carro), eu vou saber qual o valor da coluna conta_carro da linha anterior a que estou verificando. No caso apresentado nesse post, precisamos de uma função que faça o contrário da lag, ao invés de retornar o valor da linha anterior, deve retornar o valor da linha seguinte. Você verá que não existe uma função pronta para esse caso, mas o script é bem simples e se encontra na Parte 5 do código abaixo.

Veja o exemplo completo que você pode simular e acompanhar o passo a passo explicado acima:
**** Parte 1: Cria uma base de clientes ****;
data base_clientes;
    input nome $ carro $ DtCompra mmddyy8.;
    cards;
    Andre Onix 02/05/15
    Andre Palio 12/10/13
    Andre Uno 01/05/14
    Paulo Idea 10/06/15
    Jose Vectra 01/04/16
    Jose Eco 12/05/16 28
    Maria Corsa 10/25/14
    Maria Celta 02/01/16
    Renata Onix 02/09/12
    Renata Palio 06/05/11
    Renata Fit 02/11/16
    Renata Civic 05/22/14
    Michael Fit 07/13/15
    Bianca Clio 09/05/15
    Thais March 08/05/16
    Renan Palio 11/05/13
    Renan Gol 11/05/14
    ;
run;

**** Parte 2: Trata a variavel data ****;
data base_clientes_v2;
    set base_clientes;
    format DtCompra date9.;
run;

**** Parte 3: Ordena pelo nome do cliente e data da compra do veiculo ****;
proc sort data= base_clientes_v2; by nome DtCompra; run;

**** Parte 4: Cria um contador do numero de carros = conta qtas vezes o nome aparece****;
data base_clientes_v3;
    set base_clientes_v2;
    by nome;
    primeiro = first.nome;
    ultimo = last.nome;
    if primeiro = 1 then
    conta_carro = 1;
    else conta_carro+1;
run;

**** Parte 5: Cria uma coluna com o valor da linha seguinte da coluna conta_carro ****;
data base_clientes_v4;
    recno=_n_+1;
    set base_clientes_v3 end=last;
    if not last
    then set base_clientes_v3 (keep=conta_carro rename=(conta_carro=next_conta_carro)) point=recno;
    else call missing(next_conta_carro);
run;

**** Parte 6: Mantem apenas quem tem conta_carro = 1 e que a proxima linha eh 1 tb ****;
data clientes_com_um_carro;
    set base_clientes_v4;
    if conta_carro = 1 and next_conta_carro = 1;
run;

Seja mais ágil utilizando firstobs e inobs no SAS

Quando se trabalha com milhões de dados, qualquer tratamento vai consumir alguns bons minutos – ou até horas – do seu dia. Ou seja, se você escrever seu código, rodar e ele apresentar algum erro, lá se vai uma parte do seu dia. Como ninguém é perfeito, esse processo de escrever + executar + problemas se repete várias vezes ao longo do dia. Logo, você vai gastar horas para escrever um código, muitas vezes simples, e vai passar horas ocioso. Porque você vai escrever um trecho do código, vai colocar para rodar, vai esperar alguns minutos e aí sim vai resolver um problema. Para depois fazer isso de novo. E aí segue seu dia, chato e improdutivo.

Evitar o problema descrito é mais simples do que parece. Ao menos parte dele é solucionado testando em uma amostra. Por exemplo, você quer converter o formato de data da sua base. Não escreva o código e fique lá 20 minutos rodando enquanto você não faz nada, ou finge fazer. Teste essa conversão em 10 linhas da base de dados e veja o que ocorre. Se o processo for grande, envolver várias etapas, siga testando com essas 10 linhas fazendo todos os tratamentos, seja enriquecendo a base com dados de outras fontes, seja tratando os campos. Para pegar apenas 10 linhas, você tem as duas opções abaixo, uma para quem usa data step e outra para quem usa proc sql:

* primeira opcao via data step
* seleciona do primeiro ao decimo elemento
* util caso voce queira selecionar elementos do meio da tabela;
data seleciona_amostra;
    set base (firstobs = 1 obs = 10);
run;

* segunda opcao via proc sql;
proc sql inobs = 10;
    select * from base;
run;

Bem simples. Desta forma não precisa mais escrever um trecho, deixar rodando por 1h para só depois checar se deu certo.

Espero que tenha ajudado. Dúvidas, sugestões ou críticas é só escrever aí embaixo.