Macros e a expressão Let no SAS

No post As boas práticas de programação foi mencionado que o código deveria ser o menos estático possível? No SAS isso pode ser feito muito bem com a criação de Macros e com a expressão %LET.

CONCEITO DE MACROS

De acordo com o Wikipedia “Uma macro (abreviação para macroinstrução), em ciência da computação, é uma regra ou padrão que especifica como uma certa sequência de entrada (frequentemente uma sequência de caracteres) deve ser mapeada para uma substituição de sequência de saída (também frequentemente uma sequência de caracteres) de acordo com um procedimento definido.”

Ou seja, uma macroinstrução é uma sequência de regras que o programa deve seguir. Quando você cria uma macro, você cria um programinha que vai executar uma série de procedimentos.

MACROS NO SAS

No SAS, assim como em outros programas, você pode deixar uma série de nomes flexíveis dentro da sua sequência de procedimentos, para que eles rodem diversas vezes soltando saídas diferentes.

Por exemplo, suponha que a gente tenha a base FATURA_YYYYMM gerada mensalmente com as faturas dos clientes no mês corrente. Você está realizando um estudo com clientes que possuem faturas de valor acima de R$ 200,00. Porém, para seu estudo, você vai pegar clientes dos primeiros três meses do ano. Se a pessoa não conhece muito sobre macros, é esperado que ela faça um código como esse:

data faturas_jan;
     set fatura_201601;
     if vlr_fatura > 200;
run;

data faturas_fev;
     set fatura_201602;
     if vlr_fatura > 200;
run;

data faturas_mar;
     set fatura_201603;
     if vlr_fatura > 200;
run;

Não parece a melhor maneira. Alguém mais calejado já estaria quebrando a cabeça imaginando que existe um jeito mais prático. Existe, é utilizando as macros do SAS.

No começo parece até algo mais complicado, mas é bem simples. A sintaxe é da seguinte forma:

%macro nome_da_macro(input 1, input2, ...);
     comando 1;
     comando 2;
     .
     .
     .
%mend;
%nomedamacro(input 1, input2, ...);

Sendo assim, podemos criar a macro EXTRAI_FATURA na qual vamos colocar como inputs os nomes das bases que serão lidas e como output as bases de saída:

%macro extrai_fatura(input, output);
data &input;
     set &output;
     if fatura > 200;
run;
%mend;

%extrai_fatura(fatura_201601, extracao_janeiro);
%extrai_fatura(fatura_201602, extracao_fevereiro);
%extrai_fatura(fatura_201603, extracao_marco);

Veja que a macro está lendo as bases que declaramos como input e está soltando os resultados em bases com o nome que passamos como output (extracao + nome do mês).

Note que precisamos colocar o caractere ‘&’ antes do nome das variáveis que serão substituídas. Note também, que a macro pode ficar ainda mais flexível com você passando o valor que quiser em cada extração:

%macro extrai_fatura(input, output, valor);
data &input;
     set &output;
     if fatura > &valor;
run;
%mend;

%extrai_fatura(fatura_201601, extracao_janeiro, 100);
%extrai_fatura(fatura_201602, extracao_fevereiro, 200);
%extrai_fatura(fatura_201603, extracao_marco, 300);

Nessa segunda macro, podemos colocar o valor que quisermos em cada extração. A primeira execução vai ler a fatura_201601 e retornar a extracao_janeiro apenas com clientes que possuem fatura acima de R$ 100,00. A segunda execução lê a fatura_201602 e retorna a extracao_fevereiro apenas com os clientes de fatura acima de R$ 200,00.

%LET NO SAS

A expressão %LET é mais fácil ainda que a macro, embora não ache ela tão poderosa.

Essa expressão também serve para alterar parâmetros no meio do seu código, porém, diferentemente da macro, você declara a variável uma vez no início do código. Uma das facilidades que eu vejo no LET é que permite você rodar o código por partes, o que facilita bastante para pegar erros. Facilita para processos executados periodicamente em que se altera algumas variáveis de inputs. Vamos supor que agora você não vai fazer um estudo, mas você quer fazer uma campanha com os clientes de alta renda e todo mês, assim que a base de faturamento for gerada, você vai pegar os clientes que possuem faturas acima de R$ 500,00. Você faria o seguinte código no mês de janeiro:

%let base_fatura = fatura_201601;
data extracao_campanha;
     set &base_fatura;
     if fatura > 500;
run;

Novamente, a gente declara uma variável e insere ela no código com o comando ‘&’ seguido do nome do input. No mês seguinte, você precisaria apenas trocar o valor atribuído ao %let e executar o mesmo código:

%let base_fatura = fatura_201602;
data extracao_campanha;
     set &base_fatura;
     if fatura > 500;
run;

Pense agora na quantidade de possibilidades. Deixar o valor da fatura, o nome da base de saída e outras variáveis flexíveis também. Pense agora se você tivesse 50 condições ao invés dessa única. Facilitaria bastante, não?

Dica rápida: Acrescentando zero na frente do número no SAS

Sabe aquele cpf que algum sem noção mandou em formato numérico e veio com menos de 11 dígitos na sua base?

Para deixá-lo com 11 dígitos e com zero na frente é simples, use o put() e o ‘z11.’ na sequência.

Por exemplo, você recebeu a tabela Clientes, na qual a coluna DOCUMENTO veio em formato numérico, ou seja, muitos não vão ter 11 dígitos, e você pode querer o CPF correto por diversos motivos. A conversão é simples, você utiliza um length apenas para garantir o comprimento da variável correto e manda bala no put:

data clientes_v2;
    set clientes;
    length cpf $11.;
    cpf = put(documento, z11.);
run;

Excluindo colunas no R

Uma dica rápida, mas que ajuda bastante.

Vamos supor que você tenha uma tabela com 7 colunas, e você queira excluir algumas colunas dela para sua análise. Como você faz?

Simples, utiliza o c() e coloca o sinal de negativo antes do número da coluna que você quer excluir. Como exemplo, temos a seguinte tabela com o preço médio dos combustíveis no Brasil, levantado pela ANP:

Veja que a primeira coluna é uma data e a última possui diversos NAs, o que atrapalha diversas operações.

Se você tentar utilizar a função log(), por exemplo, você vai ter um erro:

log(ANP_COMBUSTIVEIS[,c(-1,-7)])
PRECO_REV_ETANOL PRECO_REV_GASOLINA PRECO_REV_GLP PRECO_REV_GNV PRECO_REV_DIESEL
1 0.009257021 0.5196268 2.844613 -0.31471074 -0.18717331
2 0.014198719 0.5370780 2.873706 -0.29988962 -0.16251893
3 0.026154957 0.5411608 2.884778 -0.30042965 -0.15059036
4 0.038354954 0.5758828 2.930244 -0.26748737 -0.10725119
5 0.032079893 0.5767257 2.937520 -0.24910259 -0.09695153
6 0.028490270 0.5736314 2.928181 -0.24718013 -0.09673119
7 0.018821754 0.4621605 3.084173 -0.24654013 -0.12386399

Agora, se você utilizar c(-1,-7) na posição da coluna na matriz, você consegue seu resultado sem problema:

log(ANP_COMBUSTIVEIS[,c(-1,-7)])
 PRECO_REV_ETANOL PRECO_REV_GASOLINA PRECO_REV_GLP PRECO_REV_GNV PRECO_REV_DIESEL

1 0.009257021 0.5196268 2.844613 -0.31471074 -0.18717331
2 0.014198719 0.5370780 2.873706 -0.29988962 -0.16251893
3 0.026154957 0.5411608 2.884778 -0.30042965 -0.15059036
4 0.038354954 0.5758828 2.930244 -0.26748737 -0.10725119
5 0.032079893 0.5767257 2.937520 -0.24910259 -0.09695153
6 0.028490270 0.5736314 2.928181 -0.24718013 -0.09673119
7 0.018821754 0.4621605 3.084173 -0.24654013 -0.12386399

Veja o que acontece se você der um View(ANP_COMBUSTIVEIS[,c(-1,-7)]:

Se você quiser excluir da coluna 1 até a coluna 5, você pode simplesmente fazer ANP_COMBUSTIVEIS[,c(-1:-5)], afinal:

c(-1:-5)
[1] -1 -2 -3 -4 -5

Abbreviation Macro no SAS – Atalho de Códigos

Uma ferramenta bacana do SAS é o Abbreviation Macro, que serve para você salvar trechos de códigos que você utiliza constantemente. Isso economiza um bom tempo. Um exemplo clássico é para fazer os joins dos proc sql e os merge do data step, que todo mundo utiliza e às vezes dá aquele branco, ou aquela preguiça. Com o Abbreviation Macro você pode salvar um exemplo desses códigos e utilizar. É bem simples de utilizar:

1 – Vá em Program e selecione Add Abbreviation Macro:

2 – Digite um nome para o trecho que você quer chamar. No meu exemplo, é um código que eu utilizo para compactar bases no SAS e que eu nomeei COMPACTAR:

Pronto, vá no seu código, escreva COMPACTAR e veja a mágica acontecer (seu código vai aparecer lá!). Fácil assim.

O código de compactar está disponível em: Compactar e Descompactar Bases no SAS

Árvore de Decisão no R

Árvore de decisão é um modelo simples e extremamente útil para fazer predições. É fácil de explicar para as pessoas mais alheias ao mundo de ciência de dados e machine learning. Além disso, é simples de identificar o poder preditivo das variáveis, requer pouco pré-processamento, etc. Hoje, vou apresentar o código em R para uma árvore de decisão. Continuar a ler “Árvore de Decisão no R”

Árvore de Decisão

Uma das técnicas mais utilizadas para tomada de decisões é a árvore de decisões (em inglês decision trees). Sendo uma técnica capaz de lidar com a não linearidade, fácil de codificar, com poucas premissas e, talvez o mais importante, com resultado fácil de interpretar, a árvore de decisões é comumente adotada para concessões de crédito, diagnósticos médicos, análises de efeitos de drogas, análises de investimentos, etc.

A definição do wikipedia diz: “Uma árvore de decisão é uma representação de uma tabela de decisão sob a forma de uma árvore, porém podem haver outras aplicações. Tem a mesma utilidade da tabela de decisão. Trata-se de uma maneira alternativa de expressar as mesmas regras que são obtidas quando se constrói a tabela.”

Para ficar mais intuitivo, vamos pensar em um exemplo bem simples. O banco XYZ vai fornecer empréstimo a uma pessoa. Porém, sabemos que o banco XYZ não pode emprestar para qualquer um, não é todo mundo que vai pagar. Para decidir se vai ou não emprestar a uma pessoa, o banco XYZ monta um formulário com três perguntas:

  • Você possui empréstimo em outros bancos?
  • Você é casado?
  • Você possui casa própria?

Claro que o exemplo é um pouco banal, pois essa decisão depende de muitas variáveis, mas estamos querendo simplificar. Com base nas suas respostas, o banco deve decidir ou não dar um empréstimo. Ou seja, com base em um conjunto de respostas, o banco decide se você é um bom ou não pagador. Veja na árvore de decisões abaixo, que o banco XYZ, com base nas respostas dos clientes, sabe a probabilidade do cliente pagar ou não o empréstimo. E passa a fornecer crédito, para os clientes com probabilidade acima de 50%, que são os que ele considera bons pagadores:

Veja pelo diagrama, como é fácil identificar os clientes com os quais o banco irá fazer negócio. Isso nada mais é do que uma árvore de decisões.

Note que a árvore de decisões é uma ilustração de um algoritmo, um passo a passo que você realiza para tomar uma decisão, nesse caso a de emprestar ou não a um cliente.

E como você chega nessas probabilidades? Bom, lembre-se que já foi falado no blog como fazer modelos estatísticos nesse post. Para a árvore de decisões o raciocínio, normalmente, é o mesmo. Você possui alguns dados de clientes que já tomaram ou não empréstimos, suas características e se eles já pagaram ou não a sua dívida. Com base nisso, você saberá definir as melhores variáveis se baseando nas menor incerteza.

Por exemplo, suponha que o banco XYZ tenha 20 clientes que tomaram empréstimo no passado. Você está tentando decidir entre algumas variáveis para sua árvore de decisão. Para isso, você organiza o diagrama abaixo, sendo que bom é o cliente que pagou a dívida e ruim é o cliente que não pagou a dívida:

No diagrama, temos que dos 20 clientes da base do banco XYZ, dentre os que tomaram empréstimo em outros bancos, nenhum pagou a dívida. E dentre os que não tomaram, apenas um não pagou a dívida com o banco XYZ.

Com base na incerteza, podemos dizer que possuir empréstimo em outro banco é a melhor.

Veja que essa variável tem zero de incerteza, com base no histórico, todos os clientes que possuem empréstimo em outros bancos são maus pagadores.

E qual a pior variável?

Seguindo a mesma lógica, é a variável possui ou não casa própria. Veja que caso a pessoa não possua casa própria, a gente não consegue decidir se é mais provável que ela seja boa ou má pagadora. É equivalente a jogar uma moeda e decidir na sorte.

Leia também:

Árvore de Decisão no R
Árvore de Decisão com Probabilidade em R

Evitando “NA” nos cálculos do R

É sempre um problema trabalhar com NAs no R. Veja o código abaixo, onde foi criada uma matriz 2×2 contendo um elemento NA:

matriz_teste = array(data=c(10,NA,5,2), dim=c(2,2));
matriz_teste;

Para calcular a média das colunas, deveríamos utilizar a função colMeans() do R, mas veja que a sintaxe abaixo retorna um erro:

colMeans(matriz_teste);

O R não consegue calcular a média por causa desse NA. Porém, o R é muito inteligente, e para calcular a média quando tiver um NA no caminho, você não precisa de muito esforço, basta acrescentar o  argumento na.rm = TRUE:

colMeans(matriz_teste, na.rm = TRUE);

Veja que ele simplesmente ignora o elemento NA. É como se houvesse apenas um elemento na coluna. Se a coluna tivesse quatro elementos, sendo que dois eram NAs, a média seria calculada como a soma dos dois elementos não NAs dividida por dois.

E isso funciona também para a função que calcula a soma da coluna:

colSums(matriz_teste, na.rm = TRUE)

Simples, não?

Com relação a função chamada array(), leia o conteúdo do Wikipedia sobre arranjo.