sexta-feira, 7 de agosto de 2020

Arquivos ZIP com pandas

Imagem de Alexas_Fotos por Pixabay

Já vimos nos tutoriais passados, que os arquivos csv são muito comuns para a criação de datasets. A principal característica dos arquivos csv é que eles são texto puro, sem formatação. Por isso eles podem ficar com um tamanho muito grande. Para tentar resolver esse problema os arquivos csv podem ser compactados. Nesse tutorial vamos aprender a carregar um arquivo csv compactado num arquivo ZIP.
O arquivo csv que vamos utilizar é o único arquivo dentro do arquivo ZIP. Você pode conseguir um arquivo semelhante compactando o arquivo filmes.csv. Nesse tutorial também vamos trabalhar com arquivos ZIP, com vários arquivos csv compactados.
Os arquivos que vamos usar nesse tutorial podem ser baixados gratuitamente aqui.

Como ler arquivos csv compactados

Vamos começar lendo um único arquivo csv compactado. Podemos fazer isso com o método read_csv(). A diferença é a extensão do arquivo que será zip e não csv.

>>> import pandas as pd
>>> animelist = pd.read_csv('AnimeList.zip')
>>> animelist
       anime_id  ...                                       ending_theme
0         11013  ...  ['#1: "Nirvana" by MUCC (eps 1, 11-12)', '#2: ...
1          2104  ...  ['#1: "Ashita e no Hikari (?????)" by Asuka Hi...
2          5262  ...  ['#1: "Rottara Rottara (???? ????)" by Buono! ...
3           721  ...  ['"Watashi No Ai Wa Chiisaikeredo" by Ritsuko ...
4         12365  ...  ['#1: "Pride on Everyday" by Sphere (eps 1-13)...
...         ...  ...                                                ...
14473     26089  ...                                                 []
14474     21525  ...                                                 []
14475     37897  ...                                                 []
14476     34193  ...                                                 []
14477     37908  ...                                                 []

[14478 rows x 31 columns]

Com arquivos compactados, contendo mais de um arquivo csv, a leitura desse arquivo é um pouco mais complicada, comparado com o exemplo anterior. Utilizando o método read_csv() não podemos especificar qual arquivo queremos ler dentro de um arquivo ZIP, mas podemos utilizar o módulo zipfile, que é uma biblioteca padrão do Python, para fazer isso.
Nesse exemplo vamos utilizar um arquivo zip contento mais de um arquivo csv. Você pode usar qualquer arquivo zip contendo arquivos csv.

>>> import pandas as pd
>>> import zipfile
>>> arq_zip = zipfile.ZipFile('dataset.zip')
>>> print('\n'.join(arq_zip.namelist()))
filmes.csv
anime_cleaned.csv
anime_filtered.csv
AnimeList.csv
>>> animeslist = pd.read_csv(arq_zip.open('AnimeList.csv'))
>>> animeslist
       anime_id  ...                                       ending_theme
0         11013  ...  ['#1: "Nirvana" by MUCC (eps 1, 11-12)', '#2: ...
1          2104  ...  ['#1: "Ashita e no Hikari (?????)" by Asuka Hi...
2          5262  ...  ['#1: "Rottara Rottara (???? ????)" by Buono! ...
3           721  ...  ['"Watashi No Ai Wa Chiisaikeredo" by Ritsuko ...
4         12365  ...  ['#1: "Pride on Everyday" by Sphere (eps 1-13)...
...         ...  ...                                                ...
14473     26089  ...                                                 []
14474     21525  ...                                                 []
14475     37897  ...                                                 []
14476     34193  ...                                                 []
14477     37908  ...                                                 []

[14478 rows x 31 columns]

Você pode trabalhar com arquivos compactados do tipo GZIP, XZ e BZ2. O método read_csv() aceita esses tipos de compressão.

Referência:
Método read_csv()
Método ZipFile()

Como ler e criar arquivos do Excel com pandas

Imagem de Esa Riutta por Pixabay

O arquivo CSV é muito comum e utilizado, mas se compararmos esse arquivo com o gigante da Microsoft, o arquivo do Excel, não parece ser grande coisa. Em muitas pesquisas de consultoria, os resultados apontam que o Excel é uma das ferramentas mais críticas em muitas empresas. O Excel é muito utilizado nas empresas para a tomada de muitas decisões importantes.
E por isso a biblioteca pandas fornece métodos para poder manipular esses arquivos. Nesse tutorial vamos aprender como criar e ler arquivos do Excel com a biblioteca pandas.
Antes de continuarmos vamos precisar instalar os pacotes xlwt e openpyxl. Esses pacotes são necessários para podermos exportar o nosso dataframe para um arquivo xls e xlsx. Utilize o pip para instalar os dois pacotes: pip install openpyxl xlwt.

Como ler e criar arquivos do Excel com pandas

O método que vamos utilizar, para criar um arquivo do excel, é o to_excel(). O que precisamos fazer é criar um dataframe e chamar esse método. Veja um exemplo:

>>> import pandas as pd
>>> nome = {'nome':['Fabiana', 'Diana', 'Amanda'],
... 'u_nome':['Ferreira', 'Lima', 'Saturno']}
>>> dataframe = pd.DataFrame(nome)
>>> dataframe.to_excel('dataframe.xls')
>>> dataframe.to_excel('dataframe.xlsx')

Abrindo o arquivo, que acabamos de criar, o resultado deve ser igual a este:

Para ler o arquivo que criamos, e qualquer outro feito no Excel, utilizamos o método read_excel(). Esse método precisa do complemento xlrd. Para baixo use o pip: pip install xlrd.

>>> import pandas as pd
>>> dataframe = pd.read_excel('dataframe.xls')
>>> dataframe
   Unnamed: 0     nome    u_nome
0           0  Fabiana  Ferreira
1           1    Diana      Lima
2           2   Amanda   Saturno

Como o arquivo já tem uma coluna de índice, podemos especificar isso para o método read_excel(), para evitar dados duplicados. Assim não teremos duas colunas de índice.

>>> dataframe = pd.read_excel('dataframe.xlsx', index_col=0)
>>> dataframe
      nome    u_nome
0  Fabiana  Ferreira
1    Diana      Lima
2   Amanda   Saturno

Com esses exemplos aprendemos que podemos ler e criar arquivos do Excel com a biblioteca pandas. Com a instalação de poucos pacotes já podemos manipular o tipo de arquivo mais utilizados pelas empresas.

Referência:
Método DataFrame()
Método to_excel()
Método read_excel()

quinta-feira, 6 de agosto de 2020

Lendo arquivo csv enorme com pandas

Imagem de Tania Dimas por Pixabay

A biblioteca pandas precisa que o computador tenha memoria disponível suficiente para poder funcionar corretamente. Todos os dataframes são alocados na memoria antes de podermos fazer qualquer operação com esses dados. Se você precisar ler os dados de um dataset muito grande, a biblioteca pandas fornece algumas opções. Caso o seu arquivo possa ser processado em partes, você pode ler algumas partes e depois processa-las. Se no seu dispositivo tiver memoria suficiente você pode carregar o arquivo inteiro. Podemos usar algumas dicas para diminuir o tamanho do arquivo.
O recomendado é que o seu computador tenha de três a dez vezes a quantidade de memoria do arquivo que você está trabalhando. Essa memoria extra é usada para manipular esses dados.

Como ler arquivo csv muito grande

Nesse tutorial vamos ler o conjunto o dados filmes.csv. Esse dataset cabe na memória de qualquer computador da atualidade, mas para fins didáticos vamos fazer de conta que não existe memória suficiente. E quando tentamos carregar esse dataset na memória recebemos um erro de falta de memória.
Quando lidamos com arquivos grandes que nossos computadores não tenham memória suficiente precisamos definir o total de memória que o arquivo inteiro vai ocupar. Para essa tarefa vamos usar o parâmetro nrows. Com esse parâmetro definimos a quantidade de linhas que serão carregados na memória.

>>> import pandas as pd
>>> filmes = pd.read_csv('filmes.csv', nrows=1000)
>>> filmes
     indice  codigo_obra  ...     cnpj_requerente data_exibicao
0         0      15639.0  ...  00.568.159/0001-07     06/jul/12
1         1          NaN  ...  03.599.148/0001-82     13/jul/04
2         2      26453.0  ...  02.341.697/0001-90    26/09/2007
3         3          NaN  ...  27.654.722/0001-16    16/12/2002
4         4       4806.0  ...  00.979.601/0001-98     15/jan/03
..      ...          ...  ...                 ...           ...
995     995   18001845.0  ...  00.979.601/0001-98    09/05/2018
996     996   17004586.0  ...  03.599.148/0001-82     19/jul/18
997     997   18002435.0  ...  27.654.722/0001-16     08/jun/18
998     998   17005733.0  ...  06.236.625/0001-33     05/jun/18
999     999   18002628.0  ...  08.346.733/0001-94     04/jul/18

[1000 rows x 9 columns]

Uma coisa importante é saber o quanto de memória um dataframe esta utilizando, e para isso temos o método info(). Esse método fornece algumas informações sobre o dataframe, incluindo a quantidade de memória utilizada.

>>> filmes.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 9 columns):
 #   Column                   Non-Null Count  Dtype
---  ------                   --------------  -----
 0   indice                   1000 non-null   int64
 1   codigo_obra              997 non-null    float64
 2   titulo_original          1000 non-null   object
 3   titulo_brasil            1000 non-null   object
 4   ano_producao             999 non-null    float64
 5   diretor                  1000 non-null   object
 6   razao_social_requerente  1000 non-null   object
 7   cnpj_requerente          1000 non-null   object
 8   data_exibicao            1000 non-null   object
dtypes: float64(2), int64(1), object(6)
memory usage: 46.9+ KB

Além das linhas podemos definir quais colunas queremos carregar na memória com o parâmetro usecols.

>>> col = [
... 'diretor',
... 'titulo_original'
... ]
>>> filmes = pd.read_csv('filmes.csv', nrows=1000, usecols=col)
>>> filmes.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 2 columns):
 #   Column           Non-Null Count  Dtype
---  ------           --------------  -----
 0   titulo_original  1000 non-null   object
 1   diretor          1000 non-null   object
dtypes: object(2)
memory usage: 7.9+ KB

Selecionando linhas e colunas, conseguimos reduzir o tamanho do dataframe. Com isso podemos reduzir o tamanho de qualquer dataframe.

Referência:
Método read_csv()
Método info()

Criando arquivo csv com pandas

Photo by Maksym Kaharlytskyi on Unsplash

Na internet podemos achar vários arquivos csv. Cada um com tipos deferentes de dados. Esses arquivos têm coisas boas e coisas ruins. A coisa boa é que eles são facilmente lidos por nos humanos, podem ser abertos com um editor de texto simples e podem ser acessados pela maioria dos editores de planilhas. O lado negativo dos arquivos csv é a falta de um padrão para o arquivo. Tem arquivos csv que utilizam vírgula como separador, outros usam ponto e vírgula. Não é possível impor o tipo de dado. Esse tipo de coisa pode tornar a criação desse arquivo complicada.
Nesse tutorial vamos aprender como criar um arquivo csv a partir de um dataframe pandas.
Os dataframes pandas têm métodos que começam com "to_". Os métodos que começam assim são métodos de exportação. Usaremos o método to_csv(). Com ele é possível descarregar um dataframe pandas num arquivo csv.

Como criar um arquivo csv com pandas

Para criar um arquivo csv primeiro precisamos de um dataframe. Nesse exemplo vamos criar um dataframe e depois salvar esse dataframe no HD como um arquivo csv.

>>> import pandas as pd
>>> nome = ['Maria', 'João', 'Daniel', 'Paulo']
>>> idade = [36, 38, 24, 66]
>>> dados = {
... 'nome':nome,
... 'idade':idade
... }
>>> pessoas = pd.DataFrame(dados)
>>> type(pessoas)
<class 'pandas.core.frame.DataFrame'>
>>> pessoas
     nome  idade
0   Maria     36
1    João     38
2  Daniel     24
3   Paulo     66

>>> pessoas.to_csv('pessoas.csv')

Com esse código criamos um dataframe com três colunas, as duas que criamos (nome e idade) e a de índice que é adicionada pelo pandas. Depois salvamos esse dataframe no arquivo pessoas.csv.
Agora com o arquivo criado podemos abri-lo com o método read_csv().

>>> pessoas = pd.read_csv('pessoas.csv')
>>> pessoas
   Unnamed: 0    nome  idade
0           0   Maria     36
1           1    João     38
2           2  Daniel     24
3           3   Paulo     66

Podemos notar que quando salvamos o arquivo com o método to_csv() foi adicionado uma coluna de índice na primeira linha, mas sem nome. E quando abrimos esse arquivo com o método read_csv() é adicionado outra coluna de índice no inicio. Assim ficamos com duas colunas de índice, uma com nome e outra sem (unnamed). Para resolvermos esse problema usamos o parâmetro index_col do método read_csv().

>>> pessoas = pd.read_csv('pessoas.csv', index_col=0)
>>> pessoas
     nome  idade
0   Maria     36
1    João     38
2  Daniel     24
3   Paulo     66

Uma alternativa, para resolver o mesmo problema, é fazer uso do parâmetro index do método to_csv(). Se passarmos o valor False o arquivo não terá um índice.

>>> pessoas = pd.DataFrame(dados)
>>> pessoas.to_csv('pessoas.csv', index=False)
>>> pessoas = pd.read_csv('pessoas.csv')
>>> pessoas
     nome  idade
0   Maria     36
1    João     38
2  Daniel     24
3   Paulo     66

Referência:
Método DataFrame()
Método to_csv()
Método read_csv()

Criando dataframes com pandas

Photo by La-Rel Easter on Unsplash

Podemos criar um dataframe de diversas maneiras e utilizar vários programas pra isso. Nesse tutorial vamos aprender a criar um dataframe com a biblioteca pandas e utilizando a linguagem de programação python.
É comum criar um dataframe a partir de um arquivo existente, ou de um banco de dados. Nos exemplos anteriores sempre criamos o dataframe a partir do arquivo filmes.csv. Nesse tutorial vamos criar um dataframe do zero, sem arquivos pré-existentes ou bancos de dados. Vamos criar um dataframe a partir de algumas listas.

Criando um dataframe pandas

Primeiro vamos criar listas com quatro elementos cada. Essas listas vão ser convertidas em colunas do dataframe, por isso é importante que os elementos das listas sejam homogêneos.

>>> import pandas as pd
>>> nome = ['Bruna', 'Heverton', 'Gelvani', 'Milena']
>>> u_nome = ['Oliveira', 'Ferreira', 'Silva', 'Reis']
>>> nascimento = [1989, 1997, 1988, 1999]

Depois vamos criar um dicionário com os nomes das colunas do dataframe. As chaves (keys) do dicionário serão os nomes das colunas no dataframe.

>>> pessoas = {'nome':nome, 'u_nome':u_nome, 'nascimento':nascimento}

Por fim, criamos o dataframe passando o dicionário pessoa para o método DataFrame().

>>> type(m_dataframe)
<class 'pandas.core.frame.DataFrame>
>>> m_dataframe
       nome    u_nome  nascimento
0     Bruna  Oliveira        1989
1  Heverton  Ferreira        1997
2   Gelvani     Silva        1988
3    Milena      Reis        1999

Nesse exemplo, os elementos das listas foram convertidos em elementos das colunas do nosso dataframe. E as chaves do dicionário pessoas dão nome às colunas do dataframe.
O padrão, quando criamos um dataframe, é o index ser numerado começando do número zero. Podemos mudar isso com o parâmetro index.

>>> m_dataframe = pd.DataFrame(pessoas, index=['a', 'b', 'c', 'd'])
>>> m_dataframe
       nome    u_nome  nascimento
a     Bruna  Oliveira        1989
b  Heverton  Ferreira        1997
c   Gelvani     Silva        1988
d    Milena      Reis        1999

Criando dataframes pandas com dicionários

Também podemos criar um dataframe a partir de uma lista de dicionários.

>>> pd.DataFrame(
... [
... {
... "nome": "Bruna",
... "u_nome": "Oliveira",
... "nascimento": 1989,
... },
... {
... "nome": "Heverton",
... "u_nome": "Ferreira",
... "nascimento": 1997,
... },
... {
... "nome": "Gelvani",
... "u_nome": "Silva",
... "nascimento": 1988,
... },
... {
... "nome": "Milena",
... "u_nome": "Reis",
... "nascimento": 1999,
... },
... ]
... )
       nome    u_nome  nascimento
0     Bruna  Oliveira        1989
1  Heverton  Ferreira        1997
2   Gelvani     Silva        1988
3    Milena      Reis        1999

Nesse exemplo, a ordem das colunas é a mesma das chaves do dicionário. Podemos mudar essa ordem com o parâmetro columns.

>>> pd.DataFrame(
... [
... {
... "nome": "Bruna",
... "u_nome": "Oliveira",
... "nascimento": 1989,
... },
... {
... "nome": "Heverton",
... "u_nome": "Ferreira",
... "nascimento": 1997,
... },
... {
... "nome": "Gelvani",
... "u_nome": "Silva",
... "nascimento": 1988,
... },
... {
... "nome": "Milena",
... "u_nome": "Reis",
... "nascimento": 1999,
... },
... ],
... columns=['nascimento', 'u_nome', 'nome']
... )
   nascimento    u_nome      nome
0        1989  Oliveira     Bruna
1        1997  Ferreira  Heverton
2        1988     Silva   Gelvani
3        1999      Reis    Milena

Mudamos a ordem das colunas passando uma lista com os nomes. A ordem das colunas segue a ordem da lista passada para o parâmetro columns.

Referência:
Método DataFrame()

Inverter a direção de uma operação

Photo by Brendan Church on Unsplash

É comum que alguns métodos dos dataframes pandas tenham o parâmetro eixo. Com esse parâmetro é possível alterar o sentido da operação. Podemos definir o sentido em que a operação deve ocorrer. Os valores passados ao parâmetro podem se 'index' (ou 0) ou 'columns' (ou 1). É muito comum ver o parâmetro de eixo recebendo valores em strings. Isso acontece porque é mais intuitivo. É mais fácil de perceber que a string 'columns' se refere a colunas do que perceber que o número um se refere à mesma coisa.
O valor padrão, da grande maioria dos parâmetros eixo, é o zero (ou 'index'). Por isso o padrão das operações é ir da primeira linha até a última. Nesse tutorial vamos aprender como mudar a direção das operações.

Como inverter a direção de uma operação no dataframe pandas

Vamos começar com um método que já vimos antes, o count(). Esse método conta os elementos não vazios. Por padrão o sentida da operação é o eixo 'index''. Para mudar o sentido da operação usamos o parâmetro axis (eixo).

>>> import pandas as pd
>>> filmes = pd.read_csv('filmes.csv')
>>> filmes.count()
indice                     9262
codigo_obra                9259
titulo_original            9262
titulo_brasil              9262
ano_producao               9259
diretor                    9262
razao_social_requerente    9262
cnpj_requerente            9262
data_exibicao              9262
dtype: int64

>>> filmes.count(axis='columns')
0       9
1       8
2       9
3       8
4       9
       ..
9257    9
9258    9
9259    9
9260    9
9261    9
Length: 9262, dtype: int64

Na primeira chamada, ao método count(), recebemos uma série com o número de elementos não vazios de cada coluna. Isso acontece porque o eixo padrão do método count() é o index. Assim o método count() vai em cada coluna e conta quantos elementos essa coluna tem. Na segunda chamada mudamos o eixo para ‘colunas’. Desse modo o método vai a cada linha e conta quantas colunas não vazias essa linha tem.

Referência:
Método count()
Método read_csv()

quarta-feira, 5 de agosto de 2020

Comparando valores ausentes no dataframe pandas

Photo by Ayesh Rathnayake on Unsplash

Os valores ausentes num dataframe pandas são representados com um objeto da biblioteca NumPy NaN (np.nan). Esse objeto é bastante curioso. Por exemplo, o objeto não é igual a ele mesmo. Para comparação o objeto None é igual a ele mesmo, mas não um objeto np.nan. No exemplo abaixo vamos fazer um pequeno teste e comparar os dois objetos com eles mesmos. O objeto np.nan vai retornar False e o None vai retornar True.

>>> import pandas as pd
>>> import numpy as np
>>> np.nan == np.nan
False

>>> None == None
True

Todos os operadores de comparação vão retornar False com exceção de um: o de diferente.

>>> np.nan > np.nan
False
>>> np.nan < np.nan
False
>>> np.nan != np.nan
True

Com esses exemplos percebemos que o objeto np.nan é um objeto singular. Essa propriedade é muito utilizada na biblioteca pandas.
Para verificar se dataframes e séries pandas são iguais é utilizado o operador ==. Esse operador realiza a operação em cada elemento do dataframe ou série. Como resultado dessa operação temos um objeto com as mesmas dimensões dos objetos pais. Nesse tutorial vamos utilizar o operador de igual (==). Muita gente acha que o operador igual e o método equals() fazem a mesma coisa, mas o operador faz coisa diferentes do método equals().

Como comparar valores ausentes do dataframe pandas

Vamos começar com um exemplo para termos uma ideia de como o operador igual funciona. Vamos comparar cada elemento do dataframe com um valor.

>>> import pandas as pd
>>> filmes = pd.read_csv(‘filmes.csv’)
>>> cod_obra = filmes.select_dtypes(include='number')
>>> cod_obra == 7603
      indice  codigo_obra  ano_producao
0      False        False         False
1      False         True         False
2      False        False         False
3      False        False         False
4      False        False         False
...      ...          ...           ...
9257   False        False         False
9258   False        False         False
9259   False        False         False
9260   False        False         False
9261   False        False         False

[9262 rows x 3 columns]

Nesse exemplo, apenas um elemento tem o valor igual a 7603. Por isso apenas uma operação retornou True. É assim que o operador igual funciona, realiza uma operação para cada elemento do dataframe.
Nota: para os próximos exemplos vamos precisar de um dataframe que tenha valores ausentes. Por isso abra o dataset filmes.csv, num editor de texto, e apague os primeiros valores da coluna codigo_obra (é só apagar o valor entre as vírgulas).
Para o próximo exemplo vamos comparar o dataframe com ele mesmo. O esperado é que todos os resultados sejam True, mas não é bem isso que acontece.

>>> filmes == filmes
      indice  codigo_obra  ...  cnpj_requerente  data_exibicao
0       True         True  ...             True           True
1       True        False  ...             True           True
2       True         True  ...             True           True
3       True        False  ...             True           True
4       True         True  ...             True           True
...      ...          ...  ...              ...            ...
9257    True         True  ...             True           True
9258    True         True  ...             True           True
9259    True         True  ...             True           True
9260    True         True  ...             True           True
9261    True         True  ...             True           True

[9262 rows x 9 columns]

Podemos ver que, contrariando as nossas expectativas, recebemos alguns valores False. Isso acontece por causa dos objetos np.nan da biblioteca NumPy. Como vimos acima np.nan é diferente de np.nan. Como a biblioteca pandas faz uso desse objeto, para representar objetos vazios, qualquer dataframe que tenha um elemento vazio será diferente dele mesmo. E como saber se um dataframe é igual a outro? Com o método equals().

>>> filmes.equals(filmes)
True

O método equals() retorna True se os dataframes forem iguais.
Esse é o jeito certo de verificar se dois dataframes são iguais. Utilizando o operador igual, se tiver algum elemento vazio, eles não serão iguais. Com o método equals() isso não acontece.