Manipulação de dados com Pandas![link image 138](/icons/link.svg)
Aviso: Este post foi traduzido para o português usando um modelo de tradução automática. Por favor, me avise se encontrar algum erro.
1. Resumo![link image 139](/icons/link.svg)
Vamos dar uma pequena introdução à biblioteca de manipulação e análise de dados Pandas
. Com ela, poderemos manipular e processar dados tabulares que nos ajudará a operar com eles e obter informações de maneira muito valiosa.
2. O que é o Pandas?![link image 140](/icons/link.svg)
Pandas é uma biblioteca de Python projetada para tornar o trabalho com dados relacionais ou rotulados fácil e intuitivo.
Pandas está projetado para muitos tipos diferentes de dados:
- Dados tabulares com colunas de tipos heterogêneos, como em uma tabela SQL ou uma planilha do Excel
- Dados de séries temporais ordenados e desordenados (não necessariamente de frequência fixa).
- Dados matriciais arbitrários (homogêneos ou heterogêneos) com rótulos de linha e coluna
- Qualquer outra forma de conjuntos de dados observacionais/estatísticos. Não é necessário rotular os dados em absoluto para colocá-los em uma estrutura de dados do Pandas.
As duas estruturas de dados principais do Pandas são as Serie
s (unidimensionais) e os DataFrame
s (bidimensionais). O Pandas é construído sobre o NumPy e é destinado a se integrar bem em um ambiente computacional científico com muitas outras bibliotecas de terceiros.
Para os cientistas de dados, o trabalho com dados geralmente se divide em várias etapas: coletar e limpar dados, analisá-los/modelá-los e, em seguida, organizar os resultados da análise de uma forma adequada para plotá-los ou exibi-los em formato de tabela. pandas é a ferramenta ideal para todas essas tarefas.
Outra característica é que o pandas é rápido, muitos dos algoritmos de baixo nível foram construídos em C
.
2.1. Pandas como pd
![link image 141](/icons/link.svg)
Geralmente na hora de importar pandas costuma-se importar com o alias de pd
import pandas as pdprint(pd.__version__)
1.0.1
3. Estruturas de dados do Pandas![link image 142](/icons/link.svg)
Em Pandas existem dois tipos de estruturas de dados: as Serie
s e os DataFrame
s
3.1. Séries![link image 143](/icons/link.svg)
O tipo de dado Serie
é uma matriz unidimensional rotulada capaz de conter qualquer tipo de dados (inteiros, strings, números de ponto flutuante, objetos Python, etc.). Ela é dividida em índices.
Para criar um tipo de dado Serie
a forma mais comum é
serie = pd.Series(data, index=index)
Onde data
pode ser:
- Um dicionário
- Uma lista ou tupla
- Um
ndarray
do Numpy - Um valor escalar
Como um dos tipos de dados pode ser um ndarray
do NumPy, importamos o NumPy para poder usá-lo
import numpy as np
3.1.1. Séries a partir de um dicionário![link image 144](/icons/link.svg)
diccionario = {"b": 1, "a": 0, "c": 2}serie = pd.Series(diccionario)serie
b 1a 0c 2dtype: int64
Se passar um índice, serão extraídos os valores dos dados correspondentes às tags do índice. Se não existirem, são criados como NaN
(not a number).
diccionario = {"b": 1, "a": 0, "c": 2}serie = pd.Series(diccionario, index=["b", "c", "d", "a"])serie
b 1.0c 2.0d NaNa 0.0dtype: float64
3.1.2. Séries a partir de uma lista ou tupla![link image 145](/icons/link.svg)
Se os dados vêm de uma lista ou tupla e nenhum índice é passado, um será criado com valores [0, ..., len(dados)-1]
serie = pd.Series([1, 2, 3, 4])serie
0 11 22 33 4dtype: int64
Se um índice for passado, ele deve ter o mesmo comprimento que os dados
serie = pd.Series([1, 2, 3, 4], index=["a", "b", "c", "d"])serie
a 1b 2c 3d 4dtype: int64
3.1.3. Séries a partir de um ndarray![link image 146](/icons/link.svg)
Se os dados vêm de um ndarray
e nenhum índice é passado, será criado um com valores [0, ..., len(data)-1]
.
serie = pd.Series(np.random.randn(5))serie
0 1.2678651 -0.8778572 -0.1385563 -0.1329874 -0.827295dtype: float64
Se um índice for passado, ele deve ter o mesmo comprimento que os dados
serie = pd.Series(np.random.randn(5), index=["a", "b", "c", "d", "e"])serie
a -1.091828b -0.584243c 0.220398d 1.248923e 1.652351dtype: float64
3.1.4. Séries a partir de um escalar![link image 147](/icons/link.svg)
Se a série for criada a partir de um escalar, ela será criada com um único item
serie = pd.Series(5.0)serie
0 5.0dtype: float64
Se quiser criar mais itens na série, é necessário passar o índice com o número de itens desejados, desta forma todos os itens terão o valor do escalar
serie = pd.Series(5.0, index=["a", "b", "c", "d", "e"])serie
a 5.0b 5.0c 5.0d 5.0e 5.0dtype: float64
3.1.5. Operações com Séries![link image 148](/icons/link.svg)
Assim como com o Numpy, podemos realizar operações com todos os elementos de uma série, sem ter que fazer uma iteração para cada um deles.
serie = pd.Series(5.0, index=["a", "b", "c", "d", "e"])print(f"serie:\n{serie}")print(f"\nserie + serie =\n{serie + serie}")
serie:a 5.0b 5.0c 5.0d 5.0e 5.0dtype: float64serie + serie =a 10.0b 10.0c 10.0d 10.0e 10.0dtype: float64
serie = pd.Series(5.0, index=["a", "b", "c", "d", "e"])print(f"serie:\n{serie}")print(f"\nexp(serie) =\n{np.exp(serie)}")
serie:a 5.0b 5.0c 5.0d 5.0e 5.0dtype: float64exp(serie) =a 148.413159b 148.413159c 148.413159d 148.413159e 148.413159dtype: float64
Uma diferença entre Serie
s e ndarrays é que as operações entre Serie
s alinham automaticamente os dados de acordo com suas etiquetas. Portanto, cálculos podem ser escritos sem considerar se as Serie
s envolvidas têm as mesmas etiquetas. Se uma etiqueta não for encontrada em uma Serie
ou outra, o resultado será marcado como faltante (NaN).
serie = pd.Series(5.0, index=["a", "b", "c", "d", "e"])print(f"serie:\n{serie}")print(f"\nserie[1:] + serie[:-1] =\n{serie[1:] + serie[:-1]}")
serie:a 5.0b 5.0c 5.0d 5.0e 5.0dtype: float64serie[1:] + serie[:-1] =a NaNb 10.0c 10.0d 10.0e NaNdtype: float64
3.1.6. Atributo nome das Séries![link image 149](/icons/link.svg)
Um dos atributos das Serie
s é name
, o qual corresponde ao nome que terão quando forem adicionadas a um DataFrame. No sentido contrário, quando se obtém uma série de um DataFrame, essa série terá como nome o que tinha no DataFrame.
serie = pd.Series(np.random.randn(5), name="aleatorio")serie
0 -0.1910091 -0.7931512 -0.9077473 -1.4405084 -0.676419Name: aleatorio, dtype: float64
Pode-se alterar o nome de uma série por meio do método rename()
serie = serie.rename("random")serie
0 -0.1910091 -0.7931512 -0.9077473 -1.4405084 -0.676419Name: random, dtype: float64
3.2. DataFrames![link image 150](/icons/link.svg)
Um DataFrame
é uma estrutura de dados rotulada e bidimensional, com colunas de tipos potencialmente diferentes, ou seja, em uma coluna pode haver dados do tipo inteiro, em outra coluna dados do tipo string, etc. Pode pensar nisso como uma planilha ou uma tabela SQL, ou um dicionário de objetos Serie
s.
É o objeto pandas mais utilizado. Assim como as Serie
s, os DataFrame
s aceitam muitos tipos diferentes de entrada:
Junto com os dados, opcionalmente você pode passar argumentos de índice (rótulos de linha) e colunas (rótulos de coluna). Se você passar um índice e/ou colunas, está garantindo o índice e/ou colunas do DataFrame
resultante. Portanto, um dicionário de Serie
s mais um índice específico descartará todos os dados que não coincidam com o índice passado
Se não forem passadas as etiquetas dos eixos, elas serão construídas a partir dos dados de entrada com base em regras de bom senso.
3.2.1. DataFrames a partir de um dicionário de Series![link image 151](/icons/link.svg)
Se um dicionário com Series
for passado, o DataFrame
será criado com tantas colunas quantas Series
o dicionário possuir.
diccionario = {
"uno": pd.Series([1.0, 2.0, 3.0]),
"dos": pd.Series([4.0, 5.0, 6.0, 7.0])
}
dataframe = pd.DataFrame(diccionario)
dataframe
Se cada uma das Serie
s tiver índices definidos, o DataFrame
resultante será a união desses índices.
diccionario = {
"uno": pd.Series([1.0, 2.0, 3.0], index=["a", "b", "c"]),
"dos": pd.Series([4.0, 5.0, 6.0, 7.0], index=["a", "b", "c", "d"])
}
dataframe = pd.DataFrame(diccionario)
dataframe
dataframe = pd.DataFrame(diccionario, index=["d", "b", "a"])
dataframe
Se as colunas forem passadas, elas aparecerão na ordem passada.
dataframe = pd.DataFrame(diccionario, columns=["dos", "tres"])
dataframe
3.2.2. DataFrames a partir de um dicionário de ndarrays ou listas![link image 152](/icons/link.svg)
Todos os ndarrays ou listas devem ter o mesmo comprimento. Se um índice for passado, também deve ter o mesmo comprimento que os ndarrays ou listas.
diccionario = {
"uno": [1.0, 2.0, 3.0, 4.0],
"dos": [4.0, 3.0, 2.0, 1.0]
}
dataframe = pd.DataFrame(diccionario)
dataframe
3.2.3. DataFrames a partir de uma matriz![link image 153](/icons/link.svg)
Se um índice for passado, ele deve ter o mesmo comprimento que o número de linhas da matriz e, se forem passadas as colunas, elas devem ter o mesmo comprimento que as colunas da matriz.
matriz = np.array([[1, 3], [2, 2], [3, 1]])
dataframe = pd.DataFrame(matriz, index=["a", "b", "c"], columns=["columna1", "columna2"])
dataframe
3.2.4. DataFrames a partir de uma lista de dicionários![link image 154](/icons/link.svg)
lista = [{"a": 1, "b": 2}, {"a": 5, "b": 10, "c": 20}]
dataframe = pd.DataFrame(lista)
dataframe
3.2.5. DataFrames a partir de um dicionário de tuplas![link image 155](/icons/link.svg)
diccionario = {
("a", "b"): {("A", "B"): 1, ("A", "C"): 2},
("a", "a"): {("A", "C"): 3, ("A", "B"): 4},
("a", "c"): {("A", "B"): 5, ("A", "C"): 6},
("b", "a"): {("A", "C"): 7, ("A", "B"): 8},
("b", "b"): {("A", "D"): 9, ("A", "B"): 10},
}
dataframe = pd.DataFrame(diccionario)
dataframe
3.2.6. DataFrames a partir de uma Série![link image 156](/icons/link.svg)
O resultado será um DataFrame
com o mesmo índice que a Série de entrada, e com uma coluna cujo nome é o nome original da Série (apenas se não for fornecido outro nome de coluna).
diccionario = {"b": 1, "a": 0, "c": 2}
serie = pd.Series(diccionario)
dataframe = pd.DataFrame(serie)
dataframe
4. Exploração de um DataFrame![link image 157](/icons/link.svg)
Quando um DataFrame
é muito grande, não pode ser representado inteiro
california_housing_train = pd.read_csv("https://raw.githubusercontent.com/maximofn/portafolio/main/posts/california_housing_train.csv")
california_housing_train
Portanto, é muito útil ter métodos para explorá-lo e obter informações de maneira rápida.
4.1. Cabeça do DataFrame![link image 158](/icons/link.svg)
Para ver as primeiras linhas e ter uma ideia de como é o DataFrame
existe o método head()
, que por padrão mostra as primeiras 5 linhas do DataFrame
. Se quiser ver um número diferente de linhas, introduzi-lo através do atributo n
california_housing_train.head(n=10)
4.2. Cauda do DataFrame![link image 159](/icons/link.svg)
Se o que se quer for visualizar as últimas linhas, pode-se usar o método tail()
, através do parâmetro n
escolhe-se quantas linhas exibir.
california_housing_train.tail()
4.3. Informação do DataFrame![link image 160](/icons/link.svg)
Outro método muito útil é info()
que nos dá informações sobre o DataFrame
california_housing_train.info()
<class 'pandas.core.frame.DataFrame'>RangeIndex: 17000 entries, 0 to 16999Data columns (total 9 columns):# Column Non-Null Count Dtype--- ------ -------------- -----0 longitude 17000 non-null float641 latitude 17000 non-null float642 housing_median_age 17000 non-null float643 total_rooms 17000 non-null float644 total_bedrooms 17000 non-null float645 population 17000 non-null float646 households 17000 non-null float647 median_income 17000 non-null float648 median_house_value 17000 non-null float64dtypes: float64(9)memory usage: 1.2 MB
4.4. Linhas e Colunas do DataFrame![link image 161](/icons/link.svg)
Os índices e as colunas de um DataFrame
podem ser obtidos através dos métodos index
e columns
diccionario = {"uno": pd.Series([1.0, 2.0, 3.0], index=["a", "b", "c"]),"dos": pd.Series([4.0, 5.0, 6.0, 7.0], index=["a", "b", "c", "d"])}dataframe = pd.DataFrame(diccionario)indices = dataframe.indexcolumnas = dataframe.columnsprint(f"El DataFrame tiene los índices\n {indices}\n")print(f"El DataFrame tiene las columnas\n {columnas}")
El DataFrame tiene los índicesIndex(['a', 'b', 'c', 'd'], dtype='object')El DataFrame tiene las columnasIndex(['uno', 'dos'], dtype='object')
4.5. Descrição do DataFrame![link image 162](/icons/link.svg)
O método describe()
mostra um resumo estatístico rápido dos dados do DataFrame
california_housing_train = pd.read_csv("https://raw.githubusercontent.com/maximofn/portafolio/main/posts/california_housing_train.csv")
california_housing_train.describe()
4.6. Ordenação do DataFrame
![link image 163](/icons/link.svg)
As linhas de um DataFrame
podem ser ordenadas alfabeticamente através do método sort_index()
.
california_housing_train = pd.read_csv("https://raw.githubusercontent.com/maximofn/portafolio/main/posts/california_housing_train.csv")
california_housing_train.sort_index().head()
Como neste caso as linhas já estavam ordenadas, definimos ascending=False
para que a ordem seja inversa.
california_housing_train.sort_index(ascending=False).head()
Se axis=1
deve ser inserido quando o objetivo é ordenar as colunas, pois por padrão é 0
.
california_housing_train.sort_index(axis=1).head()
Se quisermos ordenar o DataFrame
através de uma coluna específica, temos que usar o método sort_values()
e indicar a label da coluna pela qual queremos ordenar.
california_housing_train.sort_values('median_house_value')
4.7. Estatísticas do DataFrame![link image 164](/icons/link.svg)
Estatísticas do DataFrame
podem ser obtidas, como a média, a moda e o desvio padrão.
california_housing_train = pd.read_csv("https://raw.githubusercontent.com/maximofn/portafolio/main/posts/california_housing_train.csv")print(f"media:\n{california_housing_train.mean()}")print(f"\n\ndesviación estandar:\n{california_housing_train.std()}")
media:longitude -119.562108latitude 35.625225housing_median_age 28.589353total_rooms 2643.664412total_bedrooms 539.410824population 1429.573941households 501.221941median_income 3.883578median_house_value 207300.912353dtype: float64desviación estandar:longitude 2.005166latitude 2.137340housing_median_age 12.586937total_rooms 2179.947071total_bedrooms 421.499452population 1147.852959households 384.520841median_income 1.908157median_house_value 115983.764387dtype: float64
Se querem obter as estatísticas sobre as linhas e não sobre as colunas, é necessário indicá-lo através de axis=1
california_housing_train = pd.read_csv("https://raw.githubusercontent.com/maximofn/portafolio/main/posts/california_housing_train.csv")print(f"media:\n{california_housing_train.mean(axis=1)}")print(f"\n\ndesviación estandar:\n{california_housing_train.std(axis=1)}")
media:0 8357.5970671 10131.5277782 9664.6423223 8435.0290784 7567.436111...16995 12806.40856716996 9276.77087816997 12049.50792216998 10082.05330016999 10863.022744Length: 17000, dtype: float64desviación estandar:0 22026.6124451 26352.9392722 28514.3165883 24366.7547474 21730.014569...16995 36979.67689916996 26158.00677116997 34342.87679216998 28408.15232916999 31407.119788Length: 17000, dtype: float64
Outra coisa útil que se pode obter dos DataFrame
s é, por exemplo, o número de vezes que cada item de uma coluna se repete.
california_housing_train["total_rooms"].value_counts()
1582.0 161527.0 151717.0 141471.0 141703.0 14..157.0 12760.0 1458.0 110239.0 14068.0 1Name: total_rooms, Length: 5533, dtype: int64
Por exemplo, podemos ver que há um total de 16 casas com 1582 quartos.
4.8. Memória usada![link image 165](/icons/link.svg)
Podemos ver a memória que o DataFrame utiliza
california_housing_train.memory_usage(deep=True)
Index 128longitude 136000latitude 136000housing_median_age 136000total_rooms 136000total_bedrooms 136000population 136000households 136000median_income 136000median_house_value 136000dtype: int64
5. Adição de dados![link image 166](/icons/link.svg)
5.1. Adição de colunas![link image 167](/icons/link.svg)
Colunas podem ser adicionadas facilmente como operações de outras colunas
diccionario = {
"uno": pd.Series([1.0, 2.0, 3.0]),
"dos": pd.Series([4.0, 5.0, 6.0, 7.0])
}
dataframe = pd.DataFrame(diccionario)
dataframe["tres"] = dataframe["uno"] + dataframe["dos"]
dataframe["flag"] = dataframe["tres"] > 7.0
dataframe
Também é possível adicionar colunas indicando qual valor todos os seus itens terão
dataframe["constante"] = 8.0
dataframe
Se uma Serie
for adicionada e não tiver o mesmo número de índices que o DataFrame
, ela será ajustada ao número de índices do DataFrame
.
dataframe["Menos indices"] = dataframe["uno"][:2]
dataframe
Com os métodos anteriores a coluna era adicionada no final, mas se quiser adicionar a coluna em uma posição específica, pode-se utilizar o método insert()
.
Por exemplo, se quiser adicionar uma coluna na posição 3 (considerando que a contagem começa na posição 0), que o nome da coluna seja coluna inserida e que seu valor seja o dobro do da coluna tres, faria-se da seguinte maneira
dataframe.insert(loc=3, column="columna insertada", value=dataframe["tres"]*2)
dataframe
Se quiser adicionar mais de uma coluna por comando, pode-se usar o método assign()
dataframe = dataframe.assign(
columna_asignada1 = dataframe["uno"] * dataframe["tres"],
columna_asignada2 = dataframe["dos"] * dataframe["tres"],
)
dataframe
5.2. Adição de linhas![link image 168](/icons/link.svg)
diccionario = {
"uno": pd.Series([1.0, 2.0, 3.0]),
"dos": pd.Series([4.0, 5.0, 6.0, 7.0])
}
dataframe = pd.DataFrame(diccionario)
dataframe.head()
Podemos adicionar uma linha no final com o método concat
(que veremos com mais detalhes depois)
diccionario = {
"uno": [10.0],
"dos": [20.0]
}
dataframe = pd.concat([dataframe, pd.DataFrame(diccionario)])
dataframe
Vemos que a coluna foi adicionada no final, mas possui o índice zero, então reorganizamos os índices através do método reset_index(drop=True)
dataframe = dataframe.reset_index(drop=True)
dataframe
6. Eliminaçao de dados![link image 169](/icons/link.svg)
6.1. Eliminação de colunas![link image 170](/icons/link.svg)
Pode-se eliminar uma coluna específica utilizando o método pop()
dataframe.pop("constante")
dataframe
O mediante del
del dataframe["flag"]
dataframe
6.1. Eliminação de linhas![link image 171](/icons/link.svg)
diccionario = {
"uno": pd.Series([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]),
"dos": pd.Series([11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0]),
"tres": pd.Series([21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0])
}
dataframe = pd.DataFrame(diccionario)
dataframe.head()
Se quisermos remover uma linha, podemos usar o método drop
, especificando sua posição. Por exemplo, se quisermos remover a linha da posição 1
dataframe = dataframe.drop(1)
dataframe
Se quisermos eliminar a última linha
dataframe = dataframe.drop(len(dataframe)-1)
dataframe
Se quisermos remover um intervalo de linhas
dataframe = dataframe.drop(range(2, 5))
dataframe
Se quisermos remover um conjunto de linhas determinado
dataframe = dataframe.drop([5, 7, 9])
dataframe
Assim como quando adicionamos linhas, vemos que alguns índices foram removidos, então reorganizamos os índices usando o método reset_index(drop=True)
dataframe = dataframe.reset_index(drop=True)
dataframe
7. Operações sobre DataFrames![link image 172](/icons/link.svg)
Operações podem ser realizadas em DataFrame
s da mesma forma que podem ser feitas com Numpy.
diccionario = {
"uno": pd.Series([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]),
"dos": pd.Series([11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0]),
"tres": pd.Series([21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0])
}
dataframe = pd.DataFrame(diccionario)
dataframe.head()
dataframe[ ["uno", "dos", "tres"] ] * 2
np.exp(dataframe[ ["uno", "dos", "tres"] ])
Se quiser realizar operações mais complexas, pode-se usar o método apply()
.
dataframe = dataframe.apply(lambda x: x.max() - x.min())dataframe
uno 9.0dos 9.0tres 9.0dtype: float64
Foi aplicada uma função lambda
porque é uma função simples, mas em caso de querer aplicar funções mais complexas, podemos defini-las e aplicá-las.
def funcion(x):if x < 10:return np.exp(x) - np.log(5*x) + np.sqrt(x)elif x < 20:return np.sin(x) + np.cos(x) + np.tan(x)else:return np.log(x) + np.log10(x) + np.log2(x)dataframe = dataframe.apply(funcion)dataframe
uno 8102.277265dos 8102.277265tres 8102.277265dtype: float64
Utilizar o método apply
em um DataFrame é muito mais rápido que fazer um for
para cada uma das linhas e realizar a operação.
california_housing_train = pd.read_csv("https://raw.githubusercontent.com/maximofn/portafolio/main/posts/california_housing_train.csv")
california_housing_train.head()
Vamos a calcular o percentual de quartos em relação ao total de cômodos
california_housing_train["percent_bedrooms"] = None
%time california_housing_train["percent_bedrooms"] = california_housing_train.apply(lambda x: x["total_bedrooms"] / x["total_rooms"], axis=1)
california_housing_train.head()
california_housing_train["percent_bedrooms"] = None
%time for i in range(len(california_housing_train)): california_housing_train["percent_bedrooms"][i] = california_housing_train["total_bedrooms"][i] / california_housing_train["total_rooms"][i]
california_housing_train.head()
Com a função lambda
levou cerca de 300 ms, enquanto o loop for
levou mais de 1 segundo.
8. Transposta![link image 173](/icons/link.svg)
Pode-se fazer a transposta de um DataFrame
através do método T
diccionario = {
"uno": pd.Series([1.0, 2.0, 3.0], index=["fila a", "fila b", "fila c"]),
"dos": pd.Series([4.0, 5.0, 6.0], index=["fila a", "fila b", "fila c"])
}
dataframe = pd.DataFrame(diccionario)
dataframe["tres"] = dataframe["uno"] + dataframe["dos"]
dataframe["flag"] = dataframe["tres"] > 7.0
dataframe.T
9. Conversão para Numpy![link image 174](/icons/link.svg)
Se quiser converter uma Serie
ou DataFrame
para NumPy, pode-se usar o método to_numpy()
ou a função np.asarray()
.
diccionario = {
"uno": pd.Series([1.0, 2.0, 3.0], index=["fila a", "fila b", "fila c"]),
"dos": pd.Series([4.0, 5.0, 6.0], index=["fila a", "fila b", "fila c"])
}
dataframe = pd.DataFrame(diccionario)
dataframe["tres"] = dataframe["uno"] + dataframe["dos"]
dataframe["flag"] = dataframe["tres"] > 7.0
dataframe
matriz_np = dataframe.to_numpy()matriz_np
array([[1.0, 4.0, 5.0, False],[2.0, 5.0, 7.0, False],[3.0, 6.0, 9.0, True]], dtype=object)
matriz_np = np.asarray(dataframe)matriz_np
array([[1.0, 4.0, 5.0, False],[2.0, 5.0, 7.0, False],[3.0, 6.0, 9.0, True]], dtype=object)
Este exemplo não é o mais adequado, pois mistura números com booleanos, e como já explicamos no post anterior Cálculo matricial com NumPy, todos os elementos de um ndarray
devem ser do mesmo tipo.
Neste caso, estamos misturando números com booleanos, então para resolver isso, o NumPy os converte todos para objetos.
Para resolver isso, ficamos apenas com os números e os convertemos para um ndarray
.
matriz_np = dataframe[ ["uno", "dos", "tres"] ].to_numpy()matriz_np, matriz_np.dtype
(array([[1., 4., 5.],[2., 5., 7.],[3., 6., 9.]]), dtype('float64'))
Agora pode-se ver que foi criado um ndarray
onde todos os dados são do tipo float
.
10. Leitura de dados de fontes externas![link image 175](/icons/link.svg)
Uma das maiores forças do Pandas é poder ler dados de arquivos, portanto não é necessário criar um DataFrame
com os dados que se quer processar, mas sim ler esses dados de um arquivo.
Da mesma forma que é possível criar DataFrame
s a partir de arquivos externos, também é possível salvar DataFrame
s em arquivos, para assim criar o seu próprio conjunto de dados, configurá-lo da maneira que desejar e salvá-lo em um arquivo para poder usá-lo posteriormente.
Na tabela a seguir, são mostradas as funções para ler e escrever arquivos em diferentes formatos.
Formato | Tipo de arquivo | Função de leitura | Função de escrita |
---|---|---|---|
texto | CSV | read_csv | to_csv |
texto | Arquivo de texto de largura fixa | read_fwf | |
texto | JSON | read_json | to_json |
texto | HTML | read_html | to_html |
texto | Clipboard local | read_clipboard | to_clipboard |
binário | MS Excel | read_excel | to_excel |
binário | OpenDocument | read_excel | |
binário | Formato HDF5 | read_hdf | to_hdf |
binário | Formato Feather | read_feather | to_feather |
binário | Formato Parquet | read_parquet | to_parquet |
binário | Formato ORC | read_orc | |
binário | Msgpack | read_msgpack | to_msgpack |
binário | Stata | read_stata | to_stata |
binário | SAS | read_sas | |
binário | SPSS | read_spss | |
binário | Formato de Pickle do Python | read_pickle | to_pickle |
SQL | SQL | read_sql | to_sql |
SQL | Google BigQuery | read_gbq | to_gbq |
11. Indexação em DataFrames![link image 176](/icons/link.svg)
Há muitas maneiras de indexar em DataFrame
s.
fechas = pd.date_range('1/1/2000', periods=8)
dataframe = pd.DataFrame(np.random.randn(8, 4), index=fechas, columns=['A', 'B', 'C', 'D'])
dataframe
11.1. Indexação de colunas![link image 177](/icons/link.svg)
Para selecionar colunas dentro de um DataFrame
, podemos fazer isso selecionando a coluna entre colchetes []
, ou indicando a coluna como se fosse um atributo do DataFrame
.
dataframe['A']
2000-01-01 0.8131532000-01-02 -0.2445842000-01-03 0.1257292000-01-04 0.3522752000-01-05 -2.0509762000-01-06 -0.3122962000-01-07 0.8978372000-01-08 0.271403Freq: D, Name: A, dtype: float64
dataframe.A
2000-01-01 0.8131532000-01-02 -0.2445842000-01-03 0.1257292000-01-04 0.3522752000-01-05 -2.0509762000-01-06 -0.3122962000-01-07 0.8978372000-01-08 0.271403Freq: D, Name: A, dtype: float64
Se algumas linhas específicas forem desejadas, elas são passadas por meio de uma lista.
dataframe[ ['A', 'B'] ]
11.2. Indexação de linhas por posições![link image 178](/icons/link.svg)
Pode-se selecionar um intervalo de linhas de um DataFrame
da seguinte maneira
dataframe[0:3]
Se quiser selecionar apenas uma linha, é necessário indicar um intervalo de linhas que inclua apenas essa. Se, por exemplo, quiser selecionar a linha número 1
dataframe[1:2]
Outro método para selecionar uma linha pela sua posição é o método iloc[]
dataframe.iloc[0:3]
Se quisiser algumas linhas específicas, passa-se uma lista com suas posições.
dataframe.iloc[ [0, 2, 4] ]
11.3. Indexação de linhas por rótulos![link image 179](/icons/link.svg)
Para selecionar uma linha pelas suas etiquetas podemos usar o método loc[]
dataframe.loc['2000-01-01']
A 0.813153B -0.869356C 0.934293D 0.338644Name: 2000-01-01 00:00:00, dtype: float64
Se quiser selecionar um intervalo de linhas, podemos indexá-las usando os dois pontos :
dataframe.loc['2000-01-01':'2000-01-03']
Se querem algumas linhas específicas, elas são passadas por meio de uma lista.
dataframe.loc[ ['2000-01-01', '2000-01-03', '2000-01-05'] ]
11.4. Seleção de uma porção do DataFrame por posições![link image 180](/icons/link.svg)
dataframe.iloc[0:3, 0:2]
Se quisiser linhas e colunas específicas, passam-se listas com as posições desejadas.
dataframe.iloc[ [0, 2, 4], [0, 2] ]
11.5. Seleção de uma porção do DataFrame por meio de rótulos![link image 181](/icons/link.svg)
dataframe.loc['2000-01-01':'2000-01-03', 'A':'B']
Se querem algumas linhas e colunas específicas, passam-se listas com as etiquetas desejadas
dataframe.loc[ ['2000-01-01', '2000-01-03', '2000-01-05'], ['A', 'C'] ]
11.6. Indexação por função lambda![link image 182](/icons/link.svg)
Dados podem ser selecionados de um DataFrame
que atendam a uma condição fornecida por uma função lambda
dataframe.loc[lambda dataframe:2*dataframe['A']+5*np.exp(dataframe['B'])>0.2]
Como se pode ver, esta forma de indexação é muito poderosa
11.7. Indexação condicional![link image 183](/icons/link.svg)
Se não precisamos de funções complexas para indexar, mas apenas condicionais, podemos fazer
dataframe[dataframe['A']>0.2]
Podemos fazer múltiplas condições
dataframe[(dataframe['A']>0.2) & (dataframe['B']>0.2)]
11.8. Indexação aleatória![link image 184](/icons/link.svg)
Através do método sample()
obteremos uma linha aleatória do DataFrame
.
dataframe.sample()
Se quisermos mais de uma amostra, indicamos com o atributo n
dataframe.sample(n=3)
Se axis=1
for o que se quer são colunas aleatórias, deve-se indicar isso.
dataframe.sample(axis=1)
Se quiser um único item do DataFrame
, é necessário chamar o método sample()
duas vezes.
dataframe.sample(axis=1).sample()
12. Junção de DataFrames![link image 185](/icons/link.svg)
12.1. Concatenação de DataFrames![link image 186](/icons/link.svg)
Para concatenar vários DataFrame
s usamos o método concat()
, onde será passada uma lista com os DataFrame
s que se querem unir.
dataframe1 = pd.DataFrame({"A": ["A0", "A1", "A2", "A3"],"B": ["B0", "B1", "B2", "B3"],"C": ["C0", "C1", "C2", "C3"],"D": ["D0", "D1", "D2", "D3"],})dataframe2 = pd.DataFrame({"A": ["A4", "A5", "A6", "A7"],"B": ["B4", "B5", "B6", "B7"],"C": ["C4", "C5", "C6", "C7"],"D": ["D4", "D5", "D6", "D7"],})dataframe3 = pd.DataFrame({"A": ["A8", "A9", "A10", "A11"],"B": ["B8", "B9", "B10", "B11"],"C": ["C8", "C9", "C10", "C11"],"D": ["D8", "D9", "D10", "D11"],})dataframe = pd.concat([dataframe1, dataframe2, dataframe3])print(f"dataframe1:\n{dataframe1}")print(f"dataframe2:\n{dataframe2}")print(f"dataframe3:\n{dataframe3}")print(f"\ndataframe:\n{dataframe}")
dataframe1:A B C D0 A0 B0 C0 D01 A1 B1 C1 D12 A2 B2 C2 D23 A3 B3 C3 D3dataframe2:A B C D0 A4 B4 C4 D41 A5 B5 C5 D52 A6 B6 C6 D63 A7 B7 C7 D7dataframe3:A B C D0 A8 B8 C8 D81 A9 B9 C9 D92 A10 B10 C10 D103 A11 B11 C11 D11dataframe:A B C D0 A0 B0 C0 D01 A1 B1 C1 D12 A2 B2 C2 D23 A3 B3 C3 D30 A4 B4 C4 D41 A5 B5 C5 D52 A6 B6 C6 D63 A7 B7 C7 D70 A8 B8 C8 D81 A9 B9 C9 D92 A10 B10 C10 D103 A11 B11 C11 D11
Como pode ser visto, os índices 0
, 1
, 2
e 3
se repetem, porque cada dataframe possui esses índices. Para evitar isso, é necessário usar o parâmetro ignore_index=True
dataframe = pd.concat([dataframe1, dataframe2, dataframe3], ignore_index=True)print(f"dataframe1:\n{dataframe1}")print(f"dataframe2:\n{dataframe2}")print(f"dataframe3:\n{dataframe3}")print(f"\ndataframe:\n{dataframe}")
dataframe1:A B C D0 A0 B0 C0 D01 A1 B1 C1 D12 A2 B2 C2 D23 A3 B3 C3 D3dataframe2:A B C D0 A4 B4 C4 D41 A5 B5 C5 D52 A6 B6 C6 D63 A7 B7 C7 D7dataframe3:A B C D0 A8 B8 C8 D81 A9 B9 C9 D92 A10 B10 C10 D103 A11 B11 C11 D11dataframe:A B C D0 A0 B0 C0 D01 A1 B1 C1 D12 A2 B2 C2 D23 A3 B3 C3 D34 A4 B4 C4 D45 A5 B5 C5 D56 A6 B6 C6 D67 A7 B7 C7 D78 A8 B8 C8 D89 A9 B9 C9 D910 A10 B10 C10 D1011 A11 B11 C11 D11
Se axis=1
tivesse sido utilizado, a concatenação teria ocorrido ao longo das colunas.
dataframe = pd.concat([dataframe1, dataframe2, dataframe3], axis=1)print(f"dataframe1:\n{dataframe1}")print(f"dataframe2:\n{dataframe2}")print(f"dataframe3:\n{dataframe3}")print(f"\ndataframe:\n{dataframe}")
dataframe1:A B C D0 A0 B0 C0 D01 A1 B1 C1 D12 A2 B2 C2 D23 A3 B3 C3 D3dataframe2:A B C D0 A4 B4 C4 D41 A5 B5 C5 D52 A6 B6 C6 D63 A7 B7 C7 D7dataframe3:A B C D0 A8 B8 C8 D81 A9 B9 C9 D92 A10 B10 C10 D103 A11 B11 C11 D11dataframe:A B C D A B C D A B C D0 A0 B0 C0 D0 A4 B4 C4 D4 A8 B8 C8 D81 A1 B1 C1 D1 A5 B5 C5 D5 A9 B9 C9 D92 A2 B2 C2 D2 A6 B6 C6 D6 A10 B10 C10 D103 A3 B3 C3 D3 A7 B7 C7 D7 A11 B11 C11 D11
12.1.1. Interseção de concatenação![link image 187](/icons/link.svg)
Há duas maneiras de fazer a concatenação, pegando todos os índices dos DataFrame
s ou pegando apenas os que coincidem. Isso é determinado pela variável join
, que aceita os valores 'outer'
(padrão) (pega todos os índices) ou 'inner'
(apenas os que coincidem).
Vamos ver um exemplo de 'outer'
dataframe1 = pd.DataFrame({"A": ["A0", "A1", "A2", "A3"],"B": ["B0", "B1", "B2", "B3"],"C": ["C0", "C1", "C2", "C3"],"D": ["D0", "D1", "D2", "D3"],},index=[0, 1, 2, 3])dataframe4 = pd.DataFrame({"B": ["B2", "B3", "B6", "B7"],"D": ["D2", "D3", "D6", "D7"],"F": ["F2", "F3", "F6", "F7"],},index=[2, 3, 6, 7])dataframe = pd.concat([dataframe1, dataframe4], axis=1)print(f"dataframe1:\n{dataframe1}")print(f"dataframe2:\n{dataframe4}")print(f"\ndataframe:\n{dataframe}")
dataframe1:A B C D0 A0 B0 C0 D01 A1 B1 C1 D12 A2 B2 C2 D23 A3 B3 C3 D3dataframe2:B D F2 B2 D2 F23 B3 D3 F36 B6 D6 F67 B7 D7 F7dataframe:A B C D B D F0 A0 B0 C0 D0 NaN NaN NaN1 A1 B1 C1 D1 NaN NaN NaN2 A2 B2 C2 D2 B2 D2 F23 A3 B3 C3 D3 B3 D3 F36 NaN NaN NaN NaN B6 D6 F67 NaN NaN NaN NaN B7 D7 F7
Vamos ver um exemplo de 'inner'
dataframe = pd.concat([dataframe1, dataframe4], axis=1, join="inner")print(f"dataframe1:\n{dataframe1}")print(f"dataframe2:\n{dataframe4}")print(f"\ndataframe:\n{dataframe}")
dataframe1:A B C D0 A0 B0 C0 D01 A1 B1 C1 D12 A2 B2 C2 D23 A3 B3 C3 D3dataframe2:B D F2 B2 D2 F23 B3 D3 F36 B6 D6 F67 B7 D7 F7dataframe:A B C D B D F2 A2 B2 C2 D2 B2 D2 F23 A3 B3 C3 D3 B3 D3 F3
12.2. Merge
de DataFrames![link image 188](/icons/link.svg)
Antes criamos um novo dataframe com a união de vários dataframes, agora podemos completar um dataframe com outro, para isso usamos merge
, passando o parâmetro on
, sobre qual coluna queremos que seja feito o merge
.
dataframe1 = pd.DataFrame({"Key": ["K0", "K1", "K2", "K3"],"A": ["A0", "A1", "A2", "A3"],"B": ["B0", "B1", "B2", "B3"],})dataframe2 = pd.DataFrame({"Key": ["K0", "K1", "K2", "K3"],"C": ["C0", "C1", "C2", "C3"],"D": ["D0", "D1", "D2", "D3"],})dataframe = dataframe1.merge(dataframe2, on="Key")print(f"dataframe1:\n{dataframe1}")print(f"dataframe2:\n{dataframe2}")print(f"\ndataframe:\n{dataframe}")
dataframe1:Key A B0 K0 A0 B01 K1 A1 B12 K2 A2 B23 K3 A3 B3dataframe2:Key C D0 K0 C0 D01 K1 C1 D12 K2 C2 D23 K3 C3 D3dataframe:Key A B C D0 K0 A0 B0 C0 D01 K1 A1 B1 C1 D12 K2 A2 B2 C2 D23 K3 A3 B3 C3 D3
Neste caso, os dois dataframes tinham uma chave com o mesmo nome (Key
), mas no caso de termos dataframes em que suas chaves tenham nomes diferentes, podemos usar os parâmetros left_on
e right_on
.
dataframe1 = pd.DataFrame({"Key1": ["K0", "K1", "K2", "K3"],"A": ["A0", "A1", "A2", "A3"],"B": ["B0", "B1", "B2", "B3"],})dataframe2 = pd.DataFrame({"Key2": ["K0", "K1", "K2", "K3"],"C": ["C0", "C1", "C2", "C3"],"D": ["D0", "D1", "D2", "D3"],})dataframe = dataframe1.merge(dataframe2, left_on="Key1", right_on="Key2")print(f"dataframe1:\n{dataframe1}")print(f"dataframe2:\n{dataframe2}")print(f"\ndataframe:\n{dataframe}")
dataframe1:Key1 A B0 K0 A0 B01 K1 A1 B12 K2 A2 B23 K3 A3 B3dataframe2:Key2 C D0 K0 C0 D01 K1 C1 D12 K2 C2 D23 K3 C3 D3dataframe:Key1 A B Key2 C D0 K0 A0 B0 K0 C0 D01 K1 A1 B1 K1 C1 D12 K2 A2 B2 K2 C2 D23 K3 A3 B3 K3 C3 D3
No caso de uma das chaves não corresponder, o merge
não será realizado sobre essa chave.
dataframe1 = pd.DataFrame({"Key1": ["K0", "K1", "K2", "K3"],"A": ["A0", "A1", "A2", "A3"],"B": ["B0", "B1", "B2", "B3"],})dataframe2 = pd.DataFrame({"Key2": ["K0", "K1", "K2", np.nan],"C": ["C0", "C1", "C2", "C3"],"D": ["D0", "D1", "D2", "D3"],})dataframe = dataframe1.merge(dataframe2, left_on="Key1", right_on="Key2")print(f"dataframe1:\n{dataframe1}")print(f"dataframe2:\n{dataframe2}")print(f"\ndataframe:\n{dataframe}")
dataframe1:Key1 A B0 K0 A0 B01 K1 A1 B12 K2 A2 B23 K3 A3 B3dataframe2:Key2 C D0 K0 C0 D01 K1 C1 D12 K2 C2 D23 NaN C3 D3dataframe:Key1 A B Key2 C D0 K0 A0 B0 K0 C0 D01 K1 A1 B1 K1 C1 D12 K2 A2 B2 K2 C2 D2
Para mudar esse comportamento,我们可以使用参数 how
,其默认值为 inner
,但我们可以传递 left
、right
和 outer
值。
(Note: The part after "我们可以使用参数" is in Chinese. I assume it's a mistake and should be in Portuguese as requested. Here is the corrected version.)
Para mudar esse comportamento, podemos usar o parâmetro how
, que por padrão tem o valor inner
, mas podemos passar os valores left
, right
e outer
.
dataframe1 = pd.DataFrame({"Key1": ["K0", "K1", "K2", "K3"],"A": ["A0", "A1", "A2", "A3"],"B": ["B0", "B1", "B2", "B3"],})dataframe2 = pd.DataFrame({"Key2": ["K0", "K1", "K2", np.nan],"C": ["C0", "C1", "C2", "C3"],"D": ["D0", "D1", "D2", "D3"],})dataframe_inner = dataframe1.merge(dataframe2, left_on="Key1", right_on="Key2", how="inner")dataframe_left = dataframe1.merge(dataframe2, left_on="Key1", right_on="Key2", how="left")dataframe_right = dataframe1.merge(dataframe2, left_on="Key1", right_on="Key2", how="right")dataframe_outer = dataframe1.merge(dataframe2, left_on="Key1", right_on="Key2", how="outer")print(f"dataframe1:\n{dataframe1}")print(f"dataframe2:\n{dataframe2}")print(f"\ndataframe inner:\n{dataframe_inner}")print(f"\ndataframe left:\n{dataframe_left}")print(f"\ndataframe right:\n{dataframe_right}")print(f"\ndataframe outer:\n{dataframe_outer}")
dataframe1:Key1 A B0 K0 A0 B01 K1 A1 B12 K2 A2 B23 K3 A3 B3dataframe2:Key2 C D0 K0 C0 D01 K1 C1 D12 K2 C2 D23 NaN C3 D3dataframe inner:Key1 A B Key2 C D0 K0 A0 B0 K0 C0 D01 K1 A1 B1 K1 C1 D12 K2 A2 B2 K2 C2 D2dataframe left:Key1 A B Key2 C D0 K0 A0 B0 K0 C0 D01 K1 A1 B1 K1 C1 D12 K2 A2 B2 K2 C2 D23 K3 A3 B3 NaN NaN NaNdataframe right:Key1 A B Key2 C D0 K0 A0 B0 K0 C0 D01 K1 A1 B1 K1 C1 D12 K2 A2 B2 K2 C2 D23 NaN NaN NaN NaN C3 D3dataframe outer:Key1 A B Key2 C D0 K0 A0 B0 K0 C0 D01 K1 A1 B1 K1 C1 D12 K2 A2 B2 K2 C2 D23 K3 A3 B3 NaN NaN NaN4 NaN NaN NaN NaN C3 D3
Como pode ser visto, quando se escolhe left
são adicionados apenas os valores do dataframe da esquerda e quando se escolhe right
, os valores do dataframe da direita.
12.3. Join
de dataframes![link image 189](/icons/link.svg)
A última ferramenta de junção de dataframes é join
. É semelhante a merge
, apenas em vez de procurar similaridades com base em colunas especificadas, ela as procura com base nos índices.
dataframe1 = pd.DataFrame({"A": ["A0", "A1", "A2", "A3"],"B": ["B0", "B1", "B2", "B3"],},index=["K0", "K1", "K2", "K3"])dataframe2 = pd.DataFrame({"C": ["C0", "C1", "C2", "C3"],"D": ["D0", "D1", "D2", "D3"],},index=["K0", "K1", "K2", "K3"])dataframe = dataframe1.join(dataframe2)print(f"dataframe1:\n{dataframe1}")print(f"dataframe2:\n{dataframe2}")print(f"\ndataframe:\n{dataframe}")
dataframe1:A BK0 A0 B0K1 A1 B1K2 A2 B2K3 A3 B3dataframe2:C DK0 C0 D0K1 C1 D1K2 C2 D2K3 C3 D3dataframe:A B C DK0 A0 B0 C0 D0K1 A1 B1 C1 D1K2 A2 B2 C2 D2K3 A3 B3 C3 D3
Neste caso, os índices são iguais, mas quando são diferentes podemos especificar a maneira de unir os dataframes através do parâmetro how
, que por padrão tem o valor inner
, mas pode ter o valor left
, right
ou outer
.
dataframe1 = pd.DataFrame({"A": ["A0", "A1", "A2", "A3"],"B": ["B0", "B1", "B2", "B3"],},index=["K0", "K1", "K2", "K3"])dataframe2 = pd.DataFrame({"C": ["C0", "C2", "C3", "C4"],"D": ["D0", "D2", "D3", "D4"],},index=["K0", "K2", "K3", "K4"])dataframe_inner = dataframe1.join(dataframe2, how="inner")dataframe_left = dataframe1.join(dataframe2, how="left")dataframe_right = dataframe1.join(dataframe2, how="right")dataframe_outer = dataframe1.join(dataframe2, how="outer")print(f"dataframe1:\n{dataframe1}")print(f"dataframe2:\n{dataframe2}")print(f"\ndataframe inner:\n{dataframe_inner}")print(f"\ndataframe left:\n{dataframe_left}")print(f"\ndataframe rigth:\n{dataframe_right}")print(f"\ndataframe outer:\n{dataframe_outer}")
dataframe1:A BK0 A0 B0K1 A1 B1K2 A2 B2K3 A3 B3dataframe2:C DK0 C0 D0K2 C2 D2K3 C3 D3K4 C4 D4dataframe:A B C DK0 A0 B0 C0 D0K2 A2 B2 C2 D2K3 A3 B3 C3 D3dataframe:A B C DK0 A0 B0 C0 D0K1 A1 B1 NaN NaNK2 A2 B2 C2 D2K3 A3 B3 C3 D3dataframe:A B C DK0 A0 B0 C0 D0K2 A2 B2 C2 D2K3 A3 B3 C3 D3K4 NaN NaN C4 D4dataframe:A B C DK0 A0 B0 C0 D0K1 A1 B1 NaN NaNK2 A2 B2 C2 D2K3 A3 B3 C3 D3K4 NaN NaN C4 D4
13. Dados faltantes (NaN
)![link image 190](/icons/link.svg)
Em um DataFrame
podem haver alguns dados faltantes, o Pandas os representa como np.nan
diccionario = {
"uno": pd.Series([1.0, 2.0, 3.0]),
"dos": pd.Series([4.0, 5.0, 6.0, 7.0])
}
dataframe = pd.DataFrame(diccionario)
dataframe
13.1. Eliminação das linhas com dados faltantes![link image 191](/icons/link.svg)
Para não ter linhas com dados faltantes, essas podem ser eliminadas.
dataframe.dropna(how="any")
13.2. Eliminação das colunas com dados faltantes![link image 192](/icons/link.svg)
dataframe.dropna(axis=1, how='any')
13.3. Máscara booleana com as posições faltantes![link image 193](/icons/link.svg)
pd.isna(dataframe)
13.4. Preenchimento dos dados ausentes![link image 194](/icons/link.svg)
dataframe.fillna(value=5.5, inplace=True)
dataframe
Dica: Colocando a variável
inplace=True
modifica oDataFrame
sobre o qual está sendo operado, assim não é necessário escreverdataframe = dataframe.fillna(value=5.5)
14. Séries Temporais![link image 195](/icons/link.svg)
Pandas oferece a possibilidade de trabalhar com séries temporais. Por exemplo, criamos uma Serie
de 100 dados aleatórios a cada segundo a partir de 01/01/2021
indices = pd.date_range("1/1/2021", periods=100, freq="S")datos = np.random.randint(0, 500, len(indices))serie_temporal = pd.Series(datos, index=indices)serie_temporal
2021-01-01 00:00:00 2412021-01-01 00:00:01 142021-01-01 00:00:02 1902021-01-01 00:00:03 4072021-01-01 00:00:04 94...2021-01-01 00:01:35 2752021-01-01 00:01:36 562021-01-01 00:01:37 4482021-01-01 00:01:38 1512021-01-01 00:01:39 316Freq: S, Length: 100, dtype: int64
Esta funcionalidade do Pandas é muito poderosa, por exemplo, podemos ter um conjunto de dados em certas horas de um fuso horário e alterá-las para outro fuso.
horas = pd.date_range("3/6/2021 00:00", periods=10, freq="H")datos = np.random.randn(len(horas))serie_horaria = pd.Series(datos, horas)serie_horaria
2021-03-06 00:00:00 -0.8535242021-03-06 01:00:00 -1.3553722021-03-06 02:00:00 -1.2675032021-03-06 03:00:00 -1.1557872021-03-06 04:00:00 0.7309352021-03-06 05:00:00 1.4359572021-03-06 06:00:00 0.4609122021-03-06 07:00:00 0.7234512021-03-06 08:00:00 -0.8533372021-03-06 09:00:00 0.456359Freq: H, dtype: float64
Localizamos os dados em um fuso horário
serie_horaria_utc = serie_horaria.tz_localize("UTC")serie_horaria_utc
2021-03-06 00:00:00+00:00 -0.8535242021-03-06 01:00:00+00:00 -1.3553722021-03-06 02:00:00+00:00 -1.2675032021-03-06 03:00:00+00:00 -1.1557872021-03-06 04:00:00+00:00 0.7309352021-03-06 05:00:00+00:00 1.4359572021-03-06 06:00:00+00:00 0.4609122021-03-06 07:00:00+00:00 0.7234512021-03-06 08:00:00+00:00 -0.8533372021-03-06 09:00:00+00:00 0.456359Freq: H, dtype: float64
E agora podemos alterá-las para outro uso
serie_horaria_US = serie_horaria_utc.tz_convert("US/Eastern")serie_horaria_US
2021-03-05 19:00:00-05:00 -0.8535242021-03-05 20:00:00-05:00 -1.3553722021-03-05 21:00:00-05:00 -1.2675032021-03-05 22:00:00-05:00 -1.1557872021-03-05 23:00:00-05:00 0.7309352021-03-06 00:00:00-05:00 1.4359572021-03-06 01:00:00-05:00 0.4609122021-03-06 02:00:00-05:00 0.7234512021-03-06 03:00:00-05:00 -0.8533372021-03-06 04:00:00-05:00 0.456359Freq: H, dtype: float64
15. Dados categóricos![link image 196](/icons/link.svg)
Pandas oferece a possibilidade de adicionar dados categóricos em um DataFrame
. Suponha o seguinte DataFrame
dataframe = pd.DataFrame(
{"id": [1, 2, 3, 4, 5, 6], "raw_grade": ["a", "b", "b", "a", "a", "e"]}
)
dataframe
Podemos converter os dados da coluna raw_grade
para dados categóricos através do método astype()
dataframe['grade'] = dataframe["raw_grade"].astype("category")
dataframe
As colunas raw_grade
e grade
parecem iguais, mas se olharmos as informações do DataFrame
, podemos ver que não é assim.
dataframe.info()
<class 'pandas.core.frame.DataFrame'>RangeIndex: 6 entries, 0 to 5Data columns (total 3 columns):# Column Non-Null Count Dtype--- ------ -------------- -----0 id 6 non-null int641 raw_grade 6 non-null object2 grade 6 non-null categorydtypes: category(1), int64(1), object(1)memory usage: 334.0+ bytes
Pode-se ver que a coluna grade
é do tipo categórico
Podemos ver as categorias dos tipos de dados categóricos através do método cat.categories()
dataframe["grade"].cat.categories
Index(['a', 'b', 'e'], dtype='object')
Também podemos renomear as categorias com o mesmo método, mas introduzindo uma lista com as novas categorias.
dataframe["grade"].cat.categories = ["very good", "good", "very bad"]
dataframe
Pandas nos dá a possibilidade de codificar numericamente os dados categóricos através do método get_dummies
pd.get_dummies(dataframe["grade"])
16. Groupby![link image 197](/icons/link.svg)
Podemos agrupar os dataframes pelos valores de alguma das colunas. Vamos recarregar o dataframe com o valor das casas da Califórnia.
california_housing_train = pd.read_csv("https://raw.githubusercontent.com/maximofn/portafolio/main/posts/california_housing_train.csv")
california_housing_train.head()
Agora podemos agrupar os dados por alguma das colunas, por exemplo, agrupemos as casas em função do número de anos e vejamos quantas casas há de cada idade com count
california_housing_train.groupby("housing_median_age").count().head()
Como vemos em todas as colunas, obtemos o mesmo valor, que é o número de casas que há com uma determinada idade, mas podemos saber a média do valor de cada coluna com mean
california_housing_train.groupby("housing_median_age").mean().head()
Podemos obter várias medidas de cada idade através do comando agg
(agregação), passando-lhe as medidas que queremos por meio de uma lista, por exemplo, vejamos o mínimo, o máximo e a média de cada coluna para cada idade de cada
california_housing_train.groupby("housing_median_age").agg(['min', 'max', 'mean']).head()
Podemos especificar sobre quais colunas queremos realizar certos cálculos através da passagem de um dicionário, onde as chaves serão as colunas sobre as quais queremos realizar cálculos e os valores serão listas com os cálculos.
california_housing_train.groupby("housing_median_age").agg({'total_rooms': ['min', 'max', 'mean'], 'total_bedrooms': ['min', 'max', 'mean', 'median']}).head()
Podemos agrupar por mais de uma coluna, para isso, é necessário passar as colunas em uma lista
california_housing_train.groupby(["housing_median_age", "total_bedrooms"]).mean()
17. Gráficos![link image 198](/icons/link.svg)
Pandas oferece a possibilidade de representar os dados dos nossos DataFrame
s em gráficos para poder obter uma melhor representação deles. Para isso, utiliza a biblioteca matplotlib
, que veremos no próximo post.
17.1. Gráfico básico![link image 199](/icons/link.svg)
Para representar os dados em um gráfico, a maneira mais fácil é usar o método plot()
serie = pd.Series(np.random.randn(1000), index=pd.date_range("1/1/2000", periods=1000))
serie = serie.cumsum()
serie.plot()
No caso de ter um DataFrame
, o método plot()
representará cada uma das colunas do DataFrame
dataframe = pd.DataFrame(
np.random.randn(1000, 4), index=ts.index, columns=["A", "B", "C", "D"]
)
dataframe = dataframe.cumsum()
dataframe.plot()
17.2. Diagrama de barras verticais![link image 200](/icons/link.svg)
Há mais métodos para criar gráficos, como o gráfico de barras vertical através de plot.bar()
dataframe = pd.DataFrame(np.random.rand(10, 4), columns=["a", "b", "c", "d"])
dataframe.plot.bar()
Se quisermos empilhar as barras, indicamos isso através da variável stacked=True
dataframe.plot.bar(stacked=True)
17.3. Diagrama de barras horizontal![link image 201](/icons/link.svg)
Para criar um diagrama de barras horizontal usamos plot.barh()
dataframe.plot.barh()
Se quisermos empilhar as barras, indicamos isso através da variável stacked=True
dataframe.plot.barh(stacked=True)
17.4. Histograma![link image 202](/icons/link.svg)
Para criar um histograma usamos plot.hist()
dataframe = pd.DataFrame(
{
"a": np.random.randn(1000) + 1,
"b": np.random.randn(1000),
"c": np.random.randn(1000) - 1,
}
)
dataframe.plot.hist(alpha=0.5)
Se quisermos empilhar as barras, indicamos isso através da variável stacked=True
dataframe.plot.hist(alpha=0.5, stacked=True)
Se quisermos adicionar mais colunas, ou seja, se quisermos que o histograma seja mais informativo ou preciso, indicamos isso através da variável bins
dataframe.plot.hist(alpha=0.5, stacked=True, bins=20)
17.5. Diagramas de Velas![link image 203](/icons/link.svg)
Para criar um diagrama de velas usamos plot.box()
dataframe = pd.DataFrame(np.random.rand(10, 5), columns=["A", "B", "C", "D", "E"])
dataframe.plot.box()
17.6. Gráficos de áreas![link image 204](/icons/link.svg)
Para criar um gráfico de áreas usamos plot.area()
dataframe.plot.area()
17.7. Diagrama de dispersão![link image 205](/icons/link.svg)
Para criar um diagrama de dispersão usamos plot.scatter()
, onde é necessário indicar as variáveis x
e y
do diagrama
dataframe.plot.scatter(x='A', y='B')
17.8. Gráfico de contêiner hexagonal![link image 206](/icons/link.svg)
Para criar um gráfico de contêiner hexagonal usamos plot.hexbin()
, onde é necessário indicar as variáveis x
e y
do diagrama e o tamanho da malha por meio de gridsize
dataframe = pd.DataFrame(np.random.randn(1000, 2), columns=["a", "b"])
dataframe["b"] = dataframe["b"] + np.arange(1000)
dataframe.plot.hexbin(x="a", y="b", gridsize=25)