Contexto

Abordaremos tratamento de dados por meio do PROC SQL do SAS e o pacote dplyr do R.

O pacote dplyr do R foi escrito por Hadley Wickham, popular programador R que escreveu muitos pacotes úteis para o R, como ggplot2, tidyr etc.

Comparação em linhas gerais

O SAS não possui linha de comando. O código/script deve ser executado para retornar resultados.

R é uma linguagem de programação orientada a objetos. Os resultados de uma função são armazenados em um objeto e os resultados são extraídos do objeto, conforme necessário.

O SAS gira em torno da tabela de dados e usa procedimentos para criar e imprimir saída. Os resultados podem ser salvos em uma nova tabela de dados.

SAS R
Compilador de script Intérprete de linha de comando
Principalmente orientado pela tabela de dados e procedimentos Orientado a objeto
Não é case sensitive Case sensitive

Operadores matemáticos

Definição SAS R
Exponenciação ** ^
Multiplicação * *
Divisão / /
Adição + +
Subtração - -

Operadores lógicos

Definição SAS (Mnemônico) SAS (Símbolo) R Prioridade lógica
Igual EQ = ==
Não é igual NL ^= ¬= ~= !=
Maior GT > >
Menor LT < <
Maior ou igual GE >>= >>=
Menor ou igual LE <= <=
Igual a algum elemento de uma lista IN   %in%
Não NOT ^ ¬ ~ ! 1
E AND & & 2
OU OR | | 3

Algumas funções

Definição SAS R
Máximo max() max()
Mínimo min() min()
Média mean() mean()
Soma sum() sum()
Contagem count() count()

PROC SQL (SAS) e dplyr (R)

Tanto o PROC SQL do SAS quanto o pacote dplyr do R são poderosas ferramentas para tratamento de dados. A seguir tabela comparando algumas funções de dplyr a instruções SQL.

Descrição Função dplyr PROC SQL equivalente
Seleção de colunas (variáveis) select() SELECT
Filtrar linhas (subconjunto) filter() WHERE
Agrupar os dados group_by() GROUP BY
Resumir (ou agregar) dados summarise() -
Ordenar os dados arrange() ORDER BY
Joining data frames (juntar tabelas) join() JOIN
Criando Novas Variáveis mutate() COLUMN ALIAS

Selecionar colunas

Aqui veremos como selecionar dados de uma tabela.

Sintaxe para seleção:

PROC SQL; SELECT coluna1, coluna2, ... FROM nome_tabela; QUIT;
nome_tabela %>% select(coluna1, coluna2, ...)

Aqui, coluna1, coluna2, … são os nomes das colunas da tabela da qual desejamos selecionar os dados. Se quisermos selecionar todos os campos disponíveis na tabela, usamos a seguinte sintaxe:

PROC SQL; SELECT * FROM nome_tabela; QUIT;
nome_tabela

Seleção de distintos

Dentro de uma tabela é comum ocorrer valores duplicados, e muitas vezes desejamos listar apenas os valores diferentes (distintos).

Os codigos a seguir são utilizados para retonar apenas valores distintos (diferentes).

PROC SQL; SELECT DISTINCT * FROM nome_tabela ; QUIT;
nome_tabela %>% distinct()

Exemplos

Utilizaremos a tabela CARS (mantendo apenas as linhas completas) presente no SAS Studio University para exemplificar a seleção de dados em uma tabela.

Os seguintes códigos selecionam as colunas “Make” e “Origin” da tabela “CARS”:

PROC SQL; SELECT Make, Origin FROM CARS; QUIT;
CARS %>% select(Make, Origin)

Resultado:

Vejamos agora o resultado selecionando apenas os registros diferentes das colunas “Make” e “Origin” da tabela “CARS”:

PROC SQL; SELECT DISTINCT Make, Origin FROM CARS; QUIT;
CARS %>% select(Make, Origin) %>% distinct()

Resultado:

Observamos uma redução no numero de registro de 428 para 38 devido a exclusão dos registros repetidos.

Filtrar linhas

Extrair apenas os registros que atendem a uma condição especificada.

Códigos utilizados para filtrar registros:

PROC SQL; SELECT coluna1, coluna2, ... FROM nome_tabela WHERE condição; QUIT;
nome_tabela %>% select(coluna1, coluna2, ...) %>% dplyr::filter(condição)

Em filter() multiplos argumentos são equivalentes a utilizar &.

Exemplo

Vamos selecionar as colunas Make, Origin e Cylinders, os registros distintos em que Origin é igual a ‘Europe’ e Cylinders igual a 4 ou 6:

PROC SQL; SELECT DISTINCT Make, Origin, Cylinders FROM CARS WHERE Origin = 'Europe' AND Cylinders IN (4,6); QUIT;
CARS %>% select(Make, Origin, Cylinders) %>% dplyr::filter(Origin == 'Europe', Cylinders %in% c(4,6)) %>% distinct()

Resultado:

Observe que, neste caso, ao utilizar o R podemos fazer o filtro antes ou depois do select() sem prejuízo do resultado. Porém quando utilizamos a função filter() após o select() devemos garantir que as colunas utilizadas no filtro estejam selecionas anteriormente.

Agora inserindo mais restrições. Vamos selecionar as colunas Make, Type e Origin, os registros distintos em que Origin é igual a Europe e Type diferente de SUV ou que Cylinders maior que 4:

PROC SQL; SELECT DISTINCT Make, Type, Origin FROM CARS WHERE Origin = 'Europe' AND Type ^= 'SUV' OR Cylinders > 6; QUIT;
CARS %>% dplyr::filter(Origin == 'Europe', Type != 'SUV' | Cylinders > 6) %>% select(Make, Type, Origin) %>% distinct()

Ou

CARS %>% select(Make, Type, Origin, Cylinders) %>% dplyr::filter(Origin == 'Europe' & Type != 'SUV' | Cylinders > 6) %>% select(-Cylinders) %>% distinct()

Resultado:

Ordenar - Order by

Muitas vezes desejamos classificar os registros do conjunto de dados de acordo com uma ou mais colunas. Para ordernar o conjunto de dados em ordem crescente ou decrescente utilizamos:

PROC SQL; SELECT coluna1, coluna2, ... FROM nome_tabela ORDER BY column1, column2, ... ASC|DESC; QUIT;
nome_tabela %>% select(coluna1, coluna2, ...) %>% arrange(column1, column2, ...)

Por padrão tanto o R qual SAS classificam os registros em ordem crescente. Para classificar os registros em ordem decrescente, no SAS adiciona-se DESC após o nome da coluna deseja, e no R aplica-se a função desc() na coluna desejada.

Exemplo

Vamos selecionar as colunas Model, Type e Cylinders, ordenar primeiramente de forma crescente por Type e descrescente por Cylinders:

PROC SQL; SELECT Model, Type, Cylinders FROM CARS ORDER BY Type, Cylinders DESC; QUIT;
CARS %>% select(Model, Type, Cylinders) %>% arrange(Type, desc(Cylinders))

Resultado:

Criando novas variáveis

Podemos criar novas variáveis como funções das existentes ou talvez apenas renomeando, a seguir abordaremos esses casos.

Soma, Média, Mínimo, Máximo, Contagem

Para obter a soma de uma coluna basta:

PROC SQL; SELECT coluna1, coluna2, ... SUM(coluna1) as sum_coluna1 FROM nome_tabela; QUIT;
nome_tabela %>% select(coluna1, coluna2, ...) %>% mutate(sum_coluna1 = sum(column1))

Para obter a média, mínimo, máximo e a contagem de uma coluna devemos substituir sum() por mean(), min(), max() e count(), respectivamente.

Exemplo

PROC SQL; SELECT Model, Cylinders, Horsepower, MEAN(Horsepower) as media_HP FROM CARS; QUIT;
CARS %>% select(Model, Cylinders, Horsepower) %>% mutate(media_HP = mean(Horsepower))

Resultado:

Casos - Case when

A instrução CASE passa por condições e retorna um valor quando a primeira condição é atendida (como uma instrução IF-THEN-ELSE). Então, uma vez que uma condição é verdadeira, ela irá parar de ler e retornar o resultado. Se nenhuma condição for verdadeira, retornará o valor na cláusula ELSE.

Sintaxe:

PROC SQL; SELECT coluna1, coluna2, ... CASE WHEN condição1 THEN resultado1 WHEN condição2 THEN resultado2 WHEN condiçãoN THEN resultadoN ELSE resultado END AS caso_coluna FROM nome_tabela; QUIT;
nome_tabela %>% select(coluna1, coluna2, ...) %>% mutate(caso_coluna = case_when(condição1 ~ resultado1, condição2 ~ resultado2, condiçãoN ~ resultadoN, TRUE ~ resultado))

Exemplo:

Selecionar colunas Model, Cylinders, Horsepower, Origin e criar uma coluna chamada origem que recebe ‘Europeu’ se Origin igual a ‘Europe’, caso contrário recebe ‘Outros’:

PROC SQL; SELECT Model, Cylinders, Horsepower, Origin, CASE WHEN Origin = 'Europe' THEN 'Europeu' ELSE 'Outros' END AS origem FROM CARS; QUIT;
CARS %>% select(Model, Cylinders, Horsepower, Origin ) %>% mutate( origem = case_when( Origin == 'Europe' ~ 'Europeu', Origin != 'Europe' ~ 'Outros') )

Resultado:

Agrupar - Group by

Grande parte das operações realizadas com dados requer a definição de grupos por variáveis.

O agrupamento, geralmente, é usado com funções agregadas (count(), max(), min(), sum(), mean()) para agrupar o conjunto de resultados em uma ou mais colunas.

PROC SQL; SELECT coluna1, coluna2, ... FROM nome_tabela GROUP BY coluna1, coluna2,...; QUIT;
nome_tabela %>% group_by(coluna1, coluna2,...)

Caso não haja mais interesse em permanecer com o conjunto de dados agrupado, em R, deve-se aplicar a função ungroup(), caso contrário todas as operações realizadas na sequencia neste conjunto de dados será realizada considerando os grupos definidos. Em SAS não há essa preocupação, mas caso queira permanecer a fazer operações com o mesmo grupo, deve-se replicar o agrupamento a cada seleção.

Exemplo

Selecionar as colunas Model, Type, Horsepower, e criar coluna da média de Horsepower por Type:

PROC SQL; SELECT Model, Type, Horsepower, mean(Horsepower) as media_HP FROM CARS GROUP BY Type; QUIT;
CARS %>% select(Model, Type, Horsepower) %>% group_by(Type) %>% mutate(media_HP = mean(Horsepower))

Resultado:

Caso desejemos obter apenas as colunas media_HP e Type o dplyr proporciona um atalho utilizando summarise(), enquanto que em SAS devemos selecionar apenas as variáveis desejadas e aplicar o argumento DISTINCT, veja:

PROC SQL; SELECT DISTINCT Type, mean(Horsepower) as media_HP FROM CARS GROUP BY Type; QUIT;
CARS %>% group_by(Type) %>% summarise(media_HP = mean(Horsepower))

Resultado:

Criar tabelas

Até o presente momento apenas fizemos consultas e transformações a partir de uma tabela de dados existente, mas não armazenamos estas consultas e transformações. No R para armazenarmos a consulta basta indicar um objeto para recebe-la, já no SAS podemos utilizar a instrução CREATE TABLE (esta instrução também permite criar tabela especificando manualmente as entradas, porém aqui nos restringiremos a criação de tabelas a partir de consultas a tabelas existentes).

Sintaxe para criação de tabela:

PROC SQL; CREATE TABLE nome_nova_tabela AS SELECT coluna1, coluna2, ... FROM nome_tabela; QUIT;
nome_nova_tabela <- nome_tabela %>% select(coluna1, coluna2, ...)

Exemplo:

PROC SQL; CREATE TABLE fabricante_origem AS SELECT DISTINCT Make, Origin FROM CARS; QUIT;
fabricante_origem <- CARS %>% select(Make, Origin) %>% distinct()

Desta forma, ao consultar a tabela fabricante_origem, obteremos o seguinte resultado sem necessidade de fazer o tratamento na tabela original (CARS) novamente:

Unir tabelas (JOIN)

Uma cláusula JOIN é usada para combinar linhas de duas ou mais tabelas, com base em uma coluna relacionada entre elas.

Esquema gráfico para representar os diversas formas de união entre tabelas com SQL.

Base de dados dos exemplos

Para exemplificar a união de tabelas vamos construir duas tabelas amostradas a partir do dataset CARS, utilizaremos a variável Model como chave primária para as uniões.

Tabela CARS_1:

Tabela CARS_2:

INNER JOIN

Retorna registros que possuem valores correspondentes nas duas tabelas.

Sintaxe para INNER JOIN de tabelas:

PROC SQL; SELECT coluna1, coluna2, ... FROM tabela_1 INNER JOIN tabela_2 ON tabela_1.nome_coluna = tabela_2.nome_coluna; QUIT;
tabela_1 %>% inner_join(tabela_2, by = 'nome_coluna' ) %>% select(coluna1, coluna2, ...)

Exemplo

PROC SQL; SELECT * FROM CARS_1 INNER JOIN CARS_2 ON CARS_1.Model = CARS_2.Model; QUIT;
CARS_1 %>% inner_join(CARS_2, by = 'Model' )

Resultado:

LEFT JOIN

Retorna todos os registros da tabela à esquerda e os registros correspondentes da tabela à direita.

Sintaxe para LEFT JOIN de tabelas:

PROC SQL; SELECT coluna1, coluna2, ... FROM tabela_1 LEFT JOIN tabela_2 ON tabela_1.nome_coluna = tabela_2.nome_coluna; QUIT;
tabela_1 %>% left_join(tabela_2, by = 'nome_coluna' ) %>% select(coluna1, coluna2, ...)

Exemplo

PROC SQL; SELECT * FROM CARS_1 LEFT JOIN CARS_2 ON CARS_1.Model = CARS_2.Model; QUIT;
CARS_1 %>% left_join(CARS_2, by = 'Model' )

Resultado:

RIGHT JOIN

Retorna todos os registros da tabela à direita e os registros correspondentes da tabela à esquerda.

Sintaxe para RIGHT JOIN de tabelas:

PROC SQL; SELECT coluna1, coluna2, ... FROM tabela_1 RIGHT JOIN tabela_2 ON tabela_1.nome_coluna = tabela_2.nome_coluna; QUIT;
tabela_1 %>% right_join(tabela_2, by = 'nome_coluna' ) %>% select(coluna1, coluna2, ...)

Exemplo

PROC SQL; SELECT * FROM CARS_1 RIGHT JOIN CARS_2 ON CARS_1.Model = CARS_2.Model; QUIT;
CARS_1 %>% right_join(CARS_2, by = 'Model' )

Resultado:

FULL JOIN

Retorna todos os registros quando há uma correspondência na tabela esquerda ou direita.

Sintaxe para FULL JOIN de tabelas:

PROC SQL; SELECT coluna1, coluna2, ... FROM tabela_1 FULL JOIN tabela_2 ON tabela_1.nome_coluna = tabela_2.nome_coluna; QUIT;
tabela_1 %>% full_join(tabela_2, by = 'nome_coluna' ) %>% select(coluna1, coluna2, ...)

Exemplo

PROC SQL; SELECT * FROM CARS_1 FULL JOIN CARS_2 ON CARS_1.Model = CARS_2.Model; QUIT;
CARS_1 %>% full_join(CARS_2, by = 'Model' )

Resultado:

Referências

Curso SAS Programming for R Users, https://support.sas.com/edu/schedules.html?ctry=br&crs=SP4R

https://www.w3schools.com/sql

http://www.sascommunity.org/planet/blog/category/dplyr/