sábado, 15 de agosto de 2020

Exploração de dados com SELECT

Photo by Edu Grande on Unsplash

A melhor parte de analisar os dados é quando vou entrevistar os dados (obter informações). É nessa etapa que descobrimos se os dados estão completos, se existe algum dado que não é necessário e, acima de tudo, que tipo de informações podemos obter com esses dados. Uma maneira de pensar nessa etapa é como se ela você uma entrevista de emprego. Você deve fazer perguntas que vão lhe dar as informações para contratar essa pessoa e onde ela será mais produtiva. Do mesmo modo você deve fazer com os dados: Esses dados me serão útil? Onde?
A entrevista é importante porque você obtém informações. Por exemplo, numa entrevista de emprego você descobre que metade dos entrevistados não colocou o nome do pai ou não informou um endereço de e-mail. Na entrevista você pode descobrir se os seus dados estão incorretos: nomes trocados, faltando letras, data no formato errado, entre outras coisas. Esse tipo de informação se torna parte dos dados.
Na linguagem SQL, começamos a entrevista com a declaração SELECT. Essa declaração é utilizada para recuperar informações de linhas e colunas nos bancos de dados. A instrução SELECT pode ser simples, retornando toda a informação sem nenhum filtro, ou pode ser complexa, retornando dezenas de tabelas e aplicando filtros e cálculos.
Nesse tutorial vamos começar com instruções SELECT simples.

Sintaxe básica da declaração SELECT

Nesse exemplo, vamos selecionar todas as linhas e colunas da tabela funcionarios. Essa coluna está no banco de dados que criamos no último tutorial. É importante ter um banco de dados selecionado antes de clamar a instrução SELECT. Você pode notar o banco de dados selecionado entre colchetes.

MariaDB [(none)]> USE meu_banco_de_dados;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [meu_banco_de_dados]> SELECT * FROM funcionarios;
+------+---------+----------+-------------------+-------------+---------+
| id   | p_nome  | u_nome   | profissao         | data_inicio | salario |
+------+---------+----------+-------------------+-------------+---------+
|    0 | Eveline | Ferreira | Vendedor          | 2018-02-03  |    3400 |
|    1 | Osvaldo | Perreira | Vendedor          | 2018-03-03  |    3400 |
|    2 | Maria   | Saturno  | Gerente de vendas | 2018-01-01  |    8500 |
|    3 | Mariana | Reis     | Diretor           | 2018-01-01  |    5000 |
|    4 | Marisa  | Lima     | Gerente           | 2019-03-01  |    9000 |
+------+---------+----------+-------------------+-------------+---------+
5 rows in set (0.001 sec)

Esse exemplo mostra a forma mais básica de selecionar dados com a linguagem SQL. Utilizamos o asterisco, depois da declaração SELECT, como um curinga. O curinga é utilizado no lugar de um valor especifico. O asterisco assume o valor de todos os valores possíveis. A instrução utilizada nesse exemplo é uma forma de dizer: 'selecione todas as colunas da tabela funcionarios'. Se você passar o nome de uma coluna, no lugar do asterisco, apenas os valores dessa coluna serão apresentados. A declaração FROM indica onde a declaração SELECT deve procurar os dados. O ponto e vírgula é utilizado para sinalizar o fim da instrução.

Consultando um conjunto de colunas

O asterisco é utilizado para descobrir todo o conteúdo de uma tabela. Com grandes bancos de dados é mais prático limitar o número de coluna que a declaração deve retornar. Você pode não ter interesse nos dados sobre id ou data de entrada, você pode estar procurando informações sobre profissão e salário. Podemos definir os dados que temos interesse passando os nomes das colunas separados por vírgula depois da declaração SELECT. Veja um exemplo:

MariaDB [meu_banco_de_dados]> SELECT salario, profissao, p_nome FROM funcionarios;
+---------+-------------------+---------+
| salario | profissao         | p_nome  |
+---------+-------------------+---------+
|    3400 | Vendedor          | Eveline |
|    3400 | Vendedor          | Osvaldo |
|    8500 | Gerente de vendas | Maria   |
|    5000 | Diretor           | Mariana |
|    9000 | Gerente           | Marisa  |
+---------+-------------------+---------+
5 rows in set (0.001 sec)

Note que os dados foram retornados na ordem em que passamos os nomes das colunas. Primeiro o salário, depois a profissão e por último o nome.
Mesmos esses exemplos básicos, mostram uma boa estrategia para iniciar a analise de dados. É uma prática comum verificar se todos os dados estão presentes e no formato certo. As datas estão completas? Dia, mês e ano? Ou só o mês e o ano? Existem nomes começando, misteriosamente, com a letra C? Esses são alguns problemas que você pode achar nessa "entrevista".
Nesse exemplo, utilizamos um banco de dados com poucas linhas, mas quando você se deparar com um banco de dados, com centenas ou milhares de linhas, é preciso fazer uma analise rápida da quantidade e qualidade dos dados. Vamos fazer isso com mais algumas declarações do SQL.

Selecionando valores únicos com a declaração DISTINCT

É muito comum encontrar colunas com valores duplicados. Na coluna profissao temos algumas linhas com o valor vendedor. Isso porque uma empresa pode ter vários vendedores. Se você precisar saber quais profissões estão presentes na tabela profissao, podemos fazer uma consulta que vai retornar apenas valores únicos, eliminando os valores duplicados com a declaração DISTINCT (os valores não serão mostrados, mais continuam na tabela).

MariaDB [meu_banco_de_dados]> SELECT DISTINCT profissao
    -> FROM funcionarios;
+-------------------+
| profissao         |
+-------------------+
| Vendedor          |
| Gerente de vendas |
| Diretor           |
| Gerente           |
+-------------------+
4 rows in set (0.001 sec)

Mesmo a tabela funcionarios tendo cinco linhas, essa instrução nos mostro apenas quatro. Isso porque o valor Vendedor aparece mais de uma vez e a declaração DISTINCT nos mostra apenas valores únicos. Essa declaração é útil para analisar a quantidade e a qualidade dos dados. Com ela podemos saber o quanto de dados vamos analisar e quantos desses dados estão numa boa qualidade. Por exemplo, com a declaração DISTINCT podemos saber se existem dados escrito de forma de forma errada, como o valor Vendedor escrito dessa forma: Cendedor.
Podemos ver os valores únicos de mais de uma coluna por vez. Para isso precisamos passar os nomes das colunas separadas por vírgula.

MariaDB [meu_banco_de_dados]> SELECT DISTINCT profissao, salario
    -> FROM funcionarios;
+-------------------+---------+
| profissao         | salario |
+-------------------+---------+
| Vendedor          |    3400 |
| Gerente de vendas |    8500 |
| Diretor           |    5000 |
| Gerente           |    9000 |
+-------------------+---------+
4 rows in set (0.001 sec)

Desse modo podemos saber, por exemplo, quantos profissões tem salários diferentes. Se tiver uma pessoa que tem a mesma profissão, mas que recebe um salário diferente, será retornado o valor profissão para cada salário diferente.
Adicione uma nova linha na tabela funcionarios com o valor Vendedor e com um salário diferente de 3400 (Veja como fazer isso no tutorial anterior). Depois chame a mesma instrução do exemplo acima, o resultado deve ser parecido com esse:

MariaDB [meu_banco_de_dados]> SELECT DISTINCT profissao, salario
    -> from funcionarios;
+-------------------+---------+
| profissao         | salario |
+-------------------+---------+
| Vendedor          |    3400 |
| Gerente de vendas |    8500 |
| Diretor           |    5000 |
| Gerente           |    9000 |
| Vendedor          |    6500 |
+-------------------+---------+
5 rows in set (0.001 sec)

Note que agora temos dois valores Vendedor na coluna profissão, mas com os valores da coluna salário diferentes.

Ordenando dados com a declaração ORDER BY

Um maneira de encontrar algum sentido nos dados é organizando esses dados de alguma forma. Quando os dados estão organizados fica mais fácil encontrar algum padrão que não percebemos quando os dados estão misturados. Com a linguagem SQL podemos organizar os dados de uma consulta com a declaração ORDER BY seguido do nome da coluna ou das colunas.
Quando utilizamos ORDER BY numa consulta não estamos modificando a tabela, apenas os dados retornados pela consulta. Veja um exemplo de como utilizar ORDER BY:

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> ORDER BY salario DESC;
+---------+-------------------+---------+
| p_nome  | profissao         | salario |
+---------+-------------------+---------+
| Marisa  | Gerente           |    9000 |
| Maria   | Gerente de vendas |    8500 |
| Fabiana | Vendedor          |    6500 |
| Mariana | Diretor           |    5000 |
| Eveline | Vendedor          |    3400 |
| Osvaldo | Vendedor          |    3400 |
+---------+-------------------+---------+
6 rows in set (0.001 sec)

Nesse exemplo, organizamos os dados de forma decrescente adicionando a palavra-chave DESC. Por padrão ORDER BY organiza os dados de forma crescente. Ordenando os valores de forma decrescente descobrimos qual é a profissão que ganha mais.
A organização nos permite fazer consultas de forma mais direta e uma maior flexibilização na hora de visualizar os dados. Um dessas flexibilidades é a capacidade de organizar mais de uma coluna.

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, data_inicio
    -> FROM funcionarios
    -> ORDER BY p_nome ASC, data_inicio DESC;
+---------+-------------------+-------------+
| p_nome  | profissao         | data_inicio |
+---------+-------------------+-------------+
| Eveline | Vendedor          | 2018-02-03  |
| Fabiana | Vendedor          | 2019-03-20  |
| Maria   | Gerente de vendas | 2018-01-01  |
| Mariana | Diretor           | 2018-01-01  |
| Marisa  | Gerente           | 2019-03-01  |
| Osvaldo | Vendedor          | 2018-03-03  |
+---------+-------------------+-------------+
6 rows in set (0.001 sec)

Nesse exemplo, organizamos a coluna p_nome de forma crescente (ordem alfabética) e, a coluna data_inicio, de forma decrescente. Mas se a coluna data_inicio esta organizada de forma decrescente porque a data 2019-03-20 não está no topo? Porque a prioridade é a coluna p_nome. Primeiro os resultados são organizados por nomes e depois por data, criando subgrupos de organização.
Com esse exemplo, podemos obter a resposta para o tipo de pergunta: “Qual é a pessoa, que o nome começa com F, que está na empresa a mais tempo?”. Esse é um exemplo bobo, mas com os dados certos essa informação é muito importante.

Filtrando linhas com WHERE

Com um banco de dados grande você vai precisar limitar os resultados de uma consulta. Talvez você queira apenas os resultados que satisfaça algumas condições. Por exemplo, as profissões que ganham mais de três mil ou o nome das pessoas que trabalham como vendedor. Para limitar os resultados com condições que os dados devem ter usamos a declaração WHERE.
A declaração WHERE é utilizada para encontrar dados que correspondam a um valor especifico ou satisfação uma condição. Utilizando WHERE você pode excluir linhas com base em condições.
A declaração WHERE vem depois da declaração FROM e do nome da tabela onde vamos fazer uma consulta. Veja um exemplo:

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE profissao = 'Vendedor';
+---------+-----------+---------+
| p_nome  | profissao | salario |
+---------+-----------+---------+
| Eveline | Vendedor  |    3400 |
| Osvaldo | Vendedor  |    3400 |
| Fabiana | Vendedor  |    6500 |
+---------+-----------+---------+
3 rows in set (0.003 sec)

Nesse exemplo, fizemos uma consulta nas colunas p_nome, profissao e salario da tabela funcionarios e definimos que queremos ver apenas as linhas onde o valor da coluna profissao é igual a Vendedor. No exemplo acima, utilizamos apenas o operador igual, mas a linguagem SQL tem suporte a outros operadores. Veja a lista dos operadores suportados pela linguagem SQL:

Operador Função Exemplo
= Igual WHERE profissao = ‘Vendedor’
<> Diferente WHERE profissao <> ‘Vendedor’
> Maior que WHERE salario > 3000
< Menor que WHERE salario < 6000
>= Maior ou igual WHERE salario >= 6500
<= Menor ou igual WHERE salario <= 6500
BETWEEN Entre x e y WHERE salario BETWEEN 6000 AND 9000
IN Corresponde a um dos elementos passados WHERE profissao IN (‘Vendedor’, 'Gerente de vendas')
LIKE Corresponde a um padrão (Case sensitive) WHERE p_nome LIKE ‘Mar%’
NOT Nega uma condição WHERE p_nome NOT ILIKE ‘mar%’

Agora que já sabemos quais operadores podemos usar, vamos utilizar cada operador num exemplo. Vamos começar com o operador igual. Vamos selecionar todas as linhas com o valor da coluna salario igual a 3400.

MariaDB [meu_banco_de_dados]> SELECT u_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE salario = 3400;
+----------+-----------+---------+
| u_nome   | profissao | salario |
+----------+-----------+---------+
| Ferreira | Vendedor  |    3400 |
| Perreira | Vendedor  |    3400 |
+----------+-----------+---------+
2 rows in set (0.001 sec)

Para o nosso próximo exemplo, vamos selecionar todas as linhas que tenham um valor diferente de Vendedor na coluna profissao.

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE profissao <> 'Vendedor';
+---------+-------------------+---------+
| p_nome  | profissao         | salario |
+---------+-------------------+---------+
| Maria   | Gerente de vendas |    8500 |
| Mariana | Diretor           |    5000 |
| Marisa  | Gerente           |    9000 |
+---------+-------------------+---------+
3 rows in set (0.001 sec)

No exemplo abaixo, vamos usar os operadores >, <, >=, <=.

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE salario > 4000;
+---------+-------------------+---------+
| p_nome  | profissao         | salario |
+---------+-------------------+---------+
| Maria   | Gerente de vendas |    8500 |
| Mariana | Diretor           |    5000 |
| Marisa  | Gerente           |    9000 |
| Fabiana | Vendedor          |    6500 |
+---------+-------------------+---------+
4 rows in set (0.001 sec)

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE salario < 7000;
+---------+-----------+---------+
| p_nome  | profissao | salario |
+---------+-----------+---------+
| Eveline | Vendedor  |    3400 |
| Osvaldo | Vendedor  |    3400 |
| Mariana | Diretor   |    5000 |
| Fabiana | Vendedor  |    6500 |
+---------+-----------+---------+
4 rows in set (0.001 sec)

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE salario >= 3400;
+---------+-------------------+---------+
| p_nome  | profissao         | salario |
+---------+-------------------+---------+
| Eveline | Vendedor          |    3400 |
| Osvaldo | Vendedor          |    3400 |
| Maria   | Gerente de vendas |    8500 |
| Mariana | Diretor           |    5000 |
| Marisa  | Gerente           |    9000 |
| Fabiana | Vendedor          |    6500 |
+---------+-------------------+---------+
6 rows in set (0.001 sec)

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE salario <= 9000;
+---------+-------------------+---------+
| p_nome  | profissao         | salario |
+---------+-------------------+---------+
| Eveline | Vendedor          |    3400 |
| Osvaldo | Vendedor          |    3400 |
| Maria   | Gerente de vendas |    8500 |
| Mariana | Diretor           |    5000 |
| Marisa  | Gerente           |    9000 |
| Fabiana | Vendedor          |    6500 |
+---------+-------------------+---------+
6 rows in set (0.001 sec)

Para o nosso próximo exemplo vamos selecionar todas as linhas que o valor da coluna salario esteja entre 3500 e 8900.

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE salario BETWEEN 3500 AND 8900;
+---------+-------------------+---------+
| p_nome  | profissao         | salario |
+---------+-------------------+---------+
| Maria   | Gerente de vendas |    8500 |
| Mariana | Diretor           |    5000 |
| Fabiana | Vendedor          |    6500 |
+---------+-------------------+---------+
3 rows in set (0.004 sec)

Com operador IN você pode passar um conjunto de valores para a declaração WHERE. Desse modo a declaração WHERE vai fazer mais de uma verificação por dado. Por exemplo, você pode querer selecionar as linhas que tenham os valores 'Vendedor' ou 'Gerente' na coluna profissao. Veja o exemplo disso:

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE profissao IN ('Gerente', 'Vendedor');
+---------+-----------+---------+
| p_nome  | profissao | salario |
+---------+-----------+---------+
| Eveline | Vendedor  |    3400 |
| Osvaldo | Vendedor  |    3400 |
| Marisa  | Gerente   |    9000 |
| Fabiana | Vendedor  |    6500 |
+---------+-----------+---------+
4 rows in set (0.001 sec)

Usando o operador LIKE

Para o nosso próximo exemplo vamos utilizar o operador LIKE. Esse operador vai selecionar dados que começam com a string que passamos para o operador. É importante notar que o operador LIKE diferencia letras maiúsculas de minusculas, então Mar e mar são diferentes.

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE p_nome LIKE 'Mar%';
+---------+-------------------+---------+
| p_nome  | profissao         | salario |
+---------+-------------------+---------+
| Maria   | Gerente de vendas |    8500 |
| Mariana | Diretor           |    5000 |
| Marisa  | Gerente           |    9000 |
+---------+-------------------+---------+
3 rows in set (0.001 sec)

O sinal de porcentagem (%) no final da string é utilizado para sinalizar que queremos qualquer valor que comece com 'Mar' não importa o tamanho que esse valor tenha. Esse caractere também pode ser utilizado para selecionar valores com um final de string em comum. Por exemplo, na coluna p_nome existem dois nomes que terminam com ‘ana’ no final, Fabiana e Mariana. Para selecionar as linhas que tenham esses valores passaríamos a string ‘%ana’ para o operador LIKE.
Outro carácter utilizado é o underline (_). Esse caractere é usado para sinalizar que queremos os valores com apenas um carácter a mais dos que já passamos. Por exemplo, passando ‘Marian_’ para o operador LIKE, o operador vai retornar todos os valores que comecem com ‘Marian’ e tenham um carácter a mais. Esse carácter pode ser qualquer um, pode ser um a, um b ou c. Se começar com ‘Marian’ e tiver somente mais um carácter o valor será selecionado pelo operador. E o underline pode ser usado no meio da palavra.
Veja outros exemplos de utilização dos caracteres de porcentagem e underline:

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE p_nome LIKE '%ana';
+---------+-----------+---------+
| p_nome  | profissao | salario |
+---------+-----------+---------+
| Mariana | Diretor   |    5000 |
| Fabiana | Vendedor  |    6500 |
+---------+-----------+---------+
2 rows in set (0.000 sec)

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE p_nome LIKE '%ia%';
+---------+-------------------+---------+
| p_nome  | profissao         | salario |
+---------+-------------------+---------+
| Maria   | Gerente de vendas |    8500 |
| Mariana | Diretor           |    5000 |
| Fabiana | Vendedor          |    6500 |
+---------+-------------------+---------+
3 rows in set (0.001 sec)

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE p_nome LIKE 'Marian_';
+---------+-----------+---------+
| p_nome  | profissao | salario |
+---------+-----------+---------+
| Mariana | Diretor   |    5000 |
+---------+-----------+---------+
1 row in set (0.001 sec)

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE p_nome LIKE 'Mar_ana';
+---------+-----------+---------+
| p_nome  | profissao | salario |
+---------+-----------+---------+
| Mariana | Diretor   |    5000 |
+---------+-----------+---------+
1 row in set (0.001 sec)

Combinando operadores com AND ou OR

A linguagem SQL nos permite utilizar mais de um operador ao mesmo tempo. Assim podemos definir mais de uma condição para selecionar um valor. Por exemplo, você pode querer selecionar apenas os valores que tenham o valor 'Vendedor' na coluna profissao e o valor da coluna salario maior que 3400. Para isso usamos a palavra chave AND. Com ela o dado só será selecionado se atender as duas condições, ter o valor ‘Vendedor’ na coluna profissao E (AND) o valor da coluna salario maior que 3400.
A palavra-chave OR define duas condições e se qualquer uma dessas condições for satisfeita o dado é selecionado. Por exemplo, se você quiser selecionar os dados que tenham o valor ‘Vendedor’ na coluna profissao ou o valor da coluna salario seja maior que 3000, você deve usar OR.
Veja exemplos de como utilizar AND e OR:

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE profissao = 'Vendedor'
    -> AND salario > 3400;
+---------+-----------+---------+
| p_nome  | profissao | salario |
+---------+-----------+---------+
| Fabiana | Vendedor  |    6500 |
+---------+-----------+---------+
1 row in set (0.001 sec)

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE profissao = 'Vendedor'
    -> OR salario > 3000;
+---------+-------------------+---------+
| p_nome  | profissao         | salario |
+---------+-------------------+---------+
| Eveline | Vendedor          |    3400 |
| Osvaldo | Vendedor          |    3400 |
| Maria   | Gerente de vendas |    8500 |
| Mariana | Diretor           |    5000 |
| Marisa  | Gerente           |    9000 |
| Fabiana | Vendedor          |    6500 |
+---------+-------------------+---------+
6 rows in set (0.001 sec)

Utilizando WHERE E ORDER BY juntos

Você já pode perceber que até as consultas mais simples nos permitem analisar os dados com precisão e flexibilidade para encontrar o que procuramos. Aprendemos a usar as palavras chaves AND e OR para definir mais de uma condição ao selecionar dados. E ainda aprendemos a utilizar a declaração WHERE e organizar os dados com a declaração ORDER BY.
Agora vamos combinar o que aprendemos nesse tutorial num exemplo. O SQL é específico quanto à ordem das palavras chaves, então siga essa ordem:

SELECT nome_colunas
FROM nome_tabelas
WHERE condição
ORDER BY nome_colunas;

Veja um exemplo utilizando os conhecimentos que você acabou de adquirir:

MariaDB [meu_banco_de_dados]> SELECT p_nome, profissao, salario
    -> FROM funcionarios
    -> WHERE p_nome LIKE 'Mar' OR salario > 3400
    -> ORDER BY id DESC;
+---------+-------------------+---------+
| p_nome  | profissao         | salario |
+---------+-------------------+---------+
| Fabiana | Vendedor          |    6500 |
| Marisa  | Gerente           |    9000 |
| Mariana | Diretor           |    5000 |
| Maria   | Gerente de vendas |    8500 |
+---------+-------------------+---------+
4 rows in set (0.001 sec)

Note que não selecionamos a coluna id, mas podemos utilizá-la com a declaração ORDER BY.

sexta-feira, 14 de agosto de 2020

Criando seu primeiro banco de dados e tabela com SQL

Photo by Jeremy Manoto on Unsplash

A linguagem SQL oferece mais do que um meio de obter informações de um banco de dados. Com ela podemos definir as estruturas que serão utilizadas para guardar e organizar os dados. A principal estrutura e a TABLE (tabela).
Uma tabela funciona como uma grade, com linhas e colunas. Essas linhas e colunas criam células (como no Excel), onde podemos armazenar os dados. As linhas possuem colunas e, colunas armazenam dados. Os dados mais comuns são do tipo números, datas e strings (cadeia de caracteres). A linguagem SQL nos permite criar uma estrutura de tabela e definir como essa tabela se relaciona com outras no banco de dados. Outro uso comum do SQL é fazer consultas, para extrair dados, das tabelas.
Tabela é a principal estrutura que você deve aprender para entender os dados do banco de dados. Quando começar a trabalhar com um banco de dados novo, a primeira coisa que você deve fazer é olhar as tabelas. Procure por algo que possa chamar sua atenção nos nomes das tabelas e na estrutura das colunas. A coluna contem texto, número ou os dois? Qual é a quantidade de linhas em cada tabela?
Em seguida, veja quantas tabelas existem. O mais simples dos bancos de dados pode ter apenas uma tabela. Um banco de dados que armazena dados de clientes pode ter dezenas de tabelas, até mesmo centenas. Com essa informação você vai saber o quanto de dados você vai precisar analisar.

Criando um banco de dados com SQL

Os programas que vamos utilizar para nesse tutorial é o MariaDB e o MySQL. Esses programas são conhecidos como sistemas de gerenciamento de banco de dados. Com esses softwares podemos definir, criar e consultar bancos de dados. Ao instalar um desses programas, ele vai criar um servidor de banco de dados que já possui um banco de dados chamado mysql. Esse banco de dados contêm objetos que inclui usuários, tabelas e muito mais.
Nesse tutorial de SQL, e nos próximos, vamos usar o MariaDB e o MySQL a partir do terminal (Linux) e Prompt de Comando (Windows). Você pode utilizar tanto o MySQL quanto o MariaDB. A diferença entre os dois é quase só o nome.
Depois de instalar, qualquer um dos dois programas, digite mysql no terminal ou no prompt de comando. Você deve ver uma tela parecida com essa: 

Para ver os bancos de dados use a declaração SHOW DATABASES;. Esse comando vai lista todos os bancos de dados presentes na sua máquina. 

Não vamos mexer com nenhum desses bancos de dados, vamos criar o nosso próprio banco de dados. Para fazer isso precisamos digitar apenas uma linha: CREATE DATABASE meu_banco_de_dados;

Para criar um novo banco de dados utilizamos duas palavras chaves - CREATE e DATABASE - seguido pelo nome do banco de dados. Após o nome do novo banco de dados, terminamos a instrução com ponto e vírgula. O ponto e vírgula é utilizado para encerrar todas as instruções da linguagem SQL.
Agora que criamos um banco de dados vamos olhar os bancos de dados novamente e ver o nosso banco de dados meu_banco_de_dados

Criando uma tabela com SQL

É nas tabelas que os dados são armazenados e o relacionamento definido. Para criar uma tabela precisamos informar o seu nome e o tipo de dados que essa coluna vai guardar. O tipo de dado de uma coluna é muito importante, é esse tipo de dado que defini quais dados podem ser guardados na coluna. Por exemplo, uma coluna do tipo numérico, se você tentar guardar dados do tipo data ou texto vai gerar um erro.
Podemos acessar e analisar os dados das tabelas com declarações SQL. Também podemos visualizar e alterar os dados da tabela facilmente, se suas necessidades mudarem mais tarde.
Agora vamos criar uma tabela no nosso banco de dados meu_banco_de_dados.

Declaração CREATE TABLE do SQL

Vamos criar uma tabela dentro do nosso banco de dados para guardar informações sobre funcionários. As informações que vamos guardar são básicas: nome, salário, profissão, etc. Nesse primeiro momento vamos criar apenas a estrutura pra guardar os dados. É isso que a declaração CREATE TABLE faz, cria uma estrutura, uma tabela.
Antes de criar uma tabela, precisamos definir em qual banco de dados a tabela será criada. Fazemos isso usando a declaração USE. Veja abaixo, um exemplo de como selecionar o banco de dados e criar uma tabela com SQL:

Agora vamos entender o que acabamos de fazer. A declaração USE seleciona o banco de dados. Com a declaração CREATE TABLE funcionarios (...); criamos uma tabela com o nome funcionarios. Dentro dos parênteses, da declaração CREATE TABLE, definimos os nomes das colunas e o tipo de dados que essa coluna vai guardar. A primeira coluna é a de id. Essa coluna vai guardar somente dados do tipo inteiro (1, 2, 3, etc). Na segunda linha, dentro dos parênteses, criamos uma coluna chamada u_nome e definimos que ela vai guardar até 25 caracteres (a, b, c, 1, 23, #, etc). A coluna data_inicio vai guardar dados do tipo data (DD-MM-AAAA). E por fim a coluna salario vai guardar dados do tipo numérico (1, 0.23, 7865, etc).

Declaração INSERT do SQL

Para inserir dados numa tabela usamos a declaração INSERT INTO nome_da_tabela. Nessa declaração também definimos quais colunas vão receber valores. Veja o exemplo abaixo:

Na primeira linha definimos em qual tabela vamos inserir os dados. Na segunda linha definimos quais colunas vão receber os dados. VALUES indica o conjunto de valores que vão ser guardados na tabela. Cada conjunto de valores com o id, p_nome, u_nome, profissao, data_inicio e salario é passado entre parênteses e separados por vírgula. Note que todas essas linhas fazem parte de uma instrução, por isso só existe um ponto e vírgula. Essa instrução pode ser escrita numa linhas apenas.
Para ver os dados gravados use a declaração SELECT * FROM funcionarios;. Vamos aprender a utilizar essa declaração no próximo tutorial.

quinta-feira, 13 de agosto de 2020

Hash MD5 no Python

Imagem de TheDigitalWay por Pixabay

Os hashes criptográficos são muitos utilizados no dia-a-dia. Esse tipo de criptografia esta mais presente na sua vida do que você imagina. Por exemplo, eles são utilizados em assinaturas digitais, detecção de manipulação, códigos de autenticação de mensagens, impressões digitais, somas de verificação (verificação de integridade de mensagem ou arquivo), tabelas de hash, armazenamento de senha e muito mais. Os hashes têm mostrados a sua utilidade no envio de mensagens pela rede e para a segurança no armazenamento de senhas em servidores. Isso porque, a mensagem ou senha não fica salva diretamente no banco de dados, apenas o seu hash. Desse modo, mesmo que o banco de dados seja invadido as senhas estão salvas. Pelo menos em teoria (Nada é cem por cento seguro).
Para trabalhar com hash, python fornece várias funções no módulo hashlib. Nesse tutorial, vamos utilizar algumas dessas funções e explicar seu funcionamento do hash MD5.

MD5 Hash

A função de hash MD5 aceita sequências de bytes e retorna um valor hash de 128 bits. Esse hash é muito utilizado para verificar a integridade dos dados. Você já deve ter baixado algum arquivo, de um site, onde o hash MD5 é disponibilizado. Esse hash md5 é disponibilizado para que você possa ter certeza que o arquivo que você baixou é o mesmo que você queria. Geralmente são sites de torrents que fazem isso.
Essas são as funções que vamos utilizar para criar um hash md5:

  • encode(): Converte a string em bytes para ser aceitável pela função hash.
  • digest(): Retorna os dados codificados em formato de byte.
  • hexdigest(): Retorna os dados codificados em formato hexadecimal.

No exemplo abaixo, vamos passar um valor em bytes e vamos receber uma saída em bytes:

import hashlib 
  
# codificando a string Acervo Lima usando a função de hash md5
hash = hashlib.md5(b'Acervo Lima') 
  
# imprimir o equivalente em bytes. 
print("Equivalente em bytes ao hash: ", hash.digest())

No exemplo, chamamos a função md5() passando um valor em bytes. A função md5() faz a codificação dessa string e, depois, chamamos a função digest(). A função digest() retorna o resultado da função md5() em bytes.
Mas os hashes que vemos por ai não são disponibilizados em bytes, mas sim em hexadecimal. No exemplo abaixo, vamos retornar um hash md5 em hexadecimal.

>>> string = 'Acervo Lima'.encode()
>>> hash = hashlib.md5(string)
>>> print('O equivalente em hexadecimal ao hash: ',
... hash.hexdigest())
O equivalente em hexadecimal ao hash:  409b83920744582bf8b286e4e63e2207

Nesse exemplo, convertemos a string 'Acervo Lima' em bytes usando a função encode(). Depois, chamamos a função md5() para obter o hash md5 em bytes. E, em seguida, chamamos a função hexdigest(). A função hexdigest() converte os bytes em hexadecimal.

Referência:
Módulo hashlib

quarta-feira, 12 de agosto de 2020

concat() e append() do pandas, como usar

Imagem de Steve Buissinne por Pixabay

A biblioteca pandas possui várias facilidades para juntar séries e dataframes com outros tipos de conjuntos de dados. Nesse tutorial vamos aprender algumas dessas facilidades. Os métodos mais utilizados para concatenar uma série ou dataframe é o concat() e o append().

Concatenando Séries e DataFrames com o método concat

A função concat() é utilizada para concatenar (juntar) séries ou dataframes ao longo de um eixo. Com o método concat() podemos definir o eixo em que o método deve operar, isso no caso dos dataframes visto que as séries possuem somente um eixo. Antes de nos aprofundarmos nos parâmetros e peculiaridades desse método, vamos ver um exemplo simples de como o método opera.

>>> import pandas as pd
>>> dados1 = {
... 'A': ['A0', 'A1', 'A2', 'A3'],
... 'B': ['B0', 'B1', 'B2', 'B3'],
... 'C': ['C0', 'C1', 'C2', 'C3'],
... 'D': ['D0', 'D1', 'D2', 'D3']
... }
>>> dados2 = {
... 'A': ['A4', 'A5', 'A6', 'A7'],
... 'B': ['B4', 'B5', 'B6', 'B7'],
... 'C': ['C4', 'C5', 'C6', 'C7'],
... 'D': ['D4', 'D5', 'D6', 'D7']
... }
>>> dados3 = {
... 'A': ['A8', 'A9', 'A10', 'A11'],
... 'B': ['B8', 'B9', 'B10', 'B11'],
... 'C': ['C8', 'C9', 'C10', 'C11'],
... 'D': ['D8', 'D9', 'D10', 'D11']
... }
>>> df1 = pd.DataFrame(dados1, index=[0, 1, 2, 3])
>>> df2 = pd.DataFrame(dados1, index=[4, 5, 6, 7])
>>> df3 = pd.DataFrame(dados1, index=[8, 9, 10, 11])
>>> frames = [df1, df2, df3]
>>> resultado = pd.concat(frames)
>>> resultado
     A   B   C   D
0   A0  B0  C0  D0
1   A1  B1  C1  D1
2   A2  B2  C2  D2
3   A3  B3  C3  D3
4   A0  B0  C0  D0
5   A1  B1  C1  D1
6   A2  B2  C2  D2
7   A3  B3  C3  D3
8   A0  B0  C0  D0
9   A1  B1  C1  D1
10  A2  B2  C2  D2
11  A3  B3  C3  D3

O método concat() recebe uma lista ou dicionário e os junta de acordo com o eixo.
Sem contesto o exemplo acima deve ficar um pouco mais complicado de entender. Vamos voltar a ele. Digamos que você queira associar um rótulo para cada dataframe que foi concatenado. Assim fica mais fácil de saber onde cada dataframe foi posicionado. Podemos fazer isso passando os rótulos para o parâmetro keys.

>>> resultado = pd.concat(frames, keys=['X', 'Y', 'Z'])
>>> resultado
       A   B   C   D
X 0   A0  B0  C0  D0
  1   A1  B1  C1  D1
  2   A2  B2  C2  D2
  3   A3  B3  C3  D3
Y 4   A0  B0  C0  D0
  5   A1  B1  C1  D1
  6   A2  B2  C2  D2
  7   A3  B3  C3  D3
Z 8   A0  B0  C0  D0
  9   A1  B1  C1  D1
  10  A2  B2  C2  D2
  11  A3  B3  C3  D3

Adicionando esses rótulos criamos um índice hierárquico. Com essa vantagem podemos selecionar cada bloco pelo seu rótulo usando o atributo loc.

>>> resultado.loc['X']
    A   B   C   D
0  A0  B0  C0  D0
1  A1  B1  C1  D1
2  A2  B2  C2  D2
3  A3  B3  C3  D3

Com esse exemplo, você já pode ver como esse atributo pode ser útil. Para saber mais sobre o atributo loc, veja nosso tutorial sobre Seleção de subconjuntos de dados.

Definindo o critério de concatenação dos eixos

Os DataFrames pandas possuem dois eixos, o eixo de índice (eixo 0) e o eixo das colunas (eixo 1). Quando juntamos dois ou mais dataframes temos que decidir o que fazer com os outros eixos (além do que estamos concatenando). As opções que temos são as seguintes:

  • join='outer': Fazer a união de todos os eixos. Esse é o valor padrão. Essa opção evita perdas de dados.
  • join='inner': Fazer uma interseção dos eixos.

Vamos ver exemplos de como funciona cada uma das opções.

>>> dados4 = {
...     'B': ['B2', 'B3', 'B6', 'B7'],
...     'D': ['D2', 'D3', 'D6', 'D7'],
...     'F': ['F2', 'F3', 'F6', 'F7']
... }
>>> df4 = pd.DataFrame(dados4, index=[2, 3, 6, 7])
>>> resultado = pd.concat([df1, df4], axis=1, join='outer')
>>> resultado
     A    B    C    D    B    D    F
0   A0   B0   C0   D0  NaN  NaN  NaN
1   A1   B1   C1   D1  NaN  NaN  NaN
2   A2   B2   C2   D2   B2   D2   F2
3   A3   B3   C3   D3   B3   D3   F3
6  NaN  NaN  NaN  NaN   B6   D6   F6
7  NaN  NaN  NaN  NaN   B7   D7   F7

Nesse exemplo, usamos dois dataframes com o número de índices e colunas diferentes. Isso para ficar claro que passando o valor ‘outer’, para o parâmetro join, o método concat() vai tentar organizar os dois dataframes de uma forma que nenhum dado seja perdido. Se você olhar atentamente vai ver que o segundo dataframe (df4) começa no índice dois e na coluna segunda coluna B. Como o primeiro dataframe (df1) possui o mesmo índice não foi preciso criar um novo. Isso não acontece com a coluna B, não da pra encaixar essas colunas. Então novas são criadas. Por isso temos elementos vazios no dataframe resultado. Se o parâmetro join for omitido, o resultado é o mesmo porque o valor padrão desse parâmetro é ‘outer’.
Agora, vamos ver um exemplo passando o valor ‘inner’:

>>> resultado = pd.concat([df1, df4], axis=1, join='inner')
>>> resultado
    A   B   C   D   B   D   F
2  A2  B2  C2  D2  B2  D2  F2
3  A3  B3  C3  D3  B3  D3  F3

Nesse exemplo, podemos ver que perdemos muitos dados. Isso porque, quando passamos o valor ‘inner’ para o parâmetro join, estamos dizendo para o método que queremos apenas os dados dos índices que os dois dataframes tem em comum (no caso, 2 e 3). Você pode verificar que todos os dados dos índices 2 e 3, dos dois dataframes (df1 e df4), foram concatenados e os dados dos outro índices foram perdidos.
Nos dois últimos exemplos, concatenamos os dataframes no eixo 1 (colunas), mas podemos usar o eixo 0 (índice). Nesse caso, no primeiro exemplo o método concat() vai tentar unir as colunas. E no segundo exemplo, apenas as colunas em comum seriam concatenadas (B e D).

>>> resultado = pd.concat([df1, df4], axis=0, join='outer')
>>> resultado
     A   B    C   D    F
0   A0  B0   C0  D0  NaN
1   A1  B1   C1  D1  NaN
2   A2  B2   C2  D2  NaN
3   A3  B3   C3  D3  NaN
2  NaN  B2  NaN  D2   F2
3  NaN  B3  NaN  D3   F3
6  NaN  B6  NaN  D6   F6
7  NaN  B7  NaN  D7   F7
>>> resultado = pd.concat([df1, df4], axis=0, join='inner')
>>> resultado
    B   D
0  B0  D0
1  B1  D1
2  B2  D2
3  B3  D3
2  B2  D2
3  B3  D3
6  B6  D6
7  B7  D7

O nosso dataframe, resultante da concatenação de dois dataframes, pode ter a mesma quantidade de linhas do primeiro dataframe, e o excedente (do segundo dataframe) é perdido.

>>> resultado = pd.concat([df1, df4], axis=1).reindex(df1.index)
>>> resultado
    A   B   C   D    B    D    F
0  A0  B0  C0  D0  NaN  NaN  NaN
1  A1  B1  C1  D1  NaN  NaN  NaN
2  A2  B2  C2  D2   B2   D2   F2
3  A3  B3  C3  D3   B3   D3   F3

Usando o método append do pandas

Se você deseja concatenar dataframes somente no eixo 0 (índice), uma escolha interessante é o método append. Esse método concatena as series e os dataframes ao longo do eixo 0.

>>> resultado = df1.append(df2)
>>> resultado
    A   B   C   D
0  A0  B0  C0  D0
1  A1  B1  C1  D1
2  A2  B2  C2  D2
3  A3  B3  C3  D3
4  A0  B0  C0  D0
5  A1  B1  C1  D1
6  A2  B2  C2  D2
7  A3  B3  C3  D3

Você pode passar uma lista de objetos para serem concatenados.

>>> resultado = df1.append([df2, df3])
>>> resultado
     A   B   C   D
0   A0  B0  C0  D0
1   A1  B1  C1  D1
2   A2  B2  C2  D2
3   A3  B3  C3  D3
4   A0  B0  C0  D0
5   A1  B1  C1  D1
6   A2  B2  C2  D2
7   A3  B3  C3  D3
8   A0  B0  C0  D0
9   A1  B1  C1  D1
10  A2  B2  C2  D2
11  A3  B3  C3  D3

Ignorando índices

Você pode ignorar os índices completamente passando o valor True para o parâmetro ignore_index (Se esses dados não forem importantes). Desse modo, o método vai concatenar os dataframes de acordo com as colunas. Por exemplo, se os dois dataframes têm uma coluna chamada B, essas colunas ficaram uma embaixo da outra.

>>> resultado = pd.concat([df1, df4], ignore_index=True)
>>> resultado
     A   B    C   D    F
0   A0  B0   C0  D0  NaN
1   A1  B1   C1  D1  NaN
2   A2  B2   C2  D2  NaN
3   A3  B3   C3  D3  NaN
4  NaN  B2  NaN  D2   F2
5  NaN  B3  NaN  D3   F3
6  NaN  B6  NaN  D6   F6
7  NaN  B7  NaN  D7   F7

O mesmo parâmetro funciona no método append().

Concatenando séries com dataframes

Você pode concatenar séries com dataframes. O método concat() pode trabalhar com os dois tipos. Nesse exemplo, vamos criar uma série e concatená-la com um dataframe. Essa série será adicionada como uma coluna no final do dataframe.

>>> s1 = pd.Series(['X0', 'X1', 'X2', 'X3'], name='X')
>>> resultado = pd.concat([df1, s1], axis=1)
>>> resultado
    A   B   C   D   X
0  A0  B0  C0  D0  X0
1  A1  B1  C1  D1  X1
2  A2  B2  C2  D2  X2
3  A3  B3  C3  D3  X3

Se a série não tiver um nome, será atribuído uma sequencia de números.

>>> s2 = pd.Series(['_0', '_1', '_2', '_3'])
>>> resultado = pd.concat([df1, s2, s2, s2], axis=1)
>>> resultado
    A   B   C   D   0   1   2
0  A0  B0  C0  D0  _0  _0  _0
1  A1  B1  C1  D1  _1  _1  _1
2  A2  B2  C2  D2  _2  _2  _2
3  A3  B3  C3  D3  _3  _3  _3

Podemos usar o parâmetro ignore_index e definir os rótulos das colunas com uma sequencia numérica desde a primeira coluna.

>>> resultado = pd.concat([df1, s2, s2, s2], axis=1, ignore_index=True)
>>> resultado
    0   1   2   3   4   5   6
0  A0  B0  C0  D0  _0  _0  _0
1  A1  B1  C1  D1  _1  _1  _1
2  A2  B2  C2  D2  _2  _2  _2
3  A3  B3  C3  D3  _3  _3  _3

Concatenando com um grupo de keys

O padrão é o novo dataframe herdar os nomes das colunas dos dataframes pais. Podemos mudar isso com o parâmetro keys. O uso mais comum do parâmetro keys é exatamente esse: substituir o nome das colunas.

>>> pd.concat([s3, s4, s5], axis=1)
   um  dois  tres
0   0     0     1
1   1     1     4
2   2     1     1
3   3     3     4
>>> pd.concat([s3, s4, s5], axis=1, keys=['X', 'Y', 'Z'])
   X  Y  Z
0  0  0  1
1  1  1  4
2  2  1  1
3  3  3  4

Podemos fazer a mesma coisa com um dicionário.

>>> dicio = {'X':s3, 'Y':s4, 'Z':s5}
>>> resultado = pd.concat(dicio, axis=1)
>>> resultado
   X  Y  Z
0  0  0  1
1  1  1  4
2  2  1  1
3  3  3  4

Referência:
Função concat()
Função append()

Como usar a função groupby() do pandas

Photo by Duy Pham on Unsplash

Python é uma ótima linguagem para fazer análise de dados, principalmente por causa do fantástico ecossistema de pacotes python desenvolvidos para a análise de dados. pandas é um desses pacotes. Com ele podemos importar dados de um dataset e realizar algumas analises facilmente, como agrupar dados. O método groupby é muito utilizado para esse proposito.
O que o método groupby faz é separar os dados por grupos. Com os dados agrupados é comum aplicar uma função e combinar o resultado. Por exemplo, a velocidade de um falcão-peregrino vária de 370km/h à 390km/h e um papagaio de 24km/h à 26km/h. Com esses dados podemos usar o método groupby (para agrupar os dados) e o método mean (média) para saber qual é a velocidade média de cada ave.
Com os dados de cada ave, o método groupby vai agrupar os dados por categoria, no caso a categoria é o animal. Com esses dados agrupados podemos chamar o método mean(), que fornece a média dos valores. Desse modo temos um dataframe com a velocidade média de cada animal.

>>> import pandas as pd
>>> dados = {
... 'Animal': ['Falcao', 'Papagaio', 'Falcao', 'Papagaio'],
... 'Velocidade_maxima':[390, 24, 370, 26]
... }
>>> df = pd.DataFrame(dados)
>>> df
     Animal  Velocidade_maxima
0    Falcao                390
1  Papagaio                 24
2    Falcao                370
3  Papagaio                 26

>>> df.groupby(['Animal']).mean()
          Velocidade_maxima
Animal
Falcao                  380
Papagaio                 25

Quer aprender mais sobre a biblioteca pandas? Comece com nossos tutoriais pandas.

Referência:
Função groupby()
Função DataFrame()

Como usar o método fillna() do pandas

Photo by Brett Jordan on Unsplash

A primeira linguagem de programação que vem a mente, quando o assunto é analise de dados, é a linguagem python. Isso por que python fornece um ecossistema de pacotes para a análise de dados. pandas é um desses pacotes. Com ele podemos importar dados de um dataset e realizar algumas analises facilmente.
Um problema comum, quando importamos dados de um dataset, é elementos com valores NaN (sem valor). Esse valor pode causar problemas e erros na analise de dados, por isso pode ser interessante colocar um valor para esses elementos.
Nesse tutorial, vamos aprender a substituir valores NaN dos dataframes pandas utilizando o método fillna(). O método fillna() pode preencher todos os elementos vazios com um valor definido.
Para começar, vamos precisar de um dataframe com elementos vazios.

>>> import pandas as pd
>>> import numpy as np
>>> dados = {
... 'A':[np.nan, 4, 8, np.nan],
... 'B':[9, np.nan, 6, np.nan],
... 'C':[np.nan, 1, np.nan, 9],
... 'D':[np.nan, np.nan, 8, 3]
... }
>>> df = pd.DataFrame(dados)
>>> df
     A    B    C    D
0  NaN  9.0  NaN  NaN
1  4.0  NaN  1.0  NaN
2  8.0  6.0  NaN  8.0
3  NaN  NaN  9.0  3.0

O funcionamento do método fillna() é bem simples, só precisamos passar para o método qual é o valor que vai substituir o valor NaN. Assim o método vai procurar por todo o dataframe, e onde encontrar um elemento vazio, ele vai preencher esse elemento com o valor que recebeu.

>>> df.fillna(2)
     A    B    C    D
0  2.0  9.0  2.0  2.0
1  4.0  2.0  1.0  2.0
2  8.0  6.0  2.0  8.0
3  2.0  2.0  9.0  3.0

Também podemos utilizar os valores do próprio dataframe para preencher os elementos vazios. Por exemplo, se quiséssemos preencher o elemento vazio com o último valor não vazio, passaríamos o valor 'ffill' (forward fill) para o parâmetro method. Outra meio de preencher é com o próximo valor não vazio da sequência, nesse caso passamos o valor 'bfill' (back fill) para o parâmetro method.

>>> dados = [
... [None, 2, 6],
... [1, None, None],
... [None, 3, None]
... ]
>>> df = pd.DataFrame(dados)
>>> df
     0    1    2
0  NaN  2.0  6.0
1  1.0  NaN  NaN
2  NaN  3.0  NaN

>>> df.fillna(method='ffill')
     0    1    2
0  NaN  2.0  6.0
1  1.0  2.0  6.0
2  1.0  3.0  6.0

>>> df.fillna(method='bfill')
     0    1    2
0  1.0  2.0  6.0
1  1.0  3.0  NaN
2  NaN  3.0  NaN

Também podemos definir o valor que será usado para preencher cada coluna. Por exemplo, você pode definir que os elementos vazios da coluna A serão preenchidos com o valor 'um' e da coluna D com o valor 'dois'.

>>> replace = {'A':'um', 'D':'dois'}
>>> df.fillna(value=replace)
    A    B    C     D
0   1  NaN  5.0  dois
1  um  2.0  NaN     6
2   3  NaN  8.0  dois
3  um  4.0  NaN     9

Um parâmetro, que pode ser útil, é o limit. Com ele podemos definir quantos elementos vazios serão substituídos. Por exemplo, se você quiser que apenas um elementos de cada coluna seja substituído passe o valor 1 para o parâmetro limit.

>>> df.fillna(value=replace, limit=1)
     A    B    C     D
0    1  NaN  5.0  dois
1   um  2.0  NaN     6
2    3  NaN  8.0   NaN
3  NaN  4.0  NaN     9

Repare que apenas um elemento vazio de cada coluna foi substituído.
Quer aprender mais sobre a biblioteca pandas? Comece com nossos tutoriais pandas.

Referência:
Função fillna()

terça-feira, 11 de agosto de 2020

Seleção de subconjuntos de dados

Photo by Thanos Pal on Unsplash

Introdução

As dimensões de uma série ou dataframe tem seu rotulo no objeto index. O objeto index é usado para separar as estruturas do pandas. São os indexs que rotulam cada linha e coluna, com isso podemos selecionar os dados do dataframe. A biblioteca pandas também permite selecionar dados de acordo com a posição das colunas e linhas. Podendo selecionar dados por nome ou números (posição), a biblioteca pandas fornece uma sintaxe poderosa. O que acaba torna a seleção de subconjuntos um pouco confusa.
Já vimos exemplos de seleção de dados por rótulo e posição. A lista e o dicionário do python fazem isso. Esse é um dos motivos da biblioteca pandas ser poderosa. Juntando a capacidade de acessar dados por rótulo (dicionário) e posição (lista) temos um tipo de dado muito versátil.

Seleção de dados da série com pandas

As séries e os dataframes pandas funcionam como contêiner de dados. Esses contêineres têm métodos e atributos que nos permitem selecionar os dados de várias maneiras. Os métodos e atributos fazer operações com índices para selecionar os dados. Também podemos usar os atributos iloc e loc.
Podemos selecionar dados informando a posição ou um rótulo. Usando o atributo iloc selecionamos os dados por posição, fazendo um objeto do pandas parecer com uma lista. Já usando o atributo loc, selecionamos os dados informando um rótulo, como um dicionário do python.
Esses dois atributos estão presentes nas séries e nos dataframes. Nesse tutorial vamos aprender a selecionar dados utilizando rótulos e posições. Os dois atributos aceitam valores escalares e listas.
Colocando colchetes depois de uma variável estamos fazendo uma operação de índice. Não faz diferença se é uma seleção com rótulo ou posição, tudo é operação de índice.
Você obter o dataset usado nesse tutorial aqui.

Selecionando dados utilizando rótulo e posição

Vamos carregar o dataset na memoria e selecionar uma coluna usando uma operação de index. Nesse primeiro exemplo vamos usar o rótulo da coluna.

>>> import pandas as pd
>>> animelist = pd.read_csv(‘animelist.csv’)
>>> animelist['title']
0                                Inu x Boku SS
1                             Seto no Hanayome
2                           Shugo Chara!! Doki
3                                Princess Tutu
4                          Bakuman. 3rd Season
                         ...                  
14473               Gutchonpa Omoshiro Hanashi
14474                     Geba Geba Shou Time!
14475              Godzilla: Hoshi wo Kuu Mono
14476    Nippon Mukashibanashi: Sannen Netarou
14477               Senjou no Valkyria Special
Name: title, Length: 14478, dtype: object

Podemos ter o mesmo resultado com o atributo loc.

>>> animelist.loc[:, 'title']
0                                Inu x Boku SS
1                             Seto no Hanayome
2                           Shugo Chara!! Doki
3                                Princess Tutu
4                          Bakuman. 3rd Season
                         ...                  
14473               Gutchonpa Omoshiro Hanashi
14474                     Geba Geba Shou Time!
14475              Godzilla: Hoshi wo Kuu Mono
14476    Nippon Mukashibanashi: Sannen Netarou
14477               Senjou no Valkyria Special
Name: title, Length: 14478, dtype: object

Com o atributo loc podemos selecionar linhas e colunas passando o rótulo do índice. Se apenas um valor for passado o atributo vai retornar uma linha com os dados de cada coluna. Se passamos dois valores podemos selecionar as linhas e as colunas, e ainda podemos definir o espaçamento.

# selecionando uma linha
# passamos um número inteiro porque o índice é de inteiros e não strings
>>> animelist.loc[12]
anime_id                                                      11123
title                                          Sekaiichi Hatsukoi 2
title_english     Sekai Ichi Hatsukoi - World's Greatest Fi...
title_japanese                                              世界一初恋 2
title_synonyms    Sekai-ichi Hatsukoi 2, Sekai'ichi Hatsukoi 2
image_url         https://myanimelist.cdn-dena.com/images/anime/...
type                                                             TV
source                                                        Manga
episodes                                                         12
status                                              Finished Airing
airing                                                        False
aired_string                            Oct 8, 2011 to Dec 24, 2011
aired                    {'from': '2011-10-08', 'to': '2011-12-24'}
duration                                            24 min. per ep.
rating                                    PG-13 - Teens 13 or older
score                                                          8.23
scored_by                                                     53285
rank                                                            288
popularity                                                      945
members                                                       89543
favorites                                                       726
background        An event to show ep.1 of season 2 (along with ...
premiered                                                 Fall 2011
broadcast                                                   Unknown
related           {'Adaptation': [{'mal_id': 10309, 'type': 'man...
producer                   Lantis, Kadokawa Shoten, AT-X, KlockWorx
licensor                                                 Funimation
studio                                                  Studio Deen
genre                            Comedy, Drama, Romance, Shounen Ai
opening_theme     ['"Sekai no Hate ni Kimi ga Itemo" (世界の果てに君がいて...
ending_theme             ['"Aikotoba" (アイコトバ) by Sakura Merry-Men']
Name: 12, dtype: object

>>> animelist.loc[12:32, 'title':'rank']
                     title  ...    rank
12    Sekaiichi Hatsukoi 2  ...   288.0
13  Tonari no Kaibutsu-kun  ...  1093.0
14                  Bleach  ...   693.0
15                 Chobits  ...  1546.0
16          Kimi ni Todoke  ...   400.0
17      Naruto: Shippuuden  ...   337.0
18                 Ranma ½  ...   802.0
19               Toradora!  ...   174.0
20     Bakuman. 2nd Season  ...   108.0
21            Gakuen Alice  ...   941.0
22              Skip Beat!  ...   282.0
23           Chihayafuru 2  ...   116.0
24        Shounen Onmyouji  ...  1158.0
25             Chihayafuru  ...   246.0
26         Itazura na Kiss  ...  1108.0
27               Beelzebub  ...   528.0
28   Hanasakeru Seishounen  ...   753.0
29              SKET Dance  ...   213.0
30            B-gata H-kei  ...  3193.0
31        Crayon Shin-chan  ...  1032.0
32           Fruits Basket  ...   939.0

[21 rows x 17 columns]

No ultimo exemplo selecionamos linhas e colunas. Selecionamos os dados da linha numero doze até a linha trinta e dois. As colunas, selecionamos da coluna title até a coluna rank. O atributo iloc funciona do mesmo modo, a diferença é que esse atributo não aceita rótulos. O atributo iloc só aceita posições.

>>> animelist.iloc[12:32, 1:17]
                     title  ... scored_by
12    Sekaiichi Hatsukoi 2  ...     53285
13  Tonari no Kaibutsu-kun  ...    281448
14                  Bleach  ...    433097
15                 Chobits  ...    175388
16          Kimi ni Todoke  ...    212710
17      Naruto: Shippuuden  ...    385179
18                 Ranma ½  ...     59911
19               Toradora!  ...    557898
20     Bakuman. 2nd Season  ...    122090
21            Gakuen Alice  ...     33244
22              Skip Beat!  ...     90699
23           Chihayafuru 2  ...     62720
24        Shounen Onmyouji  ...     14619
25             Chihayafuru  ...     89081
26         Itazura na Kiss  ...     91187
27               Beelzebub  ...    136105
28   Hanasakeru Seishounen  ...     16772
29              SKET Dance  ...     44132
30            B-gata H-kei  ...    142827
31        Crayon Shin-chan  ...     17683

[20 rows x 16 columns]

Para selecionar, do primeiro elemento até um determinado, é só omitir a posição ou rótulo de inicio. Por exemplo: animelist.iloc[:32, 1:17]. Se você quiser definir o inicio e selecionar até o ultimo elemento é só omitir a posição ou rotulo do último elemento: animelist.loc[12:, ‘rank’:].

Referência:
Atributo loc
Atributo iloc