Você está na página 1de 300

Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [76]: d
Fora[76]:
01
0 ah
1 bb
2 <NA>c
3 dd

Em [77]: s.str.cat(d, na_rep="-")


Fora[77]:
0 aaa
bbb
1 CC
2 3 ddd

dtype: string

Concatenando uma Série e um objeto indexado em uma Série, com alinhamento

Para concatenação com Série ou DataFrame, é possível alinhar os índices antes da concatenação definindo o
palavra-chave de junção.

Em [78]: u = pd.Series(["b", "d", "a", "c"], índice=[1, 3, 0, 2], dtype="string")

Em [79]: s
Fora[79]:
0 a
1 b
2 c
3 d
dtype: string

Em [80]: você
Fora[80]:
1 b
3 d
0 a
c
2 dtype: string

Em [81]: s.str.cat(u)
Fora[81]:
0 ah
bb
1 CC
2 3 dd

dtype: string

Em [82]: s.str.cat(u, join="esquerda")


Fora[82]:
0 ah
(continua na próxima página)

2.9. Trabalhando com dados de texto 587


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

1 bb
2 CC
3 dd
dtype: string

Aviso: Se a palavra-chave join não for passada, o método cat() retornará ao comportamento anterior
versão 0.23.0 (ou seja, sem alinhamento), mas um FutureWarning será gerado se algum dos índices envolvidos for diferente, uma vez que
este padrão será alterado para join='left' em uma versão futura.

As opções usuais estão disponíveis para junção (uma entre 'esquerda', 'externa', 'interna', 'direita'). Em particular, o alinhamento
também significa que os diferentes comprimentos não precisam mais coincidir.

Em [83]: v = pd.Series(["z", " a", "b", "d", "e"], índice=[-1, 0, 1, 3, 4], dtype= "corda")

Em [84]: s
Fora[84]:
0 a
1 b
2 c
3d
dtype: string

Em [85]: v
Fora[85]:
-1 z
0 a
1 b
3 d
4 e
dtype: string

Em [86]: s.str.cat(v, join="left", na_rep="-")


Fora[86]:
0 ah
bb
1 c-

2 3 dd

dtype: string

Em [87]: s.str.cat(v, join="outer", na_rep="-")


Fora[87]:
-1 -z
0 ah
1 bb
2 c-

3 dd
4 -e
dtype: string

O mesmo alinhamento pode ser usado quando outro for um DataFrame:

588 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [88]: f = d.loc[[3, 2, 1, 0], :]

Em [89]: s
Fora[89]:
0 a
1 b
2 c
3 d
dtype: string

Em [90]: f
Fora[90]:
01
3 dd
2 <NA>c
1bb
0 ah

Em [91]: s.str.cat(f, join="left", na_rep="-")


Fora[91]:
0 aaa
1 bbb
2 CC
3 ddd
dtype: string

Concatenando uma série e muitos objetos em uma série

Vários itens semelhantes a array (especificamente: série, índice e variantes unidimensionais de np.ndarray) podem ser combinados
em um contêiner semelhante a uma lista (incluindo iteradores, visualizações de ditados, etc.).

Em [92]: s
Fora[92]:
0 a
1 b
2 c
3 d
dtype: string

Em [93]: você
Fora[93]:
1 b
3 d
0 a
2 c
dtype: string

Em [94]: s.str.cat([u, u.to_numpy()], join="esquerda")


Fora[94]:
0 aab
1 bd
2 cca
(continua na próxima página)

2.9. Trabalhando com dados de texto 589


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


ddc
3 dtype: string

Todos os elementos sem um índice (por exemplo, np.ndarray) dentro da lista passada devem corresponder em comprimento à série de chamada
(ou Índice), mas Série e Índice podem ter comprimento arbitrário (desde que o alinhamento não esteja desabilitado com join=None):

Em [95]: v
Fora[95]:
-1 z
0 a
b
1 d
34 e
dtype: string

Em [96]: s.str.cat([v, u, u.to_numpy()], join="outer", na_rep="-")


Fora[96]:
-1 -z--
0 aaab
1 bbbd
2 c-ca
3 dddc
4 -e--
dtype: string

Se estiver usando join='right' em uma lista de outras que contém índices diferentes, a união desses índices será usada
como base para a concatenação final:

Em [97]: u.loc[[3]]
Fora[97]:
3d
dtype: string

Em [98]: v.loc[[-1, 0]]


Fora[98]:
-1 z
0 a
dtype: string

Em [99]: s.str.cat([u.loc[[3]], v.loc[[-1, 0]]], join="right", na_rep="-")


Fora[99]:
3 dd-
-1 --z
0 ah

dtype: string

590 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.9.5 Indexação com .str

Você pode usar a notação [] para indexar diretamente por locais de posição. Se você indexar além do final da string, o resultado será
seja um NaN.

Em [100]: s = pd.Series(
.....: ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "cachorro", "gato"], dtype=
ÿÿ"string"
..... :)
.....:

Em [101]: s.str[0]
Fora[101]:
0 A
1 B
2 C
3 A
4 B
5 <NA>
6 C
7 d
c
8 dtype: string

Em [102]: s.str[1]
Fora[102]:
0 <NA>
1 <NA>
2 <NA>
3 a
4 a
5 <NA>
6 A
7 ó
8 a
dtype: string

2.9.6 Extraindo substrings

Extraia a primeira correspondência em cada assunto (extrato)

Aviso: Antes da versão 0.23, a expansão do argumento do método extract era padronizada como False. Quando
expand=False, expand retorna uma Série, Índice ou DataFrame, dependendo do assunto e da expressão regular
padrão. Quando expand=True, sempre retorna um DataFrame, que é mais consistente e menos confuso do que
a perspectiva de um usuário. expand=True é o padrão desde a versão 0.23.0.

O método extract aceita uma expressão regular com pelo menos um grupo de captura.

Extrair uma expressão regular com mais de um grupo retorna um DataFrame com uma coluna por grupo.

2.9. Trabalhando com dados de texto 591


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [103]: pd.Series(
.....: ["a1", "b2", "c3"],
.....: dtype="string",
.....: .str.extract(r"([ab])(\d)", expandir=Falso)
.....:
Fora[103]:
0 1
0 a 1
1b2
2 <NA> <NA>

Elementos que não correspondem retornam uma linha preenchida com NaN. Assim, uma série de strings confusas pode ser “convertida” em uma
Série ou DataFrame com indexação semelhante de strings limpas ou mais úteis, sem a necessidade de get() para acessar tuplas
ou re.match objetos. O dtype do resultado é sempre objeto, mesmo que nenhuma correspondência seja encontrada e o resultado contenha apenas
NaN.

Grupos nomeados como

Em [104]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(


.....: r"(?P<letra>[ab])(?P<dígito>\d)", expandir=Falso
..... :)
.....:
Fora[104]:
dígito da letra
0 a 1
1 b 2
2 <NA> <NA>

e grupos opcionais como

Em [105]: pd.Series(
.....: ["a1", "b2", "3"],
.....: dtype="string",
.....: .str.extract(r"([ab])?(\d)", expandir=Falso)
.....:
Fora[105]:
01
0 um 1
1 b2
2 <NA> 3

também pode ser usado. Observe que quaisquer nomes de grupos de captura na expressão regular serão usados para nomes de colunas; de outra forma
números de grupo de captura serão usados.

Extrair uma expressão regular com um grupo retorna um DataFrame com uma coluna se expand=True.

Em [106]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)",ÿ


ÿÿexpandir=Verdadeiro)
Fora[106]:
0
0 1
1 2
2 <NA>

Ele retorna uma série se expand=False.

592 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [107]: pd.Series(["a1", "b2", "c3"], dtype="string").str.extract(r"[ab](\d)",ÿ


ÿÿexpandir=Falso)
Fora[107]:
0 1
1 2
2 <NA>
dtype: string

Chamar um índice com uma regex com exatamente um grupo de captura retorna um DataFrame com uma coluna se
expandir = Verdadeiro.

Em [108]: s = pd.Series(["a1", "b2", "c3"], ["A11", "B22", "C33"], dtype="string")

Em [109]: s
Fora[109]:
A11 a1
B22 b2
Capítulo 33 c3
dtype: string

Em [110]: s.index.str.extract("(?P<letra>[a-zA-Z])", expand=True)


Fora[110]:
carta
0 A
1 B
2 C

Ele retorna um índice se expand=False.

Em [111]: s.index.str.extract("(?P<letra>[a-zA-Z])", expand=False)


Out[111]: Índice(['A', 'B', 'C'], dtype='objeto', nome='letra')

Chamar um índice com uma regex com mais de um grupo de captura retorna um DataFrame se expand=True.

Em [112]: s.index.str.extract("(?P<letra>[a-zA-Z])([0-9]+)", expand=True)


Fora[112]:
carta 1
0 Um 11
1 B22
2 C 33

Ele gera ValueError se expand=False.

>>> s.index.str.extract("(?P<letra>[a-zA-Z])([0-9]+)", expandir=Falso)


ValueError: apenas um grupo regex é suportado com Index

A tabela abaixo resume o comportamento de extract(expand=False) (assunto de entrada na primeira coluna, número de
grupos em regex na primeira linha)

1 grupo >1 grupo


Índice Índice Erro de valor
Série Série DataFrame

2.9. Trabalhando com dados de texto 593


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Extraia todas as correspondências em cada assunto (extractall)

Ao contrário de extract (que retorna apenas a primeira correspondência),

Em [113]: s = pd.Series(["a1a2", "b1", "c1"], index=["A", "B", "C"], dtype="string")

Em [114]: s
Fora[114]:
A1a2
B b1
C c1
dtype: string

Em [115]: dois_grupos = "(?P<letra>[az])(?P<dígito>[0-9])"

Em [116]: s.str.extract(two_groups, expand=True)


Fora[116]:
dígito da letra
A a 1
B b 1
C c 1

o método extractall retorna todas as correspondências. O resultado do extractall é sempre um DataFrame com MultiIndex
em suas fileiras. O último nível do MultiIndex é denominado match e indica a ordem do assunto.

Em [117]: s.str.extractall(dois_grupos)
Fora[117]:
dígito da letra
corresponder

Um 0 a 1
1 a 2
B0 b 1
C0 c 1

Quando cada sequência de assunto na Série tiver exatamente uma correspondência,

Em [118]: s = pd.Series(["a3", "b3", "c2"], dtype="string")

Em [119]: s
Fora[119]:
0 a3
1 b3
2 c2
dtype: string

então extractall(pat).xs(0, level='match') fornece o mesmo resultado que extract(pat).

Em [120]: extract_result = s.str.extract(two_groups, expand=True)

Em [121]: extract_result
Fora[121]:
dígito da letra
0 a 3
1 b 3
(continua na próxima página)

594 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

2 c 2

Em [122]: extractall_result = s.str.extractall(dois_grupos)

Em [123]: extractall_result
Fora[123]:
dígito da letra
corresponder

00 a 3
10 b 3
20 c 2

Em [124]: extractall_result.xs(0, level="match")


Fora[124]:
dígito da letra
0 a 3
1 b 3
2 c 2

O índice também suporta .str.extractall. Ele retorna um DataFrame que tem o mesmo resultado que Series.str.
extractall com um índice padrão (começa em 0).

Em [125]: pd.Index(["a1a2", "b1", "c1"]).str.extractall(two_groups)


Fora[125]:
dígito da letra
corresponder

00 a 1
1 a 2
10 b 1
20 c 1

Em [126]: pd.Series(["a1a2", "b1", "c1"], dtype="string").str.extractall(two_groups)


Fora[126]:
dígito da letra
corresponder

00 a 1
a 2
11 b 1
020 c 1

2.9.7 Testando strings que correspondem ou contêm um padrão

Você pode verificar se os elementos contêm um padrão:

Em [127]: padrão = r"[0-9][az]"

Em [128]: pd.Series(
.....: ["1", "2", "3a", "3b", "03c", "4dx"],
.....: dtype="string",
.....: .str.contains(padrão)
.....:
(continua na próxima página)

2.9. Trabalhando com dados de texto 595


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[128]:
0 Falso
1 Falso
2 Verdadeiro

3 Verdadeiro

4 Verdadeiro

5 Verdadeiro

tipo d: booleano

Ou se os elementos correspondem a um padrão:

Em [129]: pd.Series(
.....: ["1", "2", "3a", "3b", "03c", "4dx"],
.....: dtype="string",
.....: .str.match(padrão)
.....:
Fora[129]:
0 Falso
1 Falso
2 Verdadeiro

3 Verdadeiro

4 Falso
5 Verdadeiro

tipo d: booleano

Novo na versão 1.1.0.

Em [130]: pd.Series(
.....: ["1", "2", "3a", "3b", "03c", "4dx"],
.....: dtype="string",
.....: .str.fullmatch(padrão)
.....:
Fora[130]:
0 Falso
1 Falso
2 Verdadeiro

3 Verdadeiro

4 Falso
5 Falso
tipo d: booleano

Nota: A distinção entre match, fullmatch e contains é rigorosa: fullmatch testa se o conteúdo inteiro
string corresponde à expressão regular; match testa se há uma correspondência da expressão regular que começa em
o primeiro caractere da string; e contém testes se há uma correspondência da expressão regular em qualquer posição
dentro da string.

As funções correspondentes no pacote re para esses três modos de correspondência são re.fullmatch, re.match e re.search,
respectivamente.

Métodos como match, fullmatch, contains, começa com e termina com recebem um argumento extra que falta
os valores podem ser considerados verdadeiros ou falsos:

596 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [131]: s4 = pd.Series(
.....: ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "cachorro", "gato"], dtype=
ÿÿ"string"
..... :)
.....:

Em [132]: s4.str.contains("A", na=False)


Fora[132]:
0 Verdadeiro

Falso
Falso
Verdadeiro

1 2 3 4 Falso
5 Falso
6 Verdadeiro

7 Falso
8 Falso
tipo d: booleano

2.9.8 Criação de variáveis indicadoras

Você pode extrair variáveis fictícias de colunas de string. Por exemplo, se eles estiverem separados por um '|':

Em [133]: s = pd.Series(["a", "a|b", np.nan, "a|c"], dtype="string")

Em [134]: s.str.get_dummies(sep="|")
Fora[134]:
abc
0100
1110
2000
3101

String Index também suporta get_dummies que retorna um MultiIndex.

Em [135]: idx = pd.Index(["a", "a|b", np.nan, "a|c"])

Em [136]: idx.str.get_dummies(sep="|")
Fora[136]:
MultiÍndice([(1, 0, 0),
(1, 1, 0),
(0, 0, 0),
(1, 0, 1)],
nomes=['a', 'b', 'c'])

Veja também get_dummies().

2.9. Trabalhando com dados de texto 597


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.9.9 Resumo do método

Método Descrição
cat() Concatenar strings
split() Dividir strings no delimitador
rsplit() get() Dividir strings no delimitador trabalhando a partir do final da string
join() Indexar em cada elemento (recuperar o i-ésimo elemento)
Junte strings em cada elemento da Série com separador passado
get_dummies() Dividir strings no delimitador retornando DataFrame de variáveis fictícias
contém() Retorna um array booleano se cada string contiver padrão/regex
replace() Substitua as ocorrências de padrão/regex/string por alguma outra string ou pelo valor de retorno de um
chamável dada a ocorrência
removerprefixo() Remova o prefixo da string, ou seja, remova apenas se a string começar com prefixo.
removesufixo() Remova o sufixo da string, ou seja, remova apenas se a string terminar com sufixo.
repita() Valores duplicados (s.str.repeat(3) equivalente a x pad() * 3)
Adicione espaços em branco à esquerda, à direita ou em ambos os lados das strings

Centro() Equivalente a str.center


apenas() Equivalente a str.ljust
apenas() Equivalente a str.rjust
zfill() Equivalente a str.zfill
enrolar() Divida strings longas em linhas com comprimento menor que uma determinada largura
fatiar() Fatie cada string da série
slice_replace() Substitui fatia em cada string pelo valor passado
contar() Contar ocorrências de padrão
começa com() Equivalente a str.startswith(pat) para cada elemento
termina com() Equivalente a str.endswith(pat) para cada elemento
encontrar tudo() Calcular lista de todas as ocorrências de padrão/regex para cada string
corresponder() Chame re.match em cada elemento, retornando grupos correspondentes como lista
extrair() Chame re.search em cada elemento, retornando DataFrame com uma linha para cada elemento e
uma coluna para cada grupo de captura de regex
extrair tudo() Chame re.findall em cada elemento, retornando DataFrame com uma linha para cada correspondência e
uma coluna para cada grupo de captura de regex
len() Calcular comprimentos de string
strip() Equivalente a str.strip
rstrip() Equivalente a str.rstrip
lstrip() Equivalente a str.lstrip
partição() Equivalente a str.partition
rpartition() lower() Equivalente a str.rpartition
casefold() Equivalente a str.lower
superior() Equivalente a str.casefold
find() Equivalente a str.upper
rfind() Equivalente a str.find
index() Equivalente a str.rfind
rindex() Equivalente a str.index
capitalize() Equivalente astr.rindex
swapcase() Equivalente a str.capitalizar
normalize() Equivalente a str.swapcase
traduzir( ) Retorne o formato normal do Unicode. Equivalente a unicodedata.normalize
isalnum() isalfa() Equivalente a str.translate
Equivalente a str.isalnum
Equivalente a str.isalpha
continua na próxima página

598 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Tabela 1 – continuação da página anterior


Método Descrição
isdigit() Equivalente a str.isdigit
isspace() Equivalente a str.isspace
islower() Equivalente a str.islower
isupper() Equivalente a str.isupper
istitle() Equivalente a str.istitle
isnumeric() Equivalente a str.isnumeric
isdecimal() Equivalente a str.isdecimal

2.10 Trabalhando com dados faltantes

Nesta seção, discutiremos valores ausentes (também chamados de NA) em pandas.

Nota: A escolha de usar NaN internamente para denotar dados ausentes foi em grande parte por razões de simplicidade e desempenho.
A partir do pandas 1.0, alguns tipos de dados opcionais começam a experimentar um escalar NA nativo usando um método baseado em máscara
abordagem. Veja aqui para mais.

Consulte o livro de receitas para algumas estratégias avançadas.

2.10.1 Valores considerados “ausentes”

Como os dados vêm em vários formatos e formatos, o pandas pretende ser flexível no que diz respeito ao tratamento de dados ausentes. Enquanto
NaN é o marcador de valor ausente padrão por razões de velocidade computacional e conveniência, precisamos ser capazes de
detecte facilmente esse valor com dados de diferentes tipos: ponto flutuante, inteiro, booleano e objeto geral. Em muitos casos,
no entanto, o Python None surgirá e desejamos também considerar isso “ausente” ou “não disponível” ou “NA”.

Nota: Se quiser considerar inf e -inf como “NA” nos cálculos, você pode definir pandas.options.mode.
use_inf_as_na = Verdadeiro.

Em [1]: df = pd.DataFrame(
...: np.random.randn(5, 3),
...: índice=["a", "c", "e", "f", "h"],
...: colunas=["um", "dois", "três"],
... :)
...:

Em [2]: df["quatro"] = "barra"

Em [3]: df["cinco"] = df["um"] > 0

Em [4]: df
Fora[4]:
um dois três quatro cinco
a 0,469112 -0,282863 -1,509059 barra Verdadeiro
c -1,135632 1,212112 -0,173215 barra Falso
e 0,119209 -1,044236 -0,861849 barra Verdadeiro
f -2,104569 -0,494929 1,071804 barra Falso
(continua na próxima página)

2.10. Trabalhando com dados ausentes 599


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

h 0,721555 -0,706771 -1,039575 barra Verdadeiro

Em [5]: df2 = df.reindex(["a", "b", "c", "d", "e", "f", "g", "h"])

Em [6]: df2
Fora[6]:
um dois três quatro cinco
a 0,469112 -0,282863 -1,509059 barra Verdadeiro
NaN NaN NaN NaN NaN
bc -1,135632 1,212112 -0,173215 barra Falso
NaN NaN NaN NaN NaN
de 0,119209 -1,044236 -0,861849 barra Verdadeiro
f -2,104569 -0,494929 1,071804 barra Falso
NaN NaN NaN NaN NaN
gh 0,721555 -0,706771 -1,039575 barra Verdadeiro

Para facilitar a detecção de valores ausentes (e em diferentes tipos de array), o pandas fornece isna() e notna()
funções, que também são métodos em objetos Series e DataFrame:

Em [7]: df2["um"]
Fora[7]:
a 0,469112
b NaN
c-1,135632
d NaN
e 0,119209
f-2.104569
NaN
gh 0,721555
Nome: um, dtype: float64

Em [8]: pd.isna(df2["um"])
Fora[8]:
a Falso
b Verdadeiro

c Falso
d Verdadeiro

e Falso
f Falso
Verdadeiro

ah Falso
Nome: um, dtype: bool

Em [9]: df2["quatro"].notna()
Fora[9]:
a Verdadeiro

b Falso
c Verdadeiro

d Falso
e Verdadeiro

f Verdadeiro

g Falso
(continua na próxima página)

600 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


h Verdadeiro

Nome: quatro, dtype: bool

Em [10]: df2.isna()
Fora[10]:
um dois três quatro cinco
um Falso Falso Falso Falso Falso
b Verdadeiro Verdadeiro Verdadeiro Verdadeiro
c Falso Falso Falso Falso Falso
d Verdadeiro Verdadeiro Verdadeiro Verdadeiro
e Falso Falso Falso Falso Falso
f Falso Falso Falso Falso Falso
g Verdadeiro Verdadeiro Verdadeiro Verdadeiro
h Falso Falso Falso Falso Falso

Aviso: é preciso estar ciente de que em Python (e NumPy), os nan's não são iguais, mas os None's sim.
Observe que o pandas/NumPy usa o fato de que np.nan! = np.nan e trata None como np.nan.

Em [11]: Nenhum == Nenhum # noqa: E711


Fora[11]: Verdadeiro

Em [12]: np.nan == np.nan


Fora[12]: Falso

Portanto, em comparação com o acima, uma comparação de igualdade escalar versus None/np.nan não fornece informações úteis.

Em [13]: df2["um"] == np.nan


Fora[13]:
a Falso
b Falso
c Falso
d Falso
e Falso
f Falso
Falso
Falso
Nome: um, dtype: bool

Tipos inteiros e dados ausentes

Como NaN é um float, uma coluna de inteiros com pelo menos um valor ausente é convertida em dtype de ponto flutuante (consulte Suporte
para inteiro NA para mais). pandas fornece um array inteiro anulável, que pode ser usado solicitando explicitamente o dtype:

Em [14]: pd.Series([1, 2, np.nan, 4], dtype=pd.Int64Dtype())


Fora[14]:
0 1
1 2
2 <NA>
3 4
tipo de d: Int64

2.10. Trabalhando com dados ausentes 601


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Alternativamente, a string alias dtype='Int64' (observe o "I" maiúsculo) pode ser usada.

Consulte Tipo de dados inteiro anulável para obter mais informações.

Data e hora

Para tipos datetime64[ns], NaT representa valores ausentes. Este é um valor sentinela pseudo-nativo que pode ser representado
por NumPy em um dtype singular (datetime64[ns]). objetos pandas fornecem compatibilidade entre NaT e NaN.

Em [15]: df2 = df.copy()

Em [16]: df2["timestamp"] = pd.Timestamp("20120101")

Em [17]: df2
Fora[17]:
um dois três quatro cinco carimbo de data/hora
a 0,469112 -0,282863 -1,509059 barra Verdadeiro 01/01/2012
c -1,135632 1,212112 -0,173215 barra Falso 01/01/2012
e 0,119209 -1,044236 -0,861849 barra Verdadeiro 01/01/2012
f -2,104569 -0,494929 1,071804 barra Falso 01/01/2012
h 0,721555 -0,706771 -1,039575 barra Verdadeiro 01/01/2012

Em [18]: df2.loc[["a", "c", "h"], ["one", "timestamp"]] = np.nan

Em [19]: df2
Fora[19]:
um dois três quatro cinco carimbo de data/hora
a NaN -0,282863 -1,509059 bar Verdadeiro NaT
c NaN 1,212112 -0,173215 bar Falso NaT
e 0,119209 -1,044236 -0,861849 barra Verdadeiro 01/01/2012
f -2,104569 -0,494929 1,071804 barra Falso 01/01/2012
h NaN -0,706771 -1,039575 barra Verdadeiro NaT

Em [20]: df2.dtypes.value_counts()
Fora[20]:
float64 3
objeto 1
bool 1
datetime64[ns] dtype: 1
int64

2.10.2 Inserindo dados faltantes

Você pode inserir valores ausentes simplesmente atribuindo aos contêineres. O valor faltante real usado será escolhido com base
no tipo d.

Por exemplo, contêineres numéricos sempre usarão NaN, independentemente do tipo de valor ausente escolhido:

Em [21]: s = pd.Series([1, 2, 3])

Em [22]: s.loc[0] = Nenhum

(continua na próxima página)

602 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [23]: s
Fora[23]:
0 NaN
1 2,0
2 3,0
tipo d: float64

Da mesma forma, os contêineres de data e hora sempre usarão NaT.

Para contêineres de objetos, o pandas usará o valor fornecido:

Em [24]: s = pd.Series(["a", "b", "c"])

Em [25]: s.loc[0] = Nenhum

Em [26]: s.loc[1] = np.nan

Em [27]: s
Fora[27]:
0 Nenhum

1 NaN
2 c
dtype: objeto

2.10.3 Cálculos com dados faltantes


Os valores ausentes se propagam naturalmente por meio de operações aritméticas entre objetos pandas.

Em [28]: uma
Fora[28]:
um dois
a NaN-0,282863
c NaN 1,212112
e 0,119209 -1,044236
f -2,104569 -0,494929
h -2,104569 -0,706771

Em [29]: b
Fora[29]:
um dois três
a NaN -0,282863 -1,509059
c NaN 1,212112 -0,173215
e 0,119209 -1,044236 -0,861849
f -2,104569 -0,494929 1,071804
h NaN -0,706771 -1,039575

Em [30]: a + b
Fora[30]:
um três dois
a NaN NaN-0,565727
c NaN NaN 2,424224
(continua na próxima página)

2.10. Trabalhando com dados ausentes 603


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


e 0,238417 NaN -2,088472
f-4.209138 NaN -0,989859
h NaN NaN -1,413542

As estatísticas descritivas e métodos computacionais discutidos na visão geral da estrutura de dados (e listados aqui e aqui)
são todos gravados para compensar dados ausentes. Por exemplo:

• Ao somar os dados, os valores NA (ausentes) serão tratados como zero.

• Se todos os dados forem NA, o resultado será 0.

• Métodos cumulativos como cumsum() e cumprod() ignoram os valores NA por padrão, mas os preservam no
matrizes resultantes. Para substituir esse comportamento e incluir valores NA, use skipna=False.

Em [31]: df
Fora[31]:
um dois três
a NaN -0,282863 -1,509059
c NaN 1,212112 -0,173215
e 0,119209 -1,044236 -0,861849
f -2,104569 -0,494929 1,071804
h NaN -0,706771 -1,039575

Em [32]: df["um"].sum()
Saída[32]: -1,9853605075978744

Em [33]: df.mean(1)
Fora[33]:
-0,895961
c 0,519449
e-0,595625
f -0,509232
h-0,873173
tipo d: float64

Em [34]: df.cumsum()
Fora[34]:
um dois três
a NaN -0,282863 -1,509059
c NaN 0,929249 -1,682273
e 0,119209 -0,114987 -2,544122
f -1,985361 -0,609917 -1,472318
h NaN -1,316688 -2,511893

Em [35]: df.cumsum(skipna=False)
Fora[35]:
um dois três
aNaN -0,282863 -1,509059
cNaN 0,929249 -1,682273
eNaN -0,114987 -2,544122
fNaN -0,609917 -1,472318
hNaN -1,316688 -2,511893

604 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.10.4 Soma/produção de vazios/nans

Aviso: Este comportamento agora é padrão a partir da v0.22.0 e é consistente com o padrão em numpy; anteriormente, soma/produção
de séries/DataFrames totalmente NA ou vazias retornaria NaN. Consulte novidades da v0.22.0 para obter mais informações.

A soma de uma série ou coluna vazia ou totalmente NA de um DataFrame é 0.

Em [36]: pd.Series([np.nan]).sum()
Fora[36]: 0,0

Em [37]: pd.Series([], dtype="float64").sum()


Fora[37]: 0,0

O produto de uma série ou coluna vazia ou totalmente NA de um DataFrame é 1.

Em [38]: pd.Series([np.nan]).prod()
Fora[38]: 1,0

Em [39]: pd.Series([], dtype="float64").prod()


Fora[39]: 1,0

2.10.5 Valores NA em GroupBy

Os grupos NA em GroupBy são automaticamente excluídos. Este comportamento é consistente com R, por exemplo:

Em [40]: df
Fora[40]:
um dois três
a NaN -0,282863 -1,509059 NaN
c 1,212112 -0,173215 e 0,119209
-1,044236 -0,861849 f -2,104569 -0,494929
1,071804 NaN -0,706771 -1,039575
h

Em [41]: df.groupby("um").mean()
Fora[41]:
dois três
um
-2,104569 -0,494929 1,071804
0,119209 -1,044236 -0,861849

Consulte a seção groupby aqui para obter mais informações.

2.10. Trabalhando com dados ausentes 605


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Limpeza/preenchimento de dados ausentes

Os objetos pandas são equipados com vários métodos de manipulação de dados para lidar com dados ausentes.

2.10.6 Preenchendo valores faltantes: fillna

fillna() pode “preencher” valores NA com dados não-NA de duas maneiras, que ilustramos:

Substitua NA por um valor escalar

Em [42]: df2
Fora[42]:
um dois três quatro cinco carimbo de data/hora
a NaN -0,282863 -1,509059 bar Verdadeiro NaT
c NaN 1,212112 -0,173215 barra Falso NaT
e 0,119209 -1,044236 -0,861849 barra Verdadeiro 01/01/2012
f -2,104569 -0,494929 1,071804 barra Falso 01/01/2012
h NaN -0,706771 -1,039575 barra Verdadeiro NaT

Em [43]: df2.fillna(0)
Fora[43]:
um dois três quatro cinco carimbo de data/hora
a 0,000000 -0,282863 -1,509059 barra Verdadeiro 0
c 0,000000 1,212112 -0,173215 barra Falso 0
e 0,119209 -1,044236 -0,861849 barra Verdadeiro 01/01/2012 00:00:00
f -2,104569 -0,494929 1,071804 barra Falso 01/01/2012 00:00:00
h 0,000000 -0,706771 -1,039575 barra Verdadeiro 0

Em [44]: df2["um"].fillna("ausente")
Fora[44]:
a ausente
c ausente
e 0,119209
f-2.104569
estou faltando
Nome: um, dtype: objeto

Preencha lacunas para frente ou para trás

Usando os mesmos argumentos de preenchimento da reindexação, podemos propagar valores não-NA para frente ou para trás:

Em [45]: df
Fora[45]:
um dois três
a NaN -0,282863 -1,509059
c NaN 1,212112 -0,173215
e 0,119209 -1,044236 -0,861849
f -2,104569 -0,494929 1,071804
hNaN -0,706771 -1,039575

Em [46]: df.fillna(método="pad")
Fora[46]:
um dois três
a NaN -0,282863 -1,509059
(continua na próxima página)

606 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

c NaN 1,212112 -0,173215


e 0,119209 -1,044236 -0,861849
f -2,104569 -0,494929 1,071804
-2,104569 -0,706771 -1,039575

Limite a quantidade de recheio

Se quisermos apenas que lacunas consecutivas sejam preenchidas até um certo número de pontos de dados, podemos usar a palavra-chave limit:

Em [47]: df
Fora[47]:
um dois três
aNaN -0,282863 -1,509059
cNaN 1,212112 -0,173215
e NaN NaN NaN
fNaN NaN NaN
hNaN -0,706771 -1,039575

Em [48]: df.fillna(method="pad", limit=1)


Fora[48]:
um dois três
aNaN -0,282863 -1,509059
cNaN 1,212112 -0,173215
eNaN 1,212112 -0,173215
f NaN h NaN NaN
NaN -0,706771 -1,039575

Para lembrá-lo, estes são os métodos de preenchimento disponíveis:

Método Ação
almofada / Preencha os valores adiante

preenchimento bfill / preenchimento Preencher valores para trás

Com dados de série temporal, o uso de pad/ffill é extremamente comum para que o “último valor conhecido” esteja sempre disponível
apontar.

ffill() é equivalente a fillna(method='ffill') e bfill() é equivalente a fillna(method='bfill')

2.10.7 Preenchendo com um PandasObject

Você também pode preencher usando um ditado ou série que seja alinhável. Os rótulos do dict ou índice da Série devem corresponder ao
colunas do quadro que você deseja preencher. O caso de uso disso é preencher um DataFrame com a média dessa coluna.

Em [49]: dff = pd.DataFrame(np.random.randn(10, 3), colunas=lista("ABC"))

Em [50]: dff.iloc[3:5, 0] = np.nan

Em [51]: dff.iloc[4:6, 1] = np.nan

Em [52]: dff.iloc[5:8, 2] = np.nan

Em [53]: dff
(continua na próxima página)

2.10. Trabalhando com dados ausentes 607


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[53]:
A B C
0 0,271860 -0,424972 0,567020
10,276232 -1,087401 -0,673690
2 0,113648 -1,478427 0,524988
3 NaN 0,577046 -1,715002
4 NaN NaN -1,157892
5-1,344312 NaN NaN
6 -0,109050 1,643563 NaN
7 0,357021 -0,674600 NaN
8 -0,968914 -1,294524 0,413738
9 0,276662 -0,472035 -0,013960

Em [54]: dff.fillna(dff.mean())
Fora[54]:
A B C
0 0,271860 -0,424972 0,567020
10,276232 -1,087401 -0,673690
2 0,113648 -1,478427 0,524988
3 -0,140857 0,577046 -1,715002
4 -0,140857 -0,401419 -1,157892
5 -1,344312 -0,401419 -0,293543
6 -0,109050 1,643563 -0,293543
7 0,357021 -0,674600 -0,293543
8 -0,968914 -1,294524 0,413738
9 0,276662 -0,472035 -0,013960

Em [55]: dff.fillna(dff.mean()["B":"C"])
Fora[55]:
A B C
0 0,271860 -0,424972 0,567020
10,276232 -1,087401 -0,673690
2 0,113648 -1,478427 0,524988
3 NaN 0,577046 -1,715002
4 NaN -0,401419 -1,157892
5 -1,344312 -0,401419 -0,293543
6 -0,109050 1,643563 -0,293543
7 0,357021 -0,674600 -0,293543
8 -0,968914 -1,294524 0,413738
9 0,276662 -0,472035 -0,013960

O mesmo resultado acima, mas está alinhando o valor de 'preenchimento' que é uma Série neste caso.

Em [56]: dff.where(pd.notna(dff), dff.mean(), axis="columns")


Fora[56]:
A B C
0 0,271860 -0,424972 0,567020
10,276232 -1,087401 -0,673690
2 0,113648 -1,478427 0,524988
3 -0,140857 0,577046 -1,715002
4 -0,140857 -0,401419 -1,157892
5 -1,344312 -0,401419 -0,293543
(continua na próxima página)

608 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

6 -0,109050 1,643563 -0,293543


7 0,357021 -0,674600 -0,293543
8 -0,968914 -1,294524 0,413738
9 0,276662 -0,472035 -0,013960

2.10.8 Eliminando rótulos de eixos com dados ausentes: dropna

Você pode simplesmente excluir rótulos de um conjunto de dados que se referem a dados ausentes. Para fazer isso, use dropna():

Em [57]: df
Fora[57]:
um dois três
aNaN -0,282863 -1,509059
cNaN 1,212112 -0,173215
eNaN 0,000000 0,000000
f NaN 0,000000 0,000000 h NaN -0,706771
-1,039575

Em [58]: df.dropna(eixo=0)
Out[58]:
Colunas vazias do
DataFrame: [um, dois, três]
Índice: []

Em [59]: df.dropna(eixo=1)
Fora[59]:
dois três
a -0,282863 -1,509059
c 1,212112 -0,173215
e 0,000000 0,000000
f 0,000000 0,000000 h -0,706771
-1,039575

Em [60]: df["um"].dropna()
Out[60]: Series([], Nome: um, dtype: float64)

Um dropna() equivalente está disponível para séries. DataFrame.dropna tem consideravelmente mais opções que Series.dropna,
que podem ser examinadas na API.

2.10.9 Interpolação

Os objetos Series e DataFrame possuem interpolate() que, por padrão, executa interpolação linear em pontos de dados ausentes.

Em [61]: ts
Saída[61]:
31/01/2000 0,469112
29/02/2000 NaN
31/03/2000 NaN
28/04/2000 NaN
(continua na próxima página)

2.10. Trabalhando com dados ausentes 609


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

31/05/2000 NaN
...
31-12-2007 -6.950267
31/01/2008 -7.904475
29/02/2008 -6.441779
31/03/2008 -8.184940
30/04/2008 -9.011531
Freq: BM, Comprimento: 100, tipo d: float64

Em [62]: ts.count()
Fora[62]: 66

Em [63]: ts.plot()
Saída[63]: <AxesSubplot:>

Em [64]: ts.interpolate()
Fora[64]:
31/01/2000 0,469112
29/02/2000 0,434469
31/03/2000 0,399826
28/04/2000 0,365184
31/05/2000 0,330541
(continua na próxima página)

610 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

...
31-12-2007 -6.950267
31/01/2008 -7.904475
29/02/2008 -6.441779
31/03/2008 -8.184940
30/04/2008 -9.011531
Freq: BM, Comprimento: 100, tipo d: float64

Em [65]: ts.interpolate().count()
Fora[65]: 100

Em [66]: ts.interpolate().plot()
Saída[66]: <AxesSubplot:>

A interpolação com reconhecimento de índice está disponível por meio da palavra-chave method:

Em [67]: ts2
Saída[67]:
31/01/2000 0,469112
29/02/2000 NaN
31/07/2002 -5,785037
31/01/2005 NaN
(continua na próxima página)

2.10. Trabalhando com dados ausentes 611


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

30/04/2008 -9.011531
tipo d: float64

Em [68]: ts2.interpolate()
Fora[68]:
31/01/2000 0,469112
29/02/2000 -2,657962
31/07/2002 -5,785037
31-01-2005 -7.398284
30/04/2008 -9.011531
tipo d: float64

Em [69]: ts2.interpolate(method="time")
Fora[69]:
31/01/2000 0,469112
29/02/2000 0,270241
31/07/2002 -5,785037
31/01/2005 -7.190866
30/04/2008 -9.011531
tipo d: float64

Para um índice de ponto flutuante, use method='values':

Em [70]: ser
Fora[70]:
0,0 0,0
1,0 NaN
10,0 10,0
tipo d: float64

Em [71]: ser.interpolate()
Fora[71]:
0,0 0,0
1,0 5,0
10,0 10,0
tipo d: float64

Em [72]: ser.interpolate(method="values")
Fora[72]:
0,0 0,0
1,0 1,0
10,0 10,0
tipo d: float64

Você também pode interpolar com um DataFrame:

Em [73]: df = pd.DataFrame(
....: {
....: "A": [1, 2,1, np.nan, 4,7, 5,6, 6,8],
....: "B": [0,25, np.nan, np.nan, 4, 12,2, 14,4],
....: }
....: )
(continua na próxima página)

612 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

....:

Em [74]: df
Fora[74]:
A B
0 1,0 0,25
1 2.1 NaN
2NaN NaN
3 4,7 4,00
4 5,6 12,20
5 6,8 14,40

Em [75]: df.interpolate()
Fora[75]:
A B
0 1,0 0,25 1 2,1
1,50 2 3,4 2,75 3
4,7 4,00 4 5,6 12,20
5 6,8 14,40

O argumento do método dá acesso a métodos de interpolação mais sofisticados. Se você tiver o scipy instalado, poderá passar o nome
de uma rotina de interpolação 1-d para o método. Você vai querer consultar a documentação completa de interpolação scipy e o guia
de referência para obter detalhes. O método de interpolação apropriado dependerá do tipo de dados com os quais você está trabalhando.

• Se você estiver lidando com uma série temporal que está crescendo a uma taxa crescente, method='quadratic' pode ser apropriado.
privado.

• Se você tiver valores aproximados de uma função de distribuição cumulativa, então method='pchip' deverá funcionar bem.

• Para preencher valores faltantes com o objetivo de plotagem suave, considere method='akima'.

Aviso: Esses métodos requerem scipy.

Em [76]: df.interpolate(method="barycentric")
Fora[76]:
A B
0 1,00 0,250 1 2,10
-7,660 2 3,53 -4,515
3 4,70 4,000 4 5,60
12,200 5 6,80 14,400

Em [77]: df.interpolate(method="pchip")
Fora[77]:
A B
0 1,00000 0,250000 1 2,10000
0,672808
2 3,43454 1,928950
3 4,70000 4,000000
(continua na próxima página)

2.10. Trabalhando com dados ausentes 613


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


4 5,60000 12,200000
5 6,80000 14,400000

Em [78]: df.interpolate(method="akima")
Fora[78]:
A B
0 1,000000 0,250000
12,100000 -0,873316
2 3,406667 0,320034
3 4,700000 4,000000
4 5,600000 12,200000 5 6,800000
14,400000

Ao interpolar através de uma aproximação polinomial ou spline, você também deve especificar o grau ou a ordem da aproximação:

Em [79]: df.interpolate(method="spline", order=2)


Fora[79]:
A B
0 1,000000 0,250000
12,100000 -0,428598
2 3.404545 1.206900
3 4,700000 4,000000
4 5,600000 12,200000
5 6,800000 14,400000

Em [80]: df.interpolate(method="polinomial", order=2)


Fora[80]:
A B
0 1.000000 0,250000 1 2.100000
-2.703846 2 3.451351 -1.453846
3 4.700000 4.000000 4 5.600000
12.200000 5 6.800000 14.400000

Compare vários métodos:

Em [81]: np.random.seed(2)

Em [82]: ser = pd.Series(np.arange(1, 10,1, 0,25) ** 2 + np.random.randn(37))

Em [83]: ausente = np.array([4, 13, 14, 15, 16, 17, 18, 20, 29])

Em [84]: ser[ausente] = np.nan

Em [85]: métodos = ["linear", "quadrático", "cúbico"]

Em [86]: df = pd.DataFrame({m: ser.interpolate(method=m) for m in methods})

Em [87]: df.plot()
Saída[87]: <AxesSubplot:>

614 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Outro caso de uso é a interpolação em novos valores. Suponha que você tenha 100 observações de alguma distribuição. E vamos
suponha que você esteja particularmente interessado no que está acontecendo no meio. Você pode misturar a reindexação dos pandas e
métodos de interpolação para interpolar nos novos valores.

Em [88]: ser = pd.Series(np.sort(np.random.uniform(size=100)))

# interpolar em new_index
Em [89]: new_index = ser.index.union(pd.Index([49,25, 49,5, 49,75, 50,25, 50,5, 50,75]))

Em [90]: interp_s = ser.reindex(new_index).interpolate(method="pchip")

Em [91]: interp_s[49:51]
Fora[91]:
49,00 0,471410
49,25 0,476841
49,50 0,481780
49,75 0,485998
50,00 0,489266
50,25 0,491814
50,50 0,493995
50,75 0,495763
51,00 0,497074
tipo d: float64

2.10. Trabalhando com dados ausentes 615


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Limites de interpolação

Como outros métodos de preenchimento do pandas, interpolate() aceita um argumento de palavra-chave limit. Use este argumento para limitar o
número de valores NaN consecutivos preenchidos desde a última observação válida:

Em [92]: ser = pd.Series([np.nan, np.nan, 5, np.nan, np.nan, np.nan, 13, np.nan, np.nan])

Em [93]: ser
Fora[93]:
0 NaN
1 NaN
2 5,0
3 NaN
4 NaN
5 NaN
6 13,0
7 NaN
8 NaN
tipo d: float64

# preenche todos os valores consecutivos na direção direta


Em [94]: ser.interpolate()
Fora[94]:
0 NaN
NaN
1 2 5,0
3 7,0
4 9,0
5 11,0
6 13,0
7 13,0
8 13,0
tipo d: float64

# preenche um valor consecutivo na direção direta


Em [95]: ser.interpolate(limit=1)
Fora[95]:
0 NaN
1 NaN
2 5,0
3 7,0
4 NaN
5 NaN
6 13,0
7 13,0
NaN
8 dtipo: float64

Por padrão, os valores NaN são preenchidos na direção direta. Use o parâmetro limit_direction para preencher para trás ou de
ambas direcoes.

# preenche um valor consecutivo de trás para frente


Em [96]: ser.interpolate(limit=1, limit_direction="backward")
Fora[96]:
(continua na próxima página)

616 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

0 NaN
1 5,0
2 5,0
3 NaN
4 NaN
5 11,0
6 13,0
7 NaN
8 NaN
tipo d: float64

# preenche um valor consecutivo em ambas as direções


Em [97]: ser.interpolate(limit=1, limit_direction="both")
Fora[97]:
0 NaN
1 5,0
2 5,0
3 7,0
4 NaN
5 11,0
6 13,0
7 13,0
NaN
8 dtipo: float64

# preenche todos os valores consecutivos em ambas as direções


Em [98]: ser.interpolate(limit_direction="both")
Fora[98]:
0 5,0
1 5,0
2 5,0
3 7,0
4 9,0
5 11,0
6 13,0
7 13,0
8 13,0
tipo d: float64

Por padrão, os valores NaN são preenchidos quer estejam dentro (cercados por) valores válidos existentes ou fora dos valores válidos existentes.
valores. O parâmetro limit_area restringe o preenchimento a valores internos ou externos.

# preenche um valor interno consecutivo em ambas as direções


Em [99]: ser.interpolate(limit_direction="both", limit_area="inside", limit=1)
Fora[99]:
0 NaN
1 NaN
2 5,0
3 7,0
4 NaN
5 11,0
6 13,0
(continua na próxima página)

2.10. Trabalhando com dados ausentes 617


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

7 NaN
8 NaN
tipo d: float64

# preenche todos os valores externos consecutivos de trás para frente


Em [100]: ser.interpolate(limit_direction="backward", limit_area="outside")
Fora[100]:
0 5,0
1 5,0
2 5,0
3 NaN
4 NaN
5 NaN
6 13,0
7 NaN
8 NaN
tipo d: float64

# preenche todos os valores externos consecutivos em ambas as direções


Em [101]: ser.interpolate(limit_direction="both", limit_area="outside")
Fora[101]:
0 5,0
1 5,0
2 5,0
3 NaN
4 NaN
5 NaN
6 13,0
7 13,0
8 13,0
tipo d: float64

2.10.10 Substituindo valores genéricos

Muitas vezes queremos substituir valores arbitrários por outros valores.

replace() em Series e replace() em DataFrame fornecem uma maneira eficiente, porém flexível, de realizar tais substituições.

Para uma série, você pode substituir um único valor ou uma lista de valores por outro valor:

Em [102]: ser = pd.Series([0,0, 1,0, 2,0, 3,0, 4,0])

Em [103]: ser.replace(0, 5)
Fora[103]:
0 5,0
1 1,0
2 2,0
3 3,0
4 4,0
tipo d: float64

Você pode substituir uma lista de valores por uma lista de outros valores:

618 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [104]: ser.replace([0, 1, 2, 3, 4], [4, 3, 2, 1, 0])


Fora[104]:
0 4,0
1 3,0
2 2,0
3 1,0
4 0,0
tipo d: float64

Você também pode especificar um ditado de mapeamento:

Em [105]: ser.replace({0: 10, 1: 100})


Fora[105]:
0 10,0
1 100,0
2 2,0
3 3,0
4 4,0
tipo d: float64

Para um DataFrame, você pode especificar valores individuais por coluna:

Em [106]: df = pd.DataFrame({"a": [0, 1, 2, 3, 4], "b": [5, 6, 7, 8, 9]})

Em [107]: df.replace({"a": 0, "b": 5}, 100)


Fora[107]:
a b
0 100 100
116

227

338

4 4 9

Em vez de substituir por valores especificados, você pode tratar todos os valores fornecidos como ausentes e interpolar sobre eles:

Em [108]: ser.replace([1, 2, 3], método="pad")


Fora[108]:
0 0,0
1 0,0
2 0,0
3 0,0
4 4,0
tipo d: float64

2.10. Trabalhando com dados ausentes 619


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.10.11 Substituição de string/expressão regular

Nota: Strings Python prefixadas com o caractere r, como r'hello world', são chamadas de strings “brutas”. Eles têm
semântica diferente em relação às barras invertidas das strings sem esse prefixo. Barras invertidas em strings brutas serão interpretadas
como uma barra invertida com escape, por exemplo, r'\' == '\\'. Você deve ler sobre eles se isso não estiver claro.

Substitua o '.' com NaN (str -> str):

Em [109]: d = {"a": list(range(4)), "b": list("ab.."), "c": ["a", "b", np.nan, "d"]}

Em [110]: df = pd.DataFrame(d)

Em [111]: df.replace(".", np.nan)


Fora[111]:
a b c
00 a a
11 b b
2 2 NaN NaN
3 3 NaN d

Agora faça isso com uma expressão regular que remove os espaços em branco circundantes (regex -> regex):

Em [112]: df.replace(r"\s*\.\s*", np.nan, regex=True)


Fora[112]:
a b c
00 a a
11 b b
2 2 NaN NaN
3 3 NaN d

Substitua alguns valores diferentes (lista -> lista):

Em [113]: df.replace(["a", "."], ["b", np.nan])


Fora[113]:
a c
00b
11b bbb
2 2 NaN NaN
3 3 NaN d

lista de regex -> lista de regex:

Em [114]: df.replace([r"\.", r"(a)"], ["ponto", r"\1stuff"], regex=True)


Fora[114]:
a b c
0 0 coisas
11 b b
22 ponto NaN
33 ponto d

Pesquise apenas na coluna 'b' (dict -> dict):

620 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [115]: df.replace({"b": "."}, {"b": np.nan})


Fora[115]:
a b c
00 a a
11 b b
2 2 NaN NaN
3 3 NaN d

Igual ao exemplo anterior, mas use uma expressão regular para pesquisar (dict of regex -> dict):

Em [116]: df.replace({"b": r"\s*\.\s*"}, {"b": np.nan}, regex=True)


Fora[116]:
a b c
001 a a
1b b
2 2 NaN NaN
3 3 NaNd

Você pode passar dicionários aninhados de expressões regulares que usam regex=True:

Em [117]: df.replace({"b": {"b": r""}}, regex=True)


Fora[117]:
ab c
0 0 uma a
11 b
22 . NaN
33. d

Alternativamente, você pode passar o dicionário aninhado assim:

Em [118]: df.replace(regex={"b": {r"\s*\.\s*": np.nan}})


Fora[118]:
a b c
001 a a
1b b
2 2 NaN NaN
3 3 NaN d

Você também pode usar o grupo de correspondência de expressão regular ao substituir (dict of regex -> dict of regex), isso funciona para
listas também.

Em [119]: df.replace({"b": r"\s*(\.)\s*"}, {"b": r"\1ty"}, regex=True)


Fora[119]:
a b c
00 a a
11 b b
2 2 .ty NaN
3 3 .ty d

Você pode passar uma lista de expressões regulares, das quais aquelas que corresponderem serão substituídas por um escalar (lista de regex ->
regex).

Em [120]: df.replace([r"\s*\.\s*", r"a|b"], np.nan, regex=True)


Fora[120]:
(continua na próxima página)

2.10. Trabalhando com dados ausentes 621


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

ab c
0 0 NaN NaN
1 1 NaN NaN
2 2 NaN NaN
3 3 NaN d

Todos os exemplos de expressões regulares também podem ser passados com o argumento to_replace como argumento regex. Em
neste caso, o argumento value deve ser passado explicitamente por nome ou regex deve ser um dicionário aninhado. O anterior
exemplo, neste caso, seria então:

Em [121]: df.replace(regex=[r"\s*\.\s*", r"a|b"], valor=np.nan)


Fora[121]:
ab 0 0 c
NaN NaN
1 1 NaN NaN
2 2 NaN NaN
3 3 NaN d

Isso pode ser conveniente se você não quiser passar regex=True toda vez que quiser usar uma expressão regular.

Nota: Em qualquer lugar nos exemplos de substituição acima onde você vê uma expressão regular, uma expressão regular compilada é
válido também.

2.10.12 Substituição numérica

substituir() é semelhante a fillna().

Em [122]: df = pd.DataFrame(np.random.randn(10, 2))

Em [123]: df[np.random.rand(df.shape[0]) > 0,5] = 1,5

Em [124]: df.replace(1.5, np.nan)


Fora[124]:
01
0 -0,844214 -1,021415
10,432396 -0,323580
2 0,423825 0,799180
3 1,262614 0,751965
4 NaN NaN
5 NaN NaN
6 -0,498174 -1,060799
7 0,591667 -0,183257
8 1,019855 -1,482465
9 NaN NaN

A substituição de mais de um valor é possível passando uma lista.

Em [125]: df00 = df.iloc[0, 0]

Em [126]: df.replace([1.5, df00], [np.nan, "a"])


(continua na próxima página)

622 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[126]:
0 1
0 -1,021415
10,432396 -0,323580
2 0,423825 0,799180
3 1,262614 0,751965
4 NaN NaN
5 NaN NaN
6 -0,498174 -1,060799
7 0,591667 -0,183257
8 1,019855 -1,482465
9 NaN NaN

Em [127]: df[1].dtype
Fora[127]: dtype('float64')

Você também pode operar no DataFrame:

Em [128]: df.replace(1.5, np.nan, inplace=True)

Regras e indexação de transmissão de dados ausentes

Embora o pandas suporte o armazenamento de matrizes do tipo inteiro e booleano, esses tipos não são capazes de armazenar dados ausentes.
Até que possamos passar a usar um tipo NA nativo no NumPy, estabelecemos algumas “regras de transmissão”. Quando uma reindexação
operação introduz dados faltantes, a Série será lançada de acordo com as regras introduzidas na tabela abaixo.

tipo de dados Transmitir para

inteiro flutuador

booleano objeto
objeto sem elenco

flutuante sem elenco

Por exemplo:

Em [129]: s = pd.Series(np.random.randn(5), index=[0, 2, 4, 6, 7])

Em [130]: s > 0
Fora[130]:
0 Verdadeiro

2 Verdadeiro

4 Verdadeiro

6 Verdadeiro

7 Verdadeiro

tipo d: bool

Em [131]: (s > 0).dtype


Fora[131]: dtype('bool')

Em [132]: crit = (s > 0).reindex(list(range(8)))

(continua na próxima página)

2.10. Trabalhando com dados ausentes 623


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [133]: crítica
Fora[133]:
0 Verdadeiro

1 NaN
2 Verdadeiro

3 NaN
4 Verdadeiro

5 NaN
6 Verdadeiro

7 Verdadeiro

dtype: objeto

Em [134]: crit.dtype
Fora[134]: dtype('O')

Normalmente, o NumPy reclamará se você tentar usar um array de objetos (mesmo que contenha valores booleanos) em vez de um
array booleano para obter ou definir valores de um ndarray (por exemplo, selecionar valores com base em alguns critérios). Se um vetor booleano
contém NAs, uma exceção será gerada:

Em [135]: reindexado = s.reindex(list(range(8))).fillna(0)

Em [136]: reindexado[crit]
-------------------------------------------------- -------------------------

Erro de valor Traceback (última chamada mais recente)


Insira em [136], em <linha de célula: 1>()
----> 1 reindexado[crit]

Arquivo /pandas/pandas/core/series.py:979, em Series.__getitem__(self, key)


976 se is_iterator(chave):
977 chave = lista(chave)
-> 979 se com.is_bool_indexer(chave):
980 chave = check_bool_indexer(self.index, chave)
981 chave = np.asarray(chave, dtype=bool)

Arquivo /pandas/pandas/core/common.py:144, em is_bool_indexer(chave)


140 na_msg = "Não é possível mascarar com array não booleano contendo valores NA/NaN"
141 se lib.infer_dtype(key) == "boolean" e isna(key).any():
142 # Não aumente, por exemplo, ["A", "B", np.nan], veja
143 # test_loc_getitem_list_of_labels_categoricalindex_with_na
--> 144 aumentar ValueError(na_msg)
145 retorna falso
146 retornar Verdadeiro

ValueError: Não é possível mascarar com array não booleano contendo valores NA/NaN

No entanto, estes podem ser preenchidos usando fillna() e funcionará bem:

Em [137]: reindexado[crit.fillna(False)]
Fora[137]:
0 0,126504
20,696198
4 0,697416
(continua na próxima página)

624 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

6 0,601516
7 0,003659
tipo d: float64

Em [138]: reindexado[crit.fillna(True)]
Fora[138]:
0 0,126504
1 0,000000
2 0,696198
3 0,000000
4 0,697416
5 0,000000
6 0,601516
7 0,003659
tipo d: float64

pandas fornece um tipo inteiro anulável, mas você deve solicitá-lo explicitamente ao criar a série ou coluna. Perceber
que usamos um “I” maiúsculo em dtype="Int64".

Em [139]: s = pd.Series([0, 1, np.nan, 3, 4], dtype="Int64")

Em [140]: s
Fora[140]:
0 0
1 1
2 <NA>
3 3
4 4
tipo de d: Int64

Consulte Tipo de dados inteiro anulável para obter mais informações.

2.10.13 Escalar NA experimental para denotar valores ausentes

Aviso: Experimental: o comportamento do pd.NA ainda pode mudar sem aviso prévio.

Novo na versão 1.0.0.

A partir do pandas 1.0, um valor experimental pd.NA (singleton) está disponível para representar valores escalares ausentes. No
neste momento, ele é usado nos tipos de dados inteiro anulável, booleano e string dedicado como indicador de valor ausente.

O objetivo do pd.NA é fornecer um indicador “ausente” que possa ser usado consistentemente em todos os tipos de dados (em vez de np.nan,
Nenhum ou pd.NaT dependendo do tipo de dados).

Por exemplo, ao ter valores ausentes em uma série com o dtype inteiro anulável, ele usará pd.NA:

Em [141]: s = pd.Series([1, 2, None], dtype="Int64")

Em [142]: s
Fora[142]:
01

(continua na próxima página)

2.10. Trabalhando com dados ausentes 625


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


1 2
2 <NA>
tipo de d: Int64

Em [143]: s[2]
Fora[143]: <NA>

In [144]: s[2] é pd.NA Out[144]: True

Atualmente, o pandas ainda não usa esses tipos de dados por padrão (ao criar um DataFrame ou Série, ou ao ler dados), então você precisa
especificar o dtype explicitamente. Uma maneira fácil de converter para esses tipos é explicada aqui.

Propagação em operações aritméticas e de comparação

Em geral, os valores faltantes se propagam em operações envolvendo pd.NA. Quando um dos operandos é desconhecido, o resultado da
operação também é desconhecido.

Por exemplo, pd.NA se propaga em operações aritméticas, de forma semelhante a np.nan:

Entrada [145]: pd.NA + 1


Saída[145]: <NA>

Entrada [146]: "a" * pd.NA


Saída[146]: <NA>

Existem alguns casos especiais em que o resultado é conhecido, mesmo quando um dos operandos é NA.

Entrada [147]: pd.NA ** 0 Saída


[147]: 1

Entrada [148]: 1 ** pd.NA


Saída[148]: 1

Nas operações de igualdade e comparação, pd.NA também se propaga. Isso se desvia do comportamento de np.nan, onde comparações
com np.nan sempre retornam False.

Entrada [149]: pd.NA == 1


Saída[149]: <NA>

Entrada [150]: pd.NA == pd.NA


Saída[150]: <NA>

Entrada [151]: pd.NA < 2,5


Saída[151]: <NA>

Para verificar se um valor é igual a pd.NA, a função isna() pode ser usada:

Em [152]: pd.isna(pd.NA)
Fora[152]: Verdadeiro

Uma exceção a esta regra básica de propagação são as reduções (como a média ou o mínimo), onde o padrão do pandas é pular valores
ausentes. Veja acima para mais.

626 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Operações lógicas

Para operações lógicas, pd.NA segue as regras da lógica de três valores (ou lógica Kleene, semelhante a R, SQL e Julia). Essa lógica
significa propagar valores ausentes apenas quando for logicamente necessário.

Por exemplo, para a operação lógica “ou” (|), se um dos operandos for Verdadeiro, já sabemos que o resultado será Verdadeiro,
independentemente do outro valor (portanto, independentemente do valor faltante seria Verdadeiro ou Falso). Neste caso, pd.NA não se
propaga:

Em [153]: Verdadeiro | Falso


Fora[153]: Verdadeiro

Em [154]: Verdadeiro | pd.NA


Out[154]: Verdadeiro

Em [155]: pd.NA | Verdadeiro


[155]: Verdadeiro

Por outro lado, se um dos operandos for False, o resultado depende do valor do outro operando. Portanto, neste caso pd.NA propaga:

Em [156]: Falso | Verdadeiro


Fora[156]: Verdadeiro

Em [157]: Falso | Falso


Fora[157]: Falso

Em [158]: Falso | pd.NA Saída[158]:


<NA>

O comportamento da operação lógica “e” (&) pode ser derivado usando lógica semelhante (onde agora pd.NA não será propagado se um
dos operandos já for Falso):

Em [159]: Falso e Verdadeiro


Fora[159]: Falso

Em [160]: Falso e Falso


Fora[160]: Falso

In [161]: Falso & pd.NA Out[161]:


Falso

Em [162]: Verdadeiro e Verdadeiro


Fora[162]: Verdadeiro

Em [163]: Verdadeiro e Falso


Fora[163]: Falso

Entrada [164]: Verdadeiro & pd.NA


Saída[164]: <NA>

2.10. Trabalhando com dados ausentes 627


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

NA em um contexto booleano

Como o valor real de um NA é desconhecido, é ambíguo converter NA em um valor booleano. Os seguintes aumentos
um erro:

Em [165]: bool(pd.NA)
-------------------------------------------------- -------------------------

TypeError Traceback (última chamada mais recente)


Entrada em [165], em <linha de célula: 1>() ----> 1
bool(pd.NA)

Arquivo /pandas/pandas/_libs/missing.pyx:382, em pandas._libs.missing.NAType.__bool__()

TypeError: o valor booleano de NA é ambíguo

Isso também significa que pd.NA não pode ser usado em um contexto onde é avaliado como booleano, como if condição: ... onde
condição pode potencialmente ser pd.NA. Nesses casos, isna() pode ser usado para verificar pd.NA ou a condição pd.NA pode
ser evitada, por exemplo, preenchendo os valores ausentes antecipadamente.

Uma situação semelhante ocorre ao usar objetos Series ou DataFrame em instruções if, consulte Usando instruções if/ truth com
pandas.

NumPy ufuncs

pandas.NA implementa o protocolo __array_ufunc__ do NumPy. A maioria dos ufuncs trabalha com NA e geralmente retorna NA:

Em [166]: np.log(pd.NA)
Fora[166]: <NA>

Em [167]: np.add(pd.NA, 1)
Fora[167]: <NA>

Aviso: Atualmente, ufuncs envolvendo um ndarray e NA retornarão um object-dtype preenchido com valores NA.

Em [168]: a = np.array([1, 2, 3])

Em [169]: np.greater(a, pd.NA)


Out[169]: array([<NA>, <NA>, <NA>], dtype=objeto)

O tipo de retorno aqui pode mudar para retornar um tipo de array diferente no futuro.

Consulte Interoperabilidade do DataFrame com funções NumPy para obter mais informações sobre ufuncs.

628 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Conversão

Se você tiver um DataFrame ou Série usando tipos tradicionais que possuem dados ausentes representados usando np.nan, existem
métodos de conveniência convert_dtypes() em Series e convert_dtypes() em DataFrame que podem converter dados em
use os dtypes mais recentes para números inteiros, strings e booleanos listados aqui. Isso é especialmente útil depois de ler conjuntos de dados
ao permitir que leitores como read_csv() e read_excel() inferam dtypes padrão.

Neste exemplo, enquanto os dtypes de todas as colunas são alterados, mostramos os resultados das primeiras 10 colunas.

Em [170]: bb = pd.read_csv("data/baseball.csv", index_col="id")

Em [171]: bb[bb.columns[:10]].dtypes
Fora[171]:
período objeto
do ano int64
do jogador int64
equipe objeto
lg objeto
int64
g ab int64
R int64
h int64
Tipo int64
X2b: objeto

Em [172]: bbn = bb.convert_dtypes()

Em [173]: bbn[bbn.columns[:10]].dtypes
Fora[173]:
período corda
do ano Int64
do jogador Int64
equipe corda
lg corda
Int64
g ab Int64
R Int64
h Int64
Tipo Int64
X2b: objeto

2.11 Etiquetas Duplicadas

Os objetos de índice não precisam ser exclusivos; você pode ter rótulos de linha ou coluna duplicados. Isso pode ser um pouco confuso
inicialmente. Se você estiver familiarizado com SQL, sabe que os rótulos de linha são semelhantes a uma chave primária em uma tabela e você
nunca queira duplicatas em uma tabela SQL. Mas uma das funções dos pandas é limpar dados confusos do mundo real antes que eles cheguem a algum lugar.
sistema a jusante. E os dados do mundo real têm duplicatas, mesmo em campos que deveriam ser únicos.

Esta seção descreve como rótulos duplicados alteram o comportamento de determinadas operações e como evitam que duplicados
surjam durante as operações, ou para detectá-los, caso surjam.

2.11. Etiquetas duplicadas 629


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [1]: importar pandas como pd

Em [2]: importe numpy como np

2.11.1 Consequências de Etiquetas Duplicadas

Alguns métodos pandas (Series.reindex() por exemplo) simplesmente não funcionam com duplicatas presentes. A saída não pode ser
determinado, e assim os pandas aumentam.

Em [3]: s1 = pd.Series([0, 1, 2], índice=["a", "b", "b"])

Em [4]: s1.reindex(["a", "b", "c"])


-------------------------------------------------- -------------------------

Entrada Traceback (última chamada mais recente)


ValueError em [4], em <linha de célula: 1>()
----> 1 s1.reindex(["a", "b", "c"])

Arquivo /pandas/pandas/core/series.py:4672, em Series.reindex(self, *args, **kwargs)


4668 aumentar TypeError(
4669 "'índice' passado como argumento posicional e de palavra-chave"
4670 )
4671 kwargs.update({"índice": índice})
-> 4672 retornar super().reindex(**kwargs)

Arquivo /pandas/pandas/core/generic.py:4966, em NDFrame.reindex(self, *args, **kwargs)


4963 retornar self._reindex_multi(eixos, cópia, fill_value)
4965 #realiza a reindexação nos eixos
-> 4966 retornar self._reindex_axes(
4967 eixos, nível, limite, tolerância, método, fill_value, copiar
4968 ).__finalize__(self, método="reindex")

Arquivo /pandas/pandas/core/generic.py:4986, em NDFrame._reindex_axes(self, axes, level,ÿ


ÿÿlimite, tolerância, método, fill_value, cópia)
4981 novo_index, indexador = ax.reindex(
4982 rótulos, nível=nível, limite=limite, tolerância=tolerância, método=método
4983 )
Eixo 4985 = self._get_axis_number (a)
-> 4986 obj = obj._reindex_with_indexers(
4987 {eixo: [novo_índice, indexador]},
4988 valor_preenchimento=valor_preenchimento,
4989 copiar=copiar,
4990 permitir_dups=Falso,
4991 )
4992 # Se fizemos uma cópia uma vez, não há necessidade de fazer outra
4993 cópia = Falso

Arquivo /pandas/pandas/core/generic.py:5032, em NDFrame._reindex_with_indexers(self,ÿ


ÿÿreindexadores, fill_value, copiar, permitir_dups)
5029 indexador = garantir_plataforma_int(indexador)
5031 # TODO: acelerar objetos DataFrame homogêneos (consulte _reindex_multi)
-> 5032 novos_dados = new_data.reindex_indexer(
(continua na próxima página)

630 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

5033 índice,
5034 indexador,
5035 eixo = baxis,
5036 valor_preenchimento=valor_preenchimento,
5037 permitir_dups=allow_dups,
5038 copiar=copiar,
5039 )
5040 # Se já fizemos uma cópia uma vez, não há necessidade de fazer outra
5041 cópia = Falso

Arquivo /pandas/pandas/core/internals/managers.py:676, em BaseBlockManager.reindex_


ÿÿindexador(self, novo_eixo, indexador, eixo, valor_de_preenchimento, permitir_dups, copiar, consolidar, somente_
ÿÿfatia, use_na_proxy)
674 # alguns eixos não permitem reindexação com dups
675 se não permitir_dups:
--> 676 self.axes[axis]._validate_can_reindex(indexador)
678 se eixo >= self.ndim:
679 raise IndexError(" Eixo solicitado não encontrado no gerenciador")

Arquivo /pandas/pandas/core/indexes/base.py:4121, em Index._validate_can_reindex(self,ÿ


ÿÿindexador)
4119 # tentando reindexar em um eixo com duplicatas
4120 se não for self._index_as_unique e len(indexador):
-> 4121 raise ValueError("não é possível reindexar em um eixo com rótulos duplicados")

ValueError: não é possível reindexar em um eixo com rótulos duplicados

Outros métodos, como a indexação, podem dar resultados muito surpreendentes. Normalmente, a indexação com um escalar reduzirá a
dimensionalidade. Fatiar um DataFrame com um escalar retornará uma Série. Fatiar uma série com um escalar retornará um escalar. Mas
com duplicatas, esse não é o caso.

Em [5]: df1 = pd.DataFrame([[0, 1, 2], [3, 4, 5]], colunas=["A", "A", "B"])

Em [6]: df1
Fora[6]:
AAB
0012
1345

Temos duplicatas nas colunas. Se fatiarmos 'B', receberemos de volta uma Série

Em [7]: df1["B"] # uma série


Fora[7]:
0 2
1 5

Nome: B, dtype: int64

Mas fatiar 'A' retorna um DataFrame

Em [8]: df1["A"] # um DataFrame


Fora[8]:
AA
(continua na próxima página)

2.11. Etiquetas duplicadas 631


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


001
134

Isso também se aplica a rótulos de linha

Em [9]: df2 = pd.DataFrame({"A": [0, 1, 2]}, index=["a", "a", "b"])

Em [10]: df2
Fora[10]:
A
a0
a1
b2

In [11]: df2.loc["b", "A"] # a escalar Out[11]: 2

In [12]: df2.loc["a", "A"] # a Série Out[12]: 0

a
a 1
Nome: A, dtype: int64

2.11.2 Detecção de rótulos duplicados

Você pode verificar se um índice (armazenando os rótulos de linha ou coluna) é exclusivo com Index.is_unique:

Em [13]: df2
Fora[13]:
A
um 0
um 1
b2

In [14]: df2.index.is_unique Out[14]:


Falso

In [15]: df2.columns.is_unique Out[15]:


Verdadeiro

Nota: Verificar se um índice é exclusivo é um tanto caro para grandes conjuntos de dados. O pandas armazena esse resultado em cache,
portanto, verificar novamente o mesmo índice é muito rápido.

Index.duplicated() retornará um ndarray booleano indicando se um rótulo é repetido.

Em [16]: df2.index.duplicated()
Fora[16]: array([Falso, Verdadeiro, Falso])

Que pode ser usado como um filtro booleano para eliminar linhas duplicadas.

632 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [17]: df2.loc[~df2.index.duplicated(),: ]
Fora[17]:
A
um 0
b2

Se você precisar de lógica adicional para lidar com rótulos duplicados, em vez de apenas descartar as repetições, usar groupby()
no índice é um truque comum. Por exemplo, resolveremos duplicatas calculando a média de todas as linhas com o mesmo rótulo.

Em [18]: df2.groupby(level=0).mean()
Fora[18]:

A a 0,5
b 2,0

2.11.3 Proibindo rótulos duplicados


Novo na versão 1.2.0.

Conforme observado acima, o tratamento de duplicatas é um recurso importante na leitura de dados brutos. Dito isso,
você pode evitar a introdução de duplicatas como parte de um pipeline de processamento de dados (de métodos como
pandas.concat(), rename(), etc.). Tanto Series quanto DataFrame não permitem rótulos duplicados chamando .
set_flags(allows_duplicate_labels=Falso). (o padrão é permiti-los). Se houver rótulos duplicados, uma exceção será gerada.

Em [19]: pd.Series([0, 1, 2], index=["a", "b", "b"]).set_flags(allows_duplicate_ ÿÿlabels=False)

-------------------------------------------------- -------------------------

DuplicateLabelError Traceback (última chamada mais recente)


Entrada em [19], em <linha de célula: 1>() ----
> 1 pd.Series([0, 1, 2], index=["a", "b", "b"]) .set_flags(allows_duplicate_ ÿÿlabels=Falso)

Arquivo /pandas/pandas/core/generic.py:438, em NDFrame.set_flags(self, copy, permite_ ÿÿduplicate_labels)


436 df =
self.copy(deep=copy) 437
seallows_duplicate_labels não for Nenhum: --> 438 439
retorno df df.flags["allows_duplicate_labels"] = allows_duplicate_labels

Arquivo /pandas/pandas/core/flags.py:105, em Flags.__setitem__(self, key, value) 103 se a chave não


estiver em self._keys: raise ValueError(f"
Sinalizador desconhecido {chave}. Deve ser um de { self._keys}") 104
-> 105 setattr(self, chave, valor)

Arquivo /pandas/pandas/core/flags.py:92, em Flags.allows_duplicate_labels(self, value) 90 se não for valor: para ax


em obj.axes:
91 ax._maybe_check_unique()
---> 92
94 self._allows_duplicate_labels = valor

Arquivo /pandas/pandas/core/indexes/base.py:715, em Index._maybe_check_unique(self)


(continua na próxima página)

2.11. Etiquetas duplicadas 633


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

712 duplicatas = self._format_duplicate_message() 713 msg +=


f"\n{duplicatas}" --> 715 raise
DuplicateLabelError(msg)

DuplicateLabelError: o índice possui duplicatas. posições

rótulo
b [1, 2]

Isso se aplica a rótulos de linha e coluna para um DataFrame

Em [20]: pd.DataFrame([[0, 1, 2], [3, 4, 5]], colunas=["A", "B", "C"],).set_flags(allows_duplicate_labels=False


....:
....: )
....:
Fora[20]:
ABC 0 0
121345

Este atributo pode ser verificado ou definido comallows_duplicate_labels, que indica se aquele objeto pode ter
rótulos duplicados.

Em [21]: df = pd.DataFrame({"A": [0, 1, 2, 3]}, index=["x", "y", "X", "Y"]).set_flags( permite_duplicate_labels=Falso


....:
....: )
....:

Em [22]: df
Fora[22]:

Ax0
e1
X2
A3

In [23]: df.flags.allows_duplicate_labels Out[23]: Falso

DataFrame.set_flags() pode ser usado para retornar um novo DataFrame com atributos comoallows_duplicate_labels definidos
com algum valor

Em [24]: df2 = df.set_flags(allows_duplicate_labels=True)

In [25]: df2.flags.allows_duplicate_labels Out[25]: Verdadeiro

O novo DataFrame retornado é uma visualização dos mesmos dados do antigo DataFrame. Ou a propriedade pode ser definida
diretamente no mesmo objeto

Em [26]: df2.flags.allows_duplicate_labels = False

(continua na próxima página)

634 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [27]: df2.flags.allows_duplicate_labels
Fora[27]: Falso

Ao processar dados brutos e confusos, você pode inicialmente ler os dados confusos (que potencialmente possuem rótulos duplicados),
desduplicar e, em seguida, proibir duplicatas daqui para frente, para garantir que seu pipeline de dados não introduza duplicatas.

>>> bruto = pd.read_csv("...")


>>> deduplicado = raw.groupby(level=0).first() # remove duplicatas
>>> deduplicated.flags.allows_duplicate_labels = False # proibir daqui para frente

Definir permite_duplicate_labels=True em uma série ou DataFrame com rótulos duplicados ou executar uma operação que
introduz rótulos duplicados em uma série ou DataFrame que não permite duplicatas gerará erros.
DuplicateLabelError.

Em [28]: df.rename(str.upper)
-------------------------------------------------- -------------------------

Entrada DuplicateLabelError Traceback (última chamada mais recente)


em [28], em <linha de célula: 1>()
----> 1 df.renomear(str.superior)

Arquivo /pandas/pandas/core/frame.py:5086, em DataFrame.rename(self, mapper, index, columns,


ÿÿ eixo, copiar, inserir, nível, erros)
4967 def renomear(
4968 eu mesmo,

4969 mapeador: Renomeador | Nenhum = Nenhum,


(...)
4977 erros: str = "ignorar",
4978 ) -> DataFrame | Nenhum:
"""
4979
4980 Altere os rótulos dos eixos.
4981
(...)
5084 436
"""
5085
-> 5086 retornar super()._rename(
5087 mapeador = mapeador,
5088 índice = índice,
5089 colunas=colunas,
5090 eixo=eixo,
5091 copiar=copiar,
5092 inplace = inplace,
5093 nível = nível,
5094 erros = erros,
5095 )

Arquivo /pandas/pandas/core/generic.py:1163, em NDFrame._rename(self, mapper, index,ÿ


ÿÿcolunas, eixo, cópia, inserção, nível, erros)
1161 retornar Nenhum
1162 mais:
-> 1163 retornar resultado.__finalize__(self, método="renomear")

Arquivo /pandas/pandas/core/generic.py:5541, em NDFrame.__finalize__(self, other, method,ÿ


ÿÿ**kwargs)
(continua na próxima página)

2.11. Etiquetas duplicadas 635


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

5538 para nome em other.attrs:


5539 self.attrs[nome] = outro.attrs[nome]
-> 5541 self.flags.allows_duplicate_labels = other.flags.allows_duplicate_labels
5542 # Para subclasses usando _metadata.
5543 para nome em set(self._metadata) & set(other._metadata):

Arquivo /pandas/pandas/core/flags.py:92, em Flags.allows_duplicate_labels(self, value)


90 se não for valor:
91 para machado em obj.axes:
---> 92 machado._maybe_check_unique()
94 self._allows_duplicate_labels = valor

Arquivo /pandas/pandas/core/indexes/base.py:715, em Index._maybe_check_unique(self)


712 duplicatas = self._format_duplicate_message()
713 msg += f"\n{duplicatas}"
-> 715 aumentar DuplicateLabelError (msg)

DuplicateLabelError: o índice possui duplicatas.


posições
rótulo
X [0, 2]
S [1, 3]

Esta mensagem de erro contém os rótulos duplicados e as posições numéricas de todas as duplicatas (incluindo
o “original”) na Série ou DataFrame

Propagação de rótulos duplicados

Em geral, proibir duplicatas é “pegajoso”. É preservado por meio de operações.

Em [29]: s1 = pd.Series(0, index=["a", "b"]).set_flags(allows_duplicate_labels=False)

Em [30]: s1
Fora[30]:
a 0
0
tipo b: int64

Em [31]: s1.head().rename({"a": "b"})


-------------------------------------------------- -------------------------

Entrada DuplicateLabelError Traceback (última chamada mais recente)


em [31], em <linha de célula: 1>()
----> 1 s1.head().rename({"a": "b"})

Arquivo /pandas/pandas/core/series.py:4601, em Series.rename(self, index, axis, copy,ÿ


ÿÿinplace, nível, erros)
Eixo 4598 = self._get_axis_number(eixo)
4600 se chamável(índice) ou is_dict_like(índice):
-> 4601 retornar super()._rename(
4602 índice, cópia=cópia, inplace=inplace, nível=nível, erros=erros
4603 )
(continua na próxima página)

636 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


4604 mais:
4605 retornar self._set_name(index, inplace=inplace)

Arquivo /pandas/pandas/core/generic.py:1163, em NDFrame._rename(self, mapper, index,ÿ ÿÿcolumns, axis, copy,


inplace, level, erros) return Nenhum
1161
1162 mais:
-> 1163 retornar resultado.__finalize__(self, método="renomear")

Arquivo /pandas/pandas/core/generic.py:5541, em NDFrame.__finalize__(self, other, method,ÿ ÿÿ**kwargs) 5538 para nome


em other.attrs:
5539
self.attrs[nome] = outro.attrs[nome]
-> 5541 self.flags.allows_duplicate_labels = other.flags.allows_duplicate_labels 5542 # Para subclasses usando
_metadata. 5543 para nome em set(self._metadata) &
set(other._metadata):

Arquivo /pandas/pandas/core/flags.py:92, em Flags.allows_duplicate_labels(self, value) 90 se não for valor: para ax em


obj.axes: 91 ---> 92
94 ax._maybe_check_unique()
self._allows_duplicate_labels = valor

Arquivo /pandas/pandas/core/indexes/base.py:715, em Index._maybe_check_unique(self) 712 duplicatas =


self._format_duplicate_message() 713 msg += f"\n{duplicates}" --> 715
raise DuplicateLabelError( mensagem)

DuplicateLabelError: o índice possui duplicatas. posições

rótulo
b [0, 1]

Aviso: Atualmente,Este é um
muitos recursonão
métodos experimental.
conseguem propagar o valorallows_duplicate_labels. Em versões futuras, espera-se
que cada método que receba ou retorne um ou mais objetos DataFrame ou Series propague Allows_duplicate_labels.

2.12 Dados categóricos

Esta é uma introdução ao tipo de dados categóricos do pandas, incluindo uma breve comparação com o fator R.

Categóricos são um tipo de dados pandas correspondente a variáveis categóricas em estatísticas. Uma variável categórica assume
um número limitado e geralmente fixo de valores possíveis (categorias; níveis em R). Exemplos são género, classe social, tipo
sanguíneo, afiliação ao país, tempo de observação ou classificação através de escalas Likert.

Em contraste com as variáveis categóricas estatísticas, os dados categóricos podem ter uma ordem (por exemplo, 'concordo fortemente'
vs 'concordo' ou 'primeira observação' vs. 'segunda observação'), mas as operações numéricas (adições, divisões,...) não são possível.

Todos os valores dos dados categóricos estão em categorias ou np.nan. A ordem é definida pela ordem das categorias, não pela
ordem lexical dos valores. Internamente, a estrutura de dados consiste em um array de categorias e um array inteiro de códigos
que apontam para o valor real no array de categorias.

2.12. Dados categóricos 637


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

O tipo de dados categórico é útil nos seguintes casos:

• Uma variável de string que consiste apenas em alguns valores diferentes. Convertendo tal variável de string em uma categórica
variável economizará um pouco de memória, veja aqui.

• A ordem lexical de uma variável não é igual à ordem lógica (“um”, “dois”, “três”). Ao converter para categórico e especificar uma
ordem nas categorias, a classificação e min/max usarão a ordem lógica em vez da ordem lexical, veja aqui.

• Como um sinal para outras bibliotecas Python de que esta coluna deve ser tratada como uma variável categórica (por exemplo, para usar
métodos estatísticos ou tipos de gráficos adequados).

Consulte também a documentação da API sobre categorias.

2.12.1 Criação de objeto

Criação de série

Séries categóricas ou colunas em um DataFrame podem ser criadas de várias maneiras:

Ao especificar dtype="category" ao construir uma série:

Em [1]: s = pd.Series(["a", "b", "c", "a"], dtype="category")

Em [2]: s
Fora[2]: 0
a
b
c
a
1 2 3 dtype: categoria
Categorias (3, objeto): ['a', 'b', 'c']

Ao converter uma série ou coluna existente em um tipo de categoria:

Em [3]: df = pd.DataFrame({"A": ["a", "b", "c", "a"]})

Em [4]: df["B"] = df["A"].astype("categoria")

Em [5]: df
Fora[5]:
AB
0 aa 1 bb
2 cc 3 aa

Usando funções especiais, como cut(), que agrupa dados em compartimentos discretos. Veja o exemplo de ladrilho na documentação.

Em [6]: df = pd.DataFrame({"valor": np.random.randint(0, 100, 20)})

Em [7]: rótulos = ["{0} - {1}".format(i, i + 9) para i no intervalo(0, 100, 10)]

Em [8]: df["group"] = pd.cut(df.value, range(0, 105, 10), right=False, rótulos=rótulos)

(continua na próxima página)

638 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [9]: df.head(10)
Fora[9]:
valor grupo
0 65 60 - 69
1 49 40 - 49
2 56 50 - 59
3 43 40 - 49
4 43 40 - 49
5 91 90 - 99
6 32 30 - 39
7 87 80 - 89
8 36 30 - 39
9 8 0-9

Passando um objeto pandas.Categorical para uma Série ou atribuindo-o a um DataFrame.

Em [10]: raw_cat = pd.Categorical(


....: ["a", "b", "c", "a"], categorias=["b", "c", "d"], ordenado=Falso
....: )
....:

Em [11]: s = pd.Series(raw_cat)

Em [12]: s
Fora[12]:
0 NaN
1 b
2 c
NaN
3 dtipo: categoria
Categorias (3, objeto): ['b', 'c', 'd']

Em [13]: df = pd.DataFrame({"A": ["a", "b", "c", "a"]})

Em [14]: df["B"] = raw_cat

Em [15]: df
Fora[15]:
A B
0 por NaN
1b b
2c c
3 um NaN

Os dados categóricos têm um tipo de categoria específico:

Em [16]: df.dtypes
Fora[16]:
A objeto
B categoria
dtype: objeto

2.12. Dados categóricos 639


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Criação de DataFrame

Semelhante à seção anterior, onde uma única coluna foi convertida em categórica, todas as colunas em um DataFrame podem
ser convertido em lote para categórico durante ou após a construção.

Isso pode ser feito durante a construção especificando dtype="category" no construtor DataFrame:

Em [17]: df = pd.DataFrame({"A": list("abca"), "B": list("bccd")}, dtype="category")

Em [18]: df.dtypes
Fora[18]:
A categoria
B categoria
dtype: objeto

Observe que as categorias presentes em cada coluna são diferentes; a conversão é feita coluna por coluna, então apenas os rótulos estão presentes
em uma determinada coluna estão as categorias:

Em [19]: df["A"]
Fora[19]:
0 a
1 b
2 c
3 a
Nome: A, dtype: categoria
Categorias (3, objeto): ['a', 'b', 'c']

Em [20]: df["B"]
Fora[20]:
0b
1 c
2 c
3 d
Nome: B, dtype: categoria
Categorias (3, objeto): ['b', 'c', 'd']

Analogamente, todas as colunas em um DataFrame existente podem ser convertidas em lote usando DataFrame.astype():

Em [21]: df = pd.DataFrame({"A": list("abca"), "B": list("bccd")})

Em [22]: df_cat = df.astype("categoria")

Em [23]: df_cat.dtypes
Fora[23]:
A categoria
B categoria
dtype: objeto

Esta conversão também é feita coluna por coluna:

Em [24]: df_cat["A"]
Fora[24]:
0 a
1 b
(continua na próxima página)

640 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

2 c
3 a
Nome: A, dtype: categoria
Categorias (3, objeto): ['a', 'b', 'c']

Em [25]: df_cat["B"]
Fora[25]:
0 b
1 c
2 c
3d
Nome: B, dtype: categoria
Categorias (3, objeto): ['b', 'c', 'd']

Controlando o comportamento

Nos exemplos acima onde passamos dtype='category', usamos o comportamento padrão:

1. As categorias são inferidas a partir dos dados.

2. As categorias não são ordenadas.

Para controlar esses comportamentos, em vez de passar 'categoria', use uma instância de CategoricalDtype.

Em [26]: de pandas.api.types import CategoricalDtype

Em [27]: s = pd.Series(["a", "b", "c", "a"])

Em [28]: cat_type = CategoricalDtype(categories=["b", "c", "d"], ordenado=True)

Em [29]: s_cat = s.astype(cat_type)

Em [30]: s_cat
Fora[30]:
0 NaN
1b
2 c
3 NaN
tipo: categoria
Categorias (3, objeto): ['b' < 'c' < 'd']

Da mesma forma, um CategoricalDtype pode ser usado com um DataFrame para garantir que as categorias sejam consistentes entre todos
colunas.

Em [31]: de pandas.api.types import CategoricalDtype

Em [32]: df = pd.DataFrame({"A": list("abca"), "B": list("bccd")})

Em [33]: cat_type = CategoricalDtype(categories=list("abcd"), ordenado=True)

Em [34]: df_cat = df.astype(cat_type)

Em [35]: df_cat["A"]
(continua na próxima página)

2.12. Dados categóricos 641


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[35]:
0 a
1 b
2 c
3 a
Nome: A, dtype: categoria
Categorias (4, objeto): ['a' < 'b' < 'c' < 'd']

Em [36]: df_cat["B"]
Fora[36]:
0b
1 c
2 c
3d

Nome: B, dtype: categoria


Categorias (4, objeto): ['a' < 'b' < 'c' < 'd']

Nota: Para realizar a conversão em tabela, onde todos os rótulos em todo o DataFrame são usados como categorias para
cada coluna, o parâmetro categorias pode ser determinado programaticamente por categorias = pd.unique(df.
to_numpy().ravel()).

Se você já possui códigos e categorias, você pode usar o construtor from_codes() para salvar a etapa de fatoração
durante o modo construtor normal:

Em [37]: divisor = np.random.choice([0, 1], 5, p=[0,5, 0,5])

Em [38]: s = pd.Series(pd.Categorical.from_codes(splitter, categorias=["train", "test"]))

Recuperando dados originais

Para voltar ao array original Series ou NumPy, use Series.astype(original_dtype) ou np.


asarray(categórico):

Em [39]: s = pd.Series(["a", "b", "c", "a"])

Em [40]: s
Fora[40]:
0 a
1 b
2 c
3 a
dtype: objeto

Em [41]: s2 = s.astype("categoria")

Em [42]: s2
Fora[42]:
0 a
1 b
2 c
(continua na próxima página)

642 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

a
3 dtipo: categoria
Categorias (3, objeto): ['a', 'b', 'c']

Em [43]: s2.astype(str)
Fora[43]:
0 a
1 b
2 c
3 a
dtype: objeto

Em [44]: np.asarray(s2)
Out[44]: array(['a', 'b', 'c', 'a'], dtype=objeto)

Nota: Em contraste com a função de fator de R, os dados categóricos não convertem valores de entrada em strings; as categorias
terminarão com o mesmo tipo de dados dos valores originais.

Nota: Em contraste com a função de fator de R, atualmente não há como atribuir/alterar rótulos no momento da criação. Use
categorias para alterar as categorias após o momento da criação.

2.12.2 Tipo Categórico

O tipo de uma categoria é totalmente descrito por

1. categorias: uma sequência de valores únicos e sem valores ausentes


2. ordenado: um booleano

Essas informações podem ser armazenadas em um CategoricalDtype. O argumento categorias é opcional, o que implica que as
categorias reais devem ser inferidas a partir de tudo o que está presente nos dados quando o pandas.Categorical é criado.
As categorias são consideradas não ordenadas por padrão.

Em [45]: de pandas.api.types import CategoricalDtype

Em [46]: CategoricalDtype(["a", "b", "c"])


Out[46]: CategoricalDtype(categories=['a', 'b', 'c'], ordenado=Falso)

Em [47]: CategoricalDtype(["a", "b", "c"], ordenado = Verdadeiro)


Out[47]: CategoricalDtype(categories=['a', 'b', 'c'], ordenado=True)

Em [48]: CategóricoDtype()
Out[48]: CategoricalDtype(categories=Nenhum, ordenado=Falso)

Um CategoricalDtype pode ser usado em qualquer lugar onde o pandas espera um dtype. Por exemplo pandas.read_csv(), pandas.
DataFrame.astype() ou no construtor Series.

Nota: Por conveniência, você pode usar a string 'category' no lugar de CategoricalDtype quando desejar que o comportamento
padrão das categorias seja desordenado e igual aos valores definidos presentes na matriz. Em outras palavras,

2.12. Dados categóricos 643


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

dtype='categoria' é equivalente a dtype=CategoricalDtype().

Semântica de igualdade

Duas instâncias de CategoricalDtype são comparadas iguais sempre que têm as mesmas categorias e ordem. Ao comparar
duas categóricas não ordenadas, a ordem das categorias não é considerada.

Em [49]: c1 = CategoricalDtype(["a", "b", "c"], ordenado=Falso)

# Igual, pois o pedido não é considerado quando ordenado=Falso


Em [50]: c1 == CategoricalDtype(["b", "c", "a"], ordenado=Falso)
Fora[50]: Verdadeiro

# Desigual, já que o segundo CategoricalDtype está ordenado


Em [51]: c1 == CategoricalDtype(["a", "b", "c"], ordenado = Verdadeiro)
Fora[51]: Falso

Todas as instâncias de CategoricalDtype são comparadas iguais à string 'categoria'.

Em [52]: c1 == "categoria"
Fora[52]: Verdadeiro

Aviso: como dtype='category' é essencialmente CategoricalDtype(None, False) e como todas as instâncias CategoricalDtype
são comparadas iguais a 'category', todas as instâncias de CategoricalDtype são comparadas iguais a CategoricalDtype(None,
False), independentemente das categorias ou ordenadas.

2.12.3 Descrição

Usar description() em dados categóricos produzirá uma saída semelhante a uma Series ou DataFrame do tipo string.

Em [53]: cat = pd.Categorical(["a", "c", "c", np.nan], categorias=["b", "a", "c"])

Em [54]: df = pd.DataFrame({"cat": cat, "s": ["a", "c", "c", np.nan]})

Em [55]: df.describe()
Fora[55]:
gatos
contar 33
frequência superior
CC

única 2 2 22

Em [56]: df["cat"].describe()
Fora[56]:
contar 3
frequência 2
c
superior única 2
Nome: gato, dtype: objeto

644 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.12.4 Trabalhando com categorias

Os dados categóricos possuem categorias e uma propriedade ordenada, que listam seus valores possíveis e se a ordem é
importante ou não. Essas propriedades são expostas como s.cat.categories e s.cat.ordered. Se você não especificar
manualmente as categorias e a ordem, elas serão inferidas dos argumentos passados.

Em [57]: s = pd.Series(["a", "b", "c", "a"], dtype="category")

Em [58]: s.cat.categories Out[58]:


Index(['a', 'b', 'c'], dtype='object')

In [59]: s.cat.ordered Out[59]:


Falso

Também é possível passar nas categorias em uma ordem específica:

Em [60]: s = pd.Series(pd.Categorical(["a", "b", "c", "a"], categorias=["c", "b", "a"]))

Em [61]: s.cat.categories Fora[61]:


Índice(['c', 'b', 'a'], dtype='objeto')

In [62]: s.cat.ordered Out[62]:


Falso

Nota: Novos dados categóricos não são ordenados automaticamente. Você deve passar explicitamente order=True para indicar
um categórico ordenado.

Nota: O resultado de unique() nem sempre é o mesmo que Series.cat.categories, porque Series.unique() tem algumas garantias,
nomeadamente que retorna categorias na ordem de aparição e inclui apenas valores que são realmente presente.

Em [63]: s = pd.Series(list("babc")).astype(CategoricalDtype(list("abcd")))

Em [64]: s
Fora[64]: 0
b
1 a
2 b
3 c
tipo: categoria
Categorias (4, objeto): ['a', 'b', 'c', 'd']

# categorias In
[65]: s.cat.categories Out[65]: Index(['a',
'b', 'c', 'd'], dtype='object')

# únicos em
[66]: s.unique()
Fora[66]:
['b', 'a', 'c']
Categorias (4, objeto): ['a', 'b', 'c', 'd']

2.12. Dados categóricos 645


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Renomeando categorias

A renomeação de categorias é feita atribuindo novos valores à propriedade Series.cat.categories ou usando o


Método rename_categories():

Em [67]: s = pd.Series(["a", "b", "c", "a"], dtype="category")

Em [68]: s
Fora[68]:
0 a
1 b
2 c
3 a
tipo: categoria
Categorias (3, objeto): ['a', 'b', 'c']

Em [69]: s.cat.categories = ["Grupo %s" % g para g em s.cat.categories]

Em [70]: s
Fora[70]:
0 Grupo A
1 Grupo B
2 Grupo c
3 Grupo A
tipo: categoria
Categorias (3, objeto): ['Grupo a', 'Grupo b', 'Grupo c']

Em [71]: s = s.cat.rename_categories([1, 2, 3])

Em [72]: s
Fora[72]:
01
1 2
2 3
3 1
tipo: categoria
Categorias (3, int64): [1, 2, 3]

# Você também pode passar um objeto do tipo dict para mapear a renomeação
Em [73]: s = s.cat.rename_categories({1: "x", 2: "y", 3: "z"})

Em [74]: s
Fora[74]:
x
sim

z
x
0 1 2 3 dtipo: categoria
Categorias (3, objeto): ['x', 'y', 'z']

Nota: Em contraste com o fator R, os dados categóricos podem ter categorias de outros tipos além de string.

646 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Nota: Esteja ciente de que atribuir novas categorias é uma operação local, enquanto a maioria das outras operações em Series.cat
por padrão, retorne uma nova série de categoria dtype.

As categorias devem ser exclusivas ou um ValueError será gerado:

Em [75]: tente:
....: s.cat.categories = [1, 1, 1]
....: exceto ValueError como e:
....: print("Erro de valor:", str(e))
....:
ValueError: as categorias categóricas devem ser exclusivas

As categorias também não devem ser NaN ou um ValueError será gerado:

Em [76]: tente:
....: s.cat.categories = [1, 2, np.nan]
....: exceto ValueError como e:
....: print("Erro de valor:", str(e))
....:
ValueError: categorias categóricas não podem ser nulas

Anexando novas categorias

Anexar categorias pode ser feito usando o método add_categories():

Em [77]: s = s.cat.add_categories([4])

Em [78]: s.cat.categories
Out[78]: Índice(['x', 'y', 'z', 4], dtype='objeto')

Em [79]: s
Fora[79]:
x
sim

z
x
0 1 2 3 dtipo: categoria
Categorias (4, objeto): ['x', 'y', 'z', 4]

Removendo categorias

A remoção de categorias pode ser feita usando o método remove_categories(). Os valores removidos são substituídos por np.nan.:

Em [80]: s = s.cat.remove_categories([4])

Em [81]: s
Fora[81]:
0 x
1 sim

(continua na próxima página)

2.12. Dados categóricos 647


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

2 z
3 x
tipo: categoria
Categorias (3, objeto): ['x', 'y', 'z']

Removendo categorias não utilizadas

A remoção de categorias não utilizadas também pode ser feita:

Em [82]: s = pd.Series(pd.Categorical(["a", "b", "a"], categorias=["a", "b", "c", "d"]))

Em [83]: s
Fora[83]:
a
b
a
0 1 2 dtipo: categoria
Categorias (4, objeto): ['a', 'b', 'c', 'd']

Em [84]: s.cat.remove_unused_categories()
Fora[84]:
0 a
1 b
2 a
tipo: categoria
Categorias (2, objeto): ['a', 'b']

Configurando categorias

Se você quiser remover e adicionar novas categorias em uma única etapa (o que tem alguma vantagem de velocidade), ou simplesmente definir o
categorias para uma escala predefinida, use set_categories().

Em [85]: s = pd.Series(["um", "dois", "quatro", "-"], dtype="categoria")

Em [86]: s
Fora[86]:
0 um
1 dois
quatro
-

2 3 dtipo: categoria
Categorias (4, objeto): ['-', 'quatro', 'um', 'dois']

Em [87]: s = s.cat.set_categories(["um", "dois", "três", "quatro"])

Em [88]: s
Fora[88]:
0 um
1 dois
2 quatro
(continua na próxima página)

648 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

NaN
3 dtipo: categoria
Categorias (4, objeto): ['um', 'dois', 'três', 'quatro']

Nota: Esteja ciente de que Categorical.set_categories() não pode saber se alguma categoria foi omitida intencionalmente
ou porque está escrito incorretamente ou (no Python3) devido a uma diferença de tipo (por exemplo, NumPy S1 dtype e strings Python). Esse
pode resultar em um comportamento surpreendente!

2.12.5 Classificação e ordem

Se os dados categóricos forem ordenados (s.cat.ordered == True), então a ordem das categorias tem um significado e certos
operações são possíveis. Se o categórico não for ordenado, .min()/.max() gerará um TypeError.

Em [89]: s = pd.Series(pd.Categorical(["a", "b", "c", "a"], ordenado=Falso))

Em [90]: s.sort_values(inplace=True)

Em [91]: s = pd.Series(["a", "b", "c", "a"]).astype(CategoricalDtype(ordered=True))

Em [92]: s.sort_values(inplace=True)

Em [93]: s
Fora[93]:
0 a
3 a
1 b
2 c
tipo: categoria
Categorias (3, objeto): ['a' < 'b' < 'c']

Em [94]: s.min(), s.max()


Fora[94]: ('a', 'c')

Você pode definir dados categóricos para serem ordenados usando as_ordered() ou não ordenados usando as_unordered(). Esses
por padrão retornará um novo objeto.

Em [95]: s.cat.as_ordered()
Fora[95]:
0 a
a
31 b
2 c
tipo: categoria
Categorias (3, objeto): ['a' < 'b' < 'c']

Em [96]: s.cat.as_unordered()
Fora[96]:
0 a
3 a
(continua na próxima página)

2.12. Dados categóricos 649


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

1 b
2 c
tipo: categoria
Categorias (3, objeto): ['a', 'b', 'c']

A classificação usará a ordem definida pelas categorias, e não qualquer ordem lexical presente no tipo de dados. Isto é verdade até para
strings e dados numéricos:

Em [97]: s = pd.Series([1, 2, 3, 1], dtype="categoria")

Em [98]: s = s.cat.set_categories([2, 3, 1], ordenado = Verdadeiro)

Em [99]: s
Fora[99]:
01
1 2
2 3
1
3 dtipo: categoria
Categorias (3, int64): [2 <3 <1]

Em [100]: s.sort_values(inplace=True)

Em [101]: s
Fora[101]:
1 2
2 3
0 1
1
3 dtipo: categoria
Categorias (3, int64): [2 <3 <1]

Em [102]: s.min(), s.max()


Fora[102]: (2, 1)

Reordenando

Reordenar as categorias é possível por meio de Categorical.reorder_categories() e Categorical.


métodos set_categories(). Para Categorical.reorder_categories(), todas as categorias antigas devem ser incluídas em
as novas categorias e nenhuma nova categoria é permitida. Isso necessariamente tornará a ordem de classificação igual à
ordem das categorias.

Em [103]: s = pd.Series([1, 2, 3, 1], dtype="categoria")

Em [104]: s = s.cat.reorder_categories([2, 3, 1], ordenado=True)

Em [105]: s
Fora[105]:
0 1
1 2
2 3
(continua na próxima página)

650 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

1
3 dtipo: categoria
Categorias (3, int64): [2 <3 <1]

Em [106]: s.sort_values(inplace=True)

Em [107]: s
Fora[107]:
1 2
2 3
1
1
0 3 dtipo: categoria
Categorias (3, int64): [2 <3 <1]

Em [108]: s.min(), s.max()


Fora[108]: (2, 1)

Nota: Observe a diferença entre atribuir novas categorias e reordenar as categorias: a primeira renomeia as categorias
e, portanto, os valores individuais na Série, mas se a primeira posição foi classificada por último, o valor renomeado ainda será
ser classificado por último. Reordenar significa que a forma como os valores são classificados é diferente posteriormente, mas não que os valores individuais
na Série são alterados.

Nota: Se o Categórico não estiver ordenado, Series.min() e Series.max() gerarão TypeError. Numérico
operações como +, -, *, / e operações baseadas nelas (por exemplo, Series.median(), que precisariam calcular o
média entre dois valores se o comprimento de uma matriz for par) não funcionam e geram um TypeError.

Classificação de múltiplas colunas

Uma coluna de tipo categórico participará de uma classificação de múltiplas colunas de maneira semelhante a outras colunas. A encomenda
do categórico é determinado pelas categorias dessa coluna.

Em [109]: dfs = pd.DataFrame(


.....: {
.....: "A": pd.Categórico(
.....: lista("bbeebbaa"),
.....: categorias=["e", "a", "b"],
.....: ordenado = Verdadeiro,
.....: ),
.....: "B": [1, 2, 1, 2, 2, 1, 2, 1],
.....: }
..... :)
.....:

Em [110]: dfs.sort_values(by=["A", "B"])


Fora[110]:
AB
2e1
(continua na próxima página)

2.12. Dados categóricos 651


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

3e2
7a1
6a2
0b1
5b 1 1b
2 4b 2

Reordenar as categorias altera uma classificação futura.

Em [111]: dfs["A"] = dfs["A"].cat.reorder_categories(["a", "b", "e"])

Em [112]: dfs.sort_values(by=["A", "B"])


Fora[112]:
AB 7
a16a2
0b15b
1

1b2
4b2
2e1
3e2

2.12.6 Comparações

A comparação de dados categóricos com outros objetos é possível em três casos:

• Comparar a igualdade (== e !=) com um objeto semelhante a uma lista (lista, série, array, . . . ) do mesmo comprimento que o categórico
dados.

• Todas as comparações (==, !=, >, >=, < e <=) de dados categóricos com outra série categórica, quando
ordenado==Verdadeiro e as categorias são iguais.
• Todas as comparações de dados categóricos com dados escalares.

Todas as outras comparações, especialmente comparações de “não igualdade” de dois categóricos com categorias diferentes ou de um categórico
com qualquer objeto semelhante a uma lista, gerarão um TypeError.

Nota: Qualquer comparação de “não igualdade” de dados categóricos com uma série, np.array, lista ou dados categóricos com
categorias ou ordenações diferentes gerará um TypeError porque a ordenação de categorias personalizadas pode ser interpretada
de duas maneiras: uma levando em consideração o ordenando e um sem.

Em [113]: cat = pd.Series([1, 2, 3]).astype(CategoricalDtype([3, 2, 1], ordenado=True))

Em [114]: cat_base = pd.Series([2, 2, 2]).astype(CategoricalDtype([3, 2, 1],ÿ ÿÿordered=True))

Em [115]: cat_base2 = pd.Series([2, 2, 2]).astype(CategoricalDtype(ordered=True))

Em [116]: gato
(continua na próxima página)

652 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[116]:
0 1
1 2
2 3
tipo: categoria
Categorias (3, int64): [3 <2 <1]

Em [117]: cat_base
Fora[117]:
0 2
2
2
1 2 dtipo: categoria
Categorias (3, int64): [3 <2 <1]

Em [118]: cat_base2
Fora[118]:
02
12

22

tipo: categoria
Categorias (1, int64): [2]

Comparar com um categórico com as mesmas categorias e ordenação ou com um escalar funciona:

Em [119]: gato > cat_base


Fora[119]:
0 Verdadeiro

Falso
Falso
1 2 dtype: bool

Em [120]: gato > 2


Fora[120]:
0 Verdadeiro

1 Falso
2 Falso
tipo d: bool

As comparações de igualdade funcionam com qualquer objeto semelhante a uma lista de mesmo comprimento e escalares:

Em [121]: gato == cat_base


Fora[121]:
0 Falso
1 Verdadeiro

2 Falso
tipo d: bool

Em [122]: gato == np.array([1, 2, 3])


Fora[122]:
0 Verdadeiro

1 Verdadeiro

(continua na próxima página)

2.12. Dados categóricos 653


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


2 Verdadeiro

tipo d: bool

Em [123]: gato == 2
Fora[123]:
0 Falso
1 Verdadeiro

2 Falso
tipo d: bool

Isso não funciona porque as categorias não são as mesmas:

Em [124]: tente:
.....: gato > gato_base2
.....: exceto TypeError como e:
.....: print("TypeError:", str(e))
.....:
TypeError: categóricos só podem ser comparados se as 'categorias' forem iguais.

Se você quiser fazer uma comparação de “não igualdade” de uma série categórica com um objeto semelhante a uma lista que não é categórico
dados, você precisa ser explícito e converter os dados categóricos de volta aos valores originais:

Em [125]: base = np.array([1, 2, 3])

Em [126]: tente:
.....: gato > básico
.....: exceto TypeError como e:
.....: print("TypeError:", str(e))
.....:
TypeError: Não é possível comparar um categórico para op __gt__ com o tipo <class 'numpy.ndarray'>.
Se você quiser comparar valores, use 'np.asarray(cat) <op> other'.

Em [127]: np.asarray(cat) > base


Fora[127]: array([Falso, Falso, Falso])

Quando você compara duas categóricas não ordenadas com as mesmas categorias, a ordem não é considerada:

Em [128]: c1 = pd.Categorical(["a", "b"], categorias=["a", "b"], ordenado=Falso)

Em [129]: c2 = pd.Categorical(["a", "b"], categorias=["b", "a"], ordenado=Falso)

Em [130]: c1 == c2
Fora[130]: array([ Verdadeiro, Verdadeiro])

654 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.12.7 Operações

Além de Series.min(), Series.max() e Series.mode(), as seguintes operações são possíveis com dados categóricos:

Métodos de série como Series.value_counts() usarão todas as categorias, mesmo que algumas categorias não estejam presentes no
dados:

Em [131]: s = pd.Series(pd.Categorical(["a", "b", "c", "c"], categorias=["c", "a", "b",


ÿÿ"d"]))

Em [132]: s.value_counts()
Fora[132]:
c 2
a 1
1
0
bd tipo: int64

Métodos DataFrame como DataFrame.sum() também mostram categorias “não utilizadas”.

Em [133]: colunas = pd.Categorical(


.....: ["Um", "Um", "Dois"], categorias=["Um", "Dois", "Três"], ordenado=Verdadeiro
..... :)
.....:

Em [134]: df = pd.DataFrame(
.....: dados=[[1, 2, 3], [4, 5, 6]],
.....: colunas=pd.MultiIndex.from_arrays([["A", "B", "B"], colunas]),
..... :)
.....:

Em [135]: df.groupby(axis=1, level=1).sum()


Fora[135]:
Um dois três
0 3 3 0
1 9 6 0

Groupby também mostrará categorias “não utilizadas”:

Em [136]: gatos = pd.Categorical(


.....: ["a", "b", "b", "b", "c", "c", "c"], categorias=["a", "b", "c", "d"]
..... :)
.....:

Em [137]: df = pd.DataFrame({"gatos": gatos, "valores": [1, 2, 2, 2, 3, 4, 5]})

Em [138]: df.groupby("gatos").mean()
Fora[138]:
valores
gatos
a 1,0
b 2,0
c 4,0
(continua na próxima página)

2.12. Dados categóricos 655


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


d NaN

Em [139]: cats2 = pd.Categorical(["a", "a", "b", "b"], categorias=["a", "b", "c"])

Em [140]: df2 = pd.DataFrame(


.....: {
.....: "gatos": gatos2,
.....: "B": ["c", "d", "c", "d"],
.....: "valores": [1, 2, 3, 4],
.....: }
..... :)
.....:

Em [141]: df2.groupby(["gatos", "B"]).mean()


Fora[141]:
valores
gatos B
a c 1,0
d 2,0
b c 3,0
d 4,0
c c NaN
d NaN

Tabelas dinâmicas:

Em [142]: raw_cat = pd.Categorical(["a", "a", "b", "b"], categorias=["a", "b", "c"])

Em [143]: df = pd.DataFrame({"A": raw_cat, "B": ["c", "d", "c", "d"], "valores": [1, 2, 3 ,
ÿÿ 4]})

Em [144]: pd.pivot_table(df, valores="valores", índice=["A", "B"])


Fora[144]:
valores
AB
ac 1
2
3
DBCD 4

656 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.12.8 Transferência de dados

Os métodos otimizados de acesso a dados do pandas .loc, .iloc, .at e .iat funcionam normalmente. A única diferença é o
tipo de retorno (para obtenção) e que apenas valores já em categorias podem ser atribuídos.

Recebendo

Se a operação de fatiamento retornar um DataFrame ou uma coluna do tipo Series, a categoria dtype será preservada.

Em [145]: idx = pd.Index(["h", "i", "j", "k", "l", "m", "n"])

Em [146]: cats = pd.Series(["a", "b", "b", "b", "c", "c", "c"], dtype="category",ÿ
ÿÿíndice=idx)

Em [147]: valores = [1, 2, 2, 2, 3, 4, 5]

Em [148]: df = pd.DataFrame({"gatos": gatos, "valores": valores}, índice=idx)

Em [149]: df.iloc[2:4,: ]
Fora[149]:
valores de gatos
b 2
brincadeira b 2

Em [150]: df.iloc[2:4, :].dtypes


Fora[150]:
gatos categoria
valores int64
dtype: objeto

Em [151]: df.loc["h":"j", "gatos"]


Fora[151]:
a
b
b
hij Nome: gatos, dtype: categoria
Categorias (3, objeto): ['a', 'b', 'c']

Em [152]: df[df["gatos"] == "b"]


Fora[152]:
valores de gatos
eu b 2
b 2
brincadeira b 2

Um exemplo em que o tipo de categoria não é preservado é se você pegar uma única linha: a série resultante é do tipo d
objeto:

# obtém a linha "h" completa como uma série


Em [153]: df.loc["h",: ]
Fora[153]:
gatos a
(continua na próxima página)

2.12. Dados categóricos 657


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

valores 1
Nome: h, dtype: objeto

Retornar um único item de dados categóricos também retornará o valor, não um categórico de comprimento “1”.

Em [154]: df.iat[0, 0]
Fora[154]: 'a'

Em [155]: df["cats"].cat.categories = ["x", "y", "z"]

Em [156]: df.at["h", "cats"] # retorna uma string


Fora[156]: 'x'

Nota: A está em contraste com a função de fator de R, onde factor(c(1,2,3))[1] retorna um fator de valor único.

Para obter uma série de valor único do tipo categoria, você passa uma lista com um único valor:

Em [157]: df.loc[["h"], "gatos"]


Fora[157]:
h x
Nome: gatos, dtype: categoria
Categorias (3, objeto): ['x', 'y', 'z']

Acessadores de string e data e hora

Os acessadores .dt e .str funcionarão se s.cat.categories forem de um tipo apropriado:

Em [158]: str_s = pd.Series(list("aabb"))

Em [159]: str_cat = str_s.astype("categoria")

Em [160]: str_cat
Fora[160]:
0 a
1 a
2 b
3 b
tipo: categoria
Categorias (2, objeto): ['a', 'b']

Em [161]: str_cat.str.contains("a")
Fora[161]:
0 Verdadeiro

1 Verdadeiro

2 Falso
3 Falso
tipo d: bool

Em [162]: data_s = pd.Series(pd.date_range("1/1/2015", períodos=5))

(continua na próxima página)

658 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [163]: date_cat = date_s.astype("categoria")

Em [164]: data_cat
Fora[164]:
0 01/01/2015
12015-01-02
2 03/01/2015
3 04/01/2015
4 05/01/2015
tipo: categoria
Categorias (5, datetime64[ns]): [2015-01-01, 2015-01-02, 2015-01-03, 2015-01-04, 2015-01- ÿÿ05]

In [165]: date_cat.dt.day Out[165]:


011223
3445
dtype:
int64

Nota: A Série retornada (ou DataFrame) é do mesmo tipo como se você usasse .str.<method> / .dt.<method> em uma Série
desse tipo (e não da categoria de tipo!).

Isso significa que os valores retornados dos métodos e propriedades dos acessadores de uma Série e os valores retornados dos
métodos e propriedades dos acessadores desta Série transformados para um do tipo categoria serão iguais:

Em [166]: ret_s = str_s.str.contains("a")

Em [167]: ret_cat = str_cat.str.contains("a")

Em [168]: ret_s.dtype == ret_cat.dtype Out[168]:


Verdadeiro

Em [169]: ret_s == ret_cat


Fora[169]: 0
Verdadeiro

1 Verdadeiro

2 Verdadeiro

3 Verdadeiro

tipo d: bool

Nota: O trabalho é feito nas categorias e em seguida é construída uma nova Série. Isso tem algumas implicações no desempenho
se você tiver uma Série do tipo string, onde muitos elementos são repetidos (ou seja, o número de elementos únicos na Série é
muito menor que o comprimento da Série). Nesse caso, pode ser mais rápido converter a série original em uma categoria de tipo
e usar .str.<method> ou .dt.<property> nisso.

2.12. Dados categóricos 659


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Contexto

Definir valores em uma coluna categórica (ou série) funciona desde que o valor esteja incluído nas categorias:

Em [170]: idx = pd.Index(["h", "i", "j", "k", "l", "m", "n"])

Em [171]: gatos = pd.Categorical(["a", " a", "a", "a", "a", "a", "a"], categorias=["a", "b
ÿÿ"])

Em [172]: valores = [1, 1, 1, 1, 1, 1, 1]

Em [173]: df = pd.DataFrame({"gatos": gatos, "valores": valores}, índice=idx)

Em [174]: df.iloc[2:4, :] = [["b", 2], ["b", 2]]

Em [175]: df
Fora[175]:
valores de gatos
a 1
a 1
2
bb 2
hijkl a 1
mãe 1
n a 1

Em [176]: tente:
.....: df.iloc[2:4, :] = [["c", 3], ["c", 3]]
.....: exceto TypeError como e:
.....: print("TypeError:", str(e))
.....:
TypeError: Não é possível definir o item em um categórico com uma nova categoria, defina as categorias primeiro

Definir valores atribuindo dados categóricos também verificará se as categorias correspondem:

Em [177]: df.loc["j":"k", "cats"] = pd.Categorical(["a", "a"], categorias=["a", "b"])

Em [178]: df
Fora[178]:
valores de gatos
a 1
a 1
a 2
a 2
hijkl a 1
mãe 1
n a 1

Em [179]: tente:
.....: df.loc["j":"k", "gatos"] = pd.Categorical(["b", "b"], categorias=["a", "b",
ÿÿ"c"])
.....: exceto TypeError como e:
.....: print("TypeError:", str(e))
.....:
(continua na próxima página)

660 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

TypeError: Não é possível definir um Categórico com outro, sem categorias idênticas

Atribuir um Categórico a partes de uma coluna de outros tipos utilizará os valores:

Em [180]: df = pd.DataFrame({"a": [1, 1, 1, 1, 1], "b": ["a", "a", "a", "a", " a"]})

Em [181]: df.loc[1:2, "a"] = pd.Categorical(["b", "b"], categorias=["a", "b"])

Em [182]: df.loc[2:3, "b"] = pd.Categorical(["b", "b"], categorias=["a", "b"])

Em [183]: df
Fora[183]:
ab 0
1 a 1 ba
2 bb 3 1
b

4 1 uma

In [184]: df.dtypes
Out[184]:
a objeto
b objeto dtype:
objeto

Mesclagem/concatenação

Por padrão, combinar Series ou DataFrames que contêm as mesmas categorias resulta em categoria dtype, caso contrário, os
resultados dependerão do dtype das categorias subjacentes. As mesclagens que resultam em dtypes não categóricos
provavelmente terão maior uso de memória. Use .astype ou union_categoricals para garantir resultados de categoria.

Em [185]: de pandas.api.types import union_categoricals

# mesmas categorias
em [186]: s1 = pd.Series(["a", "b"], dtype="category")

Em [187]: s2 = pd.Series(["a", "b", "a"], dtype="category")

Em [188]: pd.concat([s1, s2])


Fora[188]: 0
a
b
10 a
1 b
2 a
tipo: categoria
Categorias (2, objeto): ['a', 'b']

# categorias diferentes em
[189]: s3 = pd.Series(["b", "c"], dtype="category")

(continua na próxima página)

2.12. Dados categóricos 661


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [190]: pd.concat([s1, s3])


Fora[190]:
0 a
1 b
0 b
1 c
dtype: objeto

# O dtype de saída é inferido com base nos valores das categorias


Em [191]: int_cats = pd.Series([1, 2], dtype="category")

Em [192]: float_cats = pd.Series([3.0, 4.0], dtype="category")

Em [193]: pd.concat([int_cats, float_cats])


Fora[193]:
0 1,0
1 2,0
0 3,0
1 4,0
tipo d: float64

Em [194]: pd.concat([s1, s3]).astype("categoria")


Fora[194]:
0 a
1 b
0 b
1 c
tipo: categoria
Categorias (3, objeto): ['a', 'b', 'c']

Em [195]: union_categoricals([s1.array, s3.array])


Fora[195]:
['a', 'b', 'b', 'c']
Categorias (3, objeto): ['a', 'b', 'c']

A tabela a seguir resume os resultados da fusão de categóricos:

arg1 arg2 resultado idêntico


Categoria verdadeira categoria categoria
categoria (objeto) categoria (objeto) categoria falsa objeto (dtype é inferido)
(int) categoria (float) Falso float (dtype é inferido)

Consulte também a seção sobre tipos de mesclagem para notas sobre como preservar tipos de mesclagem e desempenho.

662 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

União

Se você deseja combinar categóricos que não possuem necessariamente as mesmas categorias, a função
union_categoricals() combinará uma lista de categóricos. As novas categorias serão a união das categorias que estão sendo combinadas.

Em [196]: de pandas.api.types import union_categoricals

Em [197]: a = pd.Categorical(["b", "c"])

Em [198]: b = pd.Categorical(["a", "b"])

Em [199]: union_categoricals([a, b])


Fora[199]:
['b', 'c', 'a', 'b']
Categorias (3, objeto): ['b', 'c', 'a']

Por padrão, as categorias resultantes serão ordenadas conforme aparecem nos dados. Se você deseja que as categorias sejam ordenadas
por lex, use o argumento sort_categories=True.

Em [200]: union_categoricals([a, b], sort_categories=True)


Fora[200]:
['b', 'c', 'a', 'b']
Categorias (3, objeto): ['a', 'b', 'c']

union_categoricals também funciona com o caso “fácil” de combinar duas categóricas das mesmas categorias e informações
de pedido (por exemplo, o que você também pode acrescentar).

Em [201]: a = pd.Categorical(["a", "b"], ordenado = Verdadeiro)

Em [202]: b = pd.Categorical(["a", "b", "a"], ordenado = Verdadeiro)

Em [203]: union_categoricals([a, b])


Fora[203]:
['a', 'b', 'a', 'b', 'a']
Categorias (2, objeto): ['a' <'b']

O exemplo abaixo gera TypeError porque as categorias são ordenadas e não idênticas.

Em [1]: a = pd.Categorical(["a", "b"], ordenado = Verdadeiro)


Em [2]: b = pd.Categorical(["a", "b", "c"], ordenado = Verdadeiro)
Em [3]: union_categoricals([a, b])
Out[3]:
TypeError: para unir categóricos ordenados, todas as categorias devem ser iguais

Categóricos ordenados com diferentes categorias ou ordenações podem ser combinados usando o argumento
ignore_ordered=True.

Em [204]: a = pd.Categorical(["a", "b", "c"], ordenado = Verdadeiro)

Em [205]: b = pd.Categorical(["c", "b", "a"], ordenado = Verdadeiro)

Em [206]: union_categoricals([a, b], ignore_order=True)


Fora[206]:
['a', 'b', 'c', 'c', 'b', 'a']
Categorias (3, objeto): ['a', 'b', 'c']

2.12. Dados categóricos 663


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

union_categoricals() também funciona com um CategoricalIndex, ou Série contendo dados categóricos, mas observe
que o array resultante será sempre um Categorical simples:

Em [207]: a = pd.Series(["b", "c"], dtype="categoria")

Em [208]: b = pd.Series(["a", "b"], dtype="categoria")

Em [209]: union_categoricals([a, b])


Fora[209]:
['b', 'c', 'a', 'b']
Categorias (3, objeto): ['b', 'c', 'a']

Nota: union_categoricals pode recodificar os códigos inteiros para categorias ao combinar categóricos. Provavelmente é isso
que você deseja, mas se estiver contando com a numeração exata das categorias, fique atento.

Em [210]: c1 = pd.Categorical(["b", "c"])

Em [211]: c2 = pd.Categorical(["a", "b"])

Em [212]: c1
Fora[212]:
['b', 'c']
Categorias (2, objeto): ['b', 'c']

# "b" é codificado como


0 In [213]: c1.codes
Out[213]: array([0, 1], dtype=int8)

Em [214]: c2
Fora[214]:
['a', 'b']
Categorias (2, objeto): ['a', 'b']

# "b" é codificado para 1


In [215]: c2.codes
Out[215]: array([0, 1], dtype=int8)

Em [216]: c = union_categoricals([c1, c2])

Em [217]: c
Fora[217]:
['b', 'c', 'a', 'b']
Categorias (3, objeto): ['b', 'c', 'a']

# "b" é codificado como 0, igual a c1, diferente de c2 In [218]: c.codes Out[218]:


array([0, 1, 2, 0],
dtype=int8)

664 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.12.9 Obtendo/retirando dados

Você pode gravar dados que contenham tipos de categoria em um HDFStore. Veja aqui um exemplo e advertências.

Também é possível gravar e ler dados de arquivos no formato Stata . Veja aqui um exemplo e advertências.

Gravar em um arquivo CSV converterá os dados, removendo efetivamente qualquer informação sobre o categórico (categorias e
encomenda). Portanto, se você reler o arquivo CSV, deverá converter as colunas relevantes de volta para a categoria e atribuir o
categorias corretas e ordenação de categorias.

Em [219]: importar io

Em [220]: s = pd.Series(pd.Categorical(["a", "b", "b", "a", "a", "d"]))

#renomeie as categorias
Em [221]: s.cat.categories = ["muito bom", "bom", "ruim"]

# reordene as categorias e adicione as categorias ausentes


Em [222]: s = s.cat.set_categories(["muito ruim", "ruim", "médio", "bom", "muito bom"])

Em [223]: df = pd.DataFrame({"cats": s, "vals": [1, 2, 3, 4, 5, 6]})

Em [224]: csv = io.StringIO()

Em [225]: df.to_csv(csv)

Em [226]: df2 = pd.read_csv(io.StringIO(csv.getvalue()))

Em [227]: df2.dtypes
Fora[227]:
Sem nome: 0 int64
gatos objeto
vals int64
dtype: objeto

Em [228]: df2["gatos"]
Fora[228]:
0 muito bom
1 bom
2 bom
3 muito bom
4 muito bom
5 ruim
Nome: gatos, dtype: objeto

# Refaça a categoria
Em [229]: df2["cats"] = df2["cats"].astype("category")

Em [230]: df2["cats"].cat.set_categories(
.....: ["muito ruim", "ruim", "médio", "bom", "muito bom"], inplace=True
..... :)
.....:

Em [231]: df2.dtypes
(continua na próxima página)

2.12. Dados categóricos 665


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[231]:
Sem nome: 0 int64
gatos categoria
vals int64
dtype: objeto

Em [232]: df2["gatos"]
Fora[232]:
0 muito bom
1 bom
2 bom
3 muito bom
4 muito bom
5 ruim
Nome: gatos, dtype: categoria
Categorias (5, objeto): ['muito ruim', 'ruim', 'médio', 'bom', 'muito bom']

O mesmo vale para gravar em um banco de dados SQL com to_sql.

2.12.10 Dados faltantes

pandas usa principalmente o valor np.nan para representar dados ausentes. Por padrão, não é incluído nos cálculos. Ver
a seção Dados ausentes.

Os valores faltantes não devem ser incluídos nas categorias da Categórica, apenas nos valores. Em vez disso, entende-se
que NaN é diferente e é sempre uma possibilidade. Ao trabalhar com códigos categóricos, os valores faltantes serão
sempre tenha um código de -1.

Em [233]: s = pd.Series(["a", "b", np.nan, "a"], dtype="category")

# apenas duas categorias


Em [234]: s
Fora[234]:
0 a
1 b
2 NaN
3 a
tipo: categoria
Categorias (2, objeto): ['a', 'b']

Em [235]: s.cat.codes
Fora[235]:
00
11

2 -1
30

tipo d: int8

Métodos para trabalhar com dados faltantes, por exemplo, isna(), fillna(), dropna(), todos funcionam normalmente:

Em [236]: s = pd.Series(["a", "b", np.nan], dtype="category")

(continua na próxima página)

666 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [237]: s
Fora[237]: 0
a
1 b
2 NaN
tipo: categoria
Categorias (2, objeto): ['a', 'b']

Em [238]: pd.isna(s)
Out[238]: 0
Falso 1 Falso
2 dtype: bool
Verdadeiro

Em [239]: s.fillna("a")
Out[239]: 0
a
b
a
1 2 dtype: categoria
Categorias (2, objeto): ['a', 'b']

2.12.11 Diferenças no fator R

As seguintes diferenças nas funções fatoriais de R podem ser observadas:

• Os níveis de R são nomeados como categorias.

• Os níveis do R são sempre do tipo string, enquanto as categorias no pandas podem ser de qualquer tipo.

• Não é possível especificar rótulos no momento da criação. Use s.cat.rename_categories(new_labels) depois.

• Em contraste com a função fatorial de R, usar dados categóricos como a única entrada para criar uma nova série categórica não
removerá categorias não utilizadas, mas criará uma nova série categórica que é igual à passada em uma!

• R permite que valores faltantes sejam incluídos em seus níveis (categorias de pandas). pandas não permite NaN
categorias, mas valores ausentes ainda podem estar nos valores.

2.12.12 Pegadinhas

Uso de memória

O uso de memória de um Categórico é proporcional ao número de categorias mais o comprimento dos dados. Por outro lado, um dtype
de objeto é uma constante vezes o comprimento dos dados.

Em [240]: s = pd.Series(["foo", "bar"] * 1000)

# objeto dtype In
[241]: s.nbytes Out[241]:
16000

(continua na próxima página)

2.12. Dados categóricos 667


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

# categoria dtype In
[242]: s.astype("categoria").nbytes Out[242]: 2016

Nota: Se o número de categorias se aproximar do comprimento dos dados, o Categórico usará quase a mesma ou mais
memória do que uma representação de tipo de objeto equivalente.

Em [243]: s = pd.Series(["foo%04d" % i for i in range(2000)])

# objeto dtype In
[244]: s.nbytes Out[244]:
16000

# categoria dtype In
[245]: s.astype("categoria").nbytes Out[245]:
20000

Categórico não é uma matriz numpy

Atualmente, os dados categóricos e o Categorical subjacente são implementados como um objeto Python e não como um dtype de
array NumPy de baixo nível. Isso leva a alguns problemas.

O próprio NumPy não conhece o novo dtype:

Em [246]: tente:
.....: np.dtype("category") .....:
exceto TypeError as e:
.....: print("TypeError:", str(e))
.....:
TypeError: tipo de dados 'categoria' não compreendido

Em [247]: dtype = pd.Categorical(["a"]).dtype

Em [248]: tente:
.....: np.dtype(dtype) .....:
exceto TypeError as e:
.....: print("TypeError:", str(e))
.....:
TypeError: Não é possível interpretar 'CategoricalDtype(categories=['a'], ordenado=False)' como umÿ ÿÿtipo de
dados

As comparações de Dtype funcionam:

In [249]: dtype == np.str_ Out[249]:


Falso

Em [250]: np.str_ == dtype


Out[250]: Falso

Para verificar se uma série contém dados categóricos, use hasattr(s, 'cat'):

668 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [251]: hasattr(pd.Series(["a"], dtype="category"), "cat")


Fora[251]: Verdadeiro

Em [252]: hasattr(pd.Series(["a"]), "gato")


Fora[252]: Falso

Usar funções NumPy em uma série de categoria de tipo não deve funcionar, pois categóricos não são dados numéricos (mesmo
no caso de .categories ser numérico).

Em [253]: s = pd.Series(pd.Categorical([1, 2, 3, 4]))

Em [254]: tente:
.....: np.soma(s)
.....: exceto TypeError como e:
.....: print("TypeError:", str(e))
.....:
TypeError: 'Categorical' com categoria dtype não suporta redução 'soma'

Nota: Se tal função funcionar, registre um bug em https://github.com/pandas-dev/pandas!

digite aplicar

Atualmente, o pandas não preserva o dtype nas funções de aplicação: se você aplicar ao longo das linhas, obterá uma série de objetos
dtype (o mesmo que obter uma linha -> obter um elemento retornará um tipo básico) e aplicar ao longo das colunas também
converter em objeto. Os valores NaN não são afetados. Você pode usar fillna para lidar com valores ausentes antes de aplicar uma função.

Em [255]: df = pd.DataFrame(
.....: {
.....: "uma": [1, 2, 3, 4],
.....: "b": ["a", "b", "c", "d"],
.....: "gatos": pd.Categorical([1, 2, 3, 2]),
.....: }
..... :)
.....:

Em [256]: df.apply(lambda row: type(row["cats"]), axis=1)


Fora[256]:
0 <classe 'int'>
1 <classe 'int'>
2 <classe 'int'>
<classe 'int'>
3 dtipo: objeto

Em [257]: df.apply(lambda col: col.dtype, eixo=0)


Fora[257]:
a int64
b objeto
gatos categoria
dtype: objeto

2.12. Dados categóricos 669


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Índice categórico

CategoricalIndex é um tipo de índice útil para oferecer suporte à indexação com duplicatas. Este é um contêiner em torno de um
Categórico e permite a indexação e armazenamento eficiente de um índice com um grande número de elementos duplicados. Consulte
a documentação de indexação avançada para uma explicação mais detalhada.

Definir o índice criará um CategoricalIndex:

Em [258]: gatos = pd.Categorical([1, 2, 3, 4], categorias=[4, 2, 3, 1])

Em [259]: strings = ["a", "b", "c", "d"]

Em [260]: valores = [4, 2, 3, 1]

Em [261]: df = pd.DataFrame({"strings": strings, "valores": valores}, index=cats)

In [262]: df.index Out[262]:


CategoricalIndex([1, 2, 3, 4], categorias=[4, 2, 3, 1], ordenado=Falso, dtype= ÿÿ'categoria')

# Isso agora classifica pela ordem das categorias em


[263]: df.sort_index()
Out[263]:
valores de strings 1
4 d
2 b 2
3 c 3
1 a 4

Efeitos colaterais

Construir uma série a partir de um categórico não copiará a entrada categórica. Isso significa que as alterações na Série irão,
na maioria dos casos, alterar a Categórica original:

Em [264]: cat = pd.Categorical([1, 2, 3, 10], categorias=[1, 2, 3, 4, 10])

Em [265]: s = pd.Series(cat, name="cat")

Em [266]: gato
Fora[266]:
[1, 2, 3, 10]
Categorias (5, int64): [1, 2, 3, 4, 10]

Em [267]: s.iloc[0:2] = 10

Em [268]: gato
Fora[268]:
[10, 10, 3, 10]
Categorias (5, int64): [1, 2, 3, 4, 10]

Em [269]: df = pd.DataFrame(s)

Em [270]: df["cat"].cat.categories = [1, 2, 3, 4, 5]


(continua na próxima página)

670 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [271]: gato
Fora[271]:
[10, 10, 3, 10]
Categorias (5, int64): [1, 2, 3, 4, 10]

Use copy=True para evitar tal comportamento ou simplesmente não reutilize categóricos:

Em [272]: cat = pd.Categorical([1, 2, 3, 10], categorias=[1, 2, 3, 4, 10])

Em [273]: s = pd.Series(cat, name="cat", copy=True)

Em [274]: gato
Fora[274]:
[1, 2, 3, 10]
Categorias (5, int64): [1, 2, 3, 4, 10]

Em [275]: s.iloc[0:2] = 10

Em [276]: gato
Fora[276]:
[1, 2, 3, 10]
Categorias (5, int64): [1, 2, 3, 4, 10]

Nota: Isso também acontece em alguns casos quando você fornece um array NumPy em vez de um Categórico: usar um
array int (por exemplo, np.array([1,2,3,4])) exibirá o mesmo comportamento, enquanto usa uma string array (por exemplo,
np.array(["a","b", "c","a"])) não.

2.13 Tipo de dados inteiro anulável

Nota: IntegerArray é atualmente experimental. Sua API ou implementação pode mudar sem aviso prévio.

Alterado na versão 1.0.0: agora usa pandas.NA como valor ausente em vez de numpy.nan.

Em Trabalhando com dados ausentes, vimos que o pandas usa principalmente NaN para representar dados ausentes. Como NaN é um ponto
flutuante, isso força uma matriz de números inteiros com quaisquer valores ausentes a se tornar um ponto flutuante. Em alguns casos, isso pode não
importar muito. Mas se a sua coluna inteira for, digamos, um identificador, a conversão para float pode ser problemática. Alguns inteiros nem sequer
podem ser representados como números de ponto flutuante.

2.13. Tipo de dados inteiro anulável 671


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.13.1 Construção

pandas pode representar dados inteiros com valores possivelmente ausentes usando arrays.IntegerArray. Este é um tipo de
extensão implementado no pandas.

Em [1]: arr = pd.array([1, 2, Nenhum], dtype=pd.Int64Dtype())

Em [2]: arr
Fora[2]:
<ArrayInteiro>
[1, 2, <NA>]
Comprimento: 3, tipo d: Int64

Ou o alias de string "Int64" (observe o "I" maiúsculo, para diferenciar do dtype 'int64' do NumPy:

Em [3]: pd.array([1, 2, np.nan], dtype="Int64")


Saída[3]:
<IntegerArray> [1,
2, <NA>]
Comprimento: 3, tipo d: Int64

Todos os valores semelhantes a NA são substituídos por pandas.NA.

Em [4]: pd.array([1, 2, np.nan, None, pd.NA], dtype="Int64")


Saída[4]:
<IntegerArray> [1,
2, <NA>, <NA>, <NA>]
Comprimento: 5, tipo d: Int64

Este array pode ser armazenado em um DataFrame ou Series como qualquer array NumPy.

Em [5]: pd.Series(arr)
Fora[5]: 0
1
1 2
2 <NA>
tipo de d: Int64

Você também pode passar o objeto semelhante a uma lista para o construtor Series com o dtype.

Aviso: atualmente pandas.array() e pandas.Series() usam regras diferentes para inferência de dtype. pandas. array() inferirá
um tipo de número inteiro anulável

Em [6]: pd.array([1, Nenhum])


Saída[6]:
<IntegerArray> [1,
<NA>]
Comprimento: 2, tipo de d: Int64

Em [7]: pd.array([1, 2])


Saída[7]:
<IntegerArray> [1,
2]
Comprimento: 2, tipo de d: Int64

672 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Para compatibilidade com versões anteriores, Series infere-os como tipo inteiro ou tipo flutuante

Em [8]: pd.Series([1, Nenhum])


Fora[8]:
0 1,0
1 NaN
tipo d: float64

Em [9]: pd.Series([1, 2])


Fora[9]:
0 1
12

tipo d: int64

Recomendamos fornecer explicitamente o dtype para evitar confusão.

Em [10]: pd.array([1, None], dtype="Int64")


Fora[10]:
<ArrayInteiro>
[1, <NA>]
Comprimento: 2, tipo de d: Int64

Em [11]: pd.Series([1, None], dtype="Int64")


Fora[11]:
0 1
1 <NA>
tipo de d: Int64

No futuro, poderemos fornecer uma opção para Series inferir um dtype inteiro anulável.

2.13.2 Operações

As operações envolvendo uma matriz inteira se comportarão de maneira semelhante às matrizes NumPy. Valores ausentes serão propagados e o
os dados serão coagidos para outro dtype, se necessário.

Em [12]: s = pd.Series([1, 2, None], dtype="Int64")

# aritmética
Em [13]: s + 1
Fora[13]:
0 2
1 3
2 <NA>
tipo de d: Int64

# comparação
Em [14]: s == 1
Fora[14]:
Verdadeiro

Falso
<NA>
0 1 2 dtype: booleano

(continua na próxima página)

2.13. Tipo de dados inteiro anulável 673


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

# indexação
Em [15]: s.iloc[1:3]
Fora[15]:
1 2
2 <NA>
tipo de d: Int64

#opera com outros dtypes


Em [16]: s + s.iloc[1:3].astype("Int8")
Fora[16]:
<NA>
4
<NA>
0 1 2 tipo d: Int64

# coagir quando necessário


Em [17]: s + 0,01
Fora[17]:
0 1,01
12.01
2 <NA>
tipo de d: Float64

Esses dtypes podem operar como parte do DataFrame.

Em [18]: df = pd.DataFrame({"A": s, "B": [1, 1, 3], "C": list("aab")})

Em [19]: df
Fora[19]:
abc
0 1 1 uma
1 2 1 uma
2 <NA> 3 b

Em [20]: df.dtypes
Fora[20]:
Um Int64
B int64
Objeto C
dtype: objeto

Esses dtypes podem ser mesclados, remodelados e fundidos.

Em [21]: pd.concat([df[["A"]], df[["B", "C"]]], eixo=1).dtypes


Fora[21]:
A Int64
B int64
C objeto
dtype: objeto

Em [22]: df["A"].astype(float)
Fora[22]:
(continua na próxima página)

674 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

0 1,0
1 2,0
2 NaN
Nome: A, tipo d: float64

Operações de redução e agrupamento, como 'soma', também funcionam.

Em [23]: df.sum()
Fora[23]:
A 3
B 5
aab
Tipo de C: objeto

Em [24]: df.groupby("B").A.sum()
Fora[24]:
B
1 3
30

Nome: A, tipo de d: Int64

2.13.3 Valor Escalar NA

arrays.IntegerArray usa pandas.NA como seu valor escalar ausente. Fatiar um único elemento que está faltando irá
retornar pandas.NA

Em [25]: a = pd.array([1, None], dtype="Int64")

Em [26]: uma[1]
Fora[26]: <NA>

2.14 Tipo de dados booleano anulável

Nota: BooleanArray é atualmente experimental. Sua API ou implementação pode mudar sem aviso prévio.

Novo na versão 1.0.0.

2.14.1 Indexação com valores NA

pandas permite a indexação com valores NA em uma matriz booleana, que são tratados como False.

Alterado na versão 1.0.2.

Em [1]: s = pd.Series([1, 2, 3])

Em [2]: máscara = pd.array([True, False, pd.NA], dtype="boolean")

(continua na próxima página)

2.14. Tipo de dados booleano anulável 675


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [3]: s[máscara]
Fora[3]:
01

tipo d: int64

Se preferir manter os valores NA, você pode preenchê-los manualmente com fillna(True).

Em [4]: s[mask.fillna(True)]
Fora[4]:
01
23

tipo d: int64

2.14.2 Operações lógicas de Kleene

arrays.BooleanArray implementa Kleene Logic (às vezes chamada de lógica de três valores) para operações lógicas como &
(e), | (ou) e ^ (exclusivo-ou).

Esta tabela demonstra os resultados para cada combinação. Essas operações são simétricas, portanto, invertendo os lados esquerdo e
lado direito não faz diferença no resultado.

Expressão Resultado

Verdade verdade Verdadeiro

Verdadeiro e Falso Falso


Verdadeiro e NA N/D

Falso e Falso Falso


Falso e NA Falso
NA e NA N/D

Verdadeiro | Verdadeiro Verdadeiro

Verdadeiro | Falso verdadeiro


Verdadeiro | N / D Verdadeiro

Falso | Falso Falso


Falso | N / D N/D

NA | N / D N/D

Verdadeiro ^ Verdadeiro Falso


Verdadeiro ^ Falso Verdadeiro
Verdadeiro ^ NA N/D

Falso ^ Falso Falso


Falso ^ NA N/D

NA ^ NA N/D

Quando um NA está presente em uma operação, o valor de saída será NA somente se o resultado não puder ser determinado apenas com base em
a outra entrada. Por exemplo, Verdadeiro | NA é Verdadeiro, porque tanto Verdadeiro | Verdadeiro e Verdadeiro | Falso é Verdadeiro. Naquilo
Neste caso, não precisamos realmente considerar o valor de NA.

Por outro lado, Verdadeiro e NA é NA. O resultado depende se o NA é realmente Verdadeiro ou Falso, uma vez que Verdadeiro e
True é True, mas True & False é False, portanto não podemos determinar a saída.

Isso difere de como o np.nan se comporta em operações lógicas. pandas tratados np.nan é sempre falso na saída.

Em ou

676 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [5]: pd.Series([True, False, np.nan], dtype="object") | Verdadeiro


Fora[5]:
0 Verdadeiro

1 Verdadeiro

2 Falso
tipo d: bool

Em [6]: pd.Series([True, False, np.nan], dtype="boolean") | Verdadeiro


Fora[6]:
Verdadeiro

Verdadeiro

Verdadeiro

0 1 2 dtype: booleano

dentro e

Em [7]: pd.Series([True, False, np.nan], dtype="object") & True


Fora[7]:
0 Verdadeiro

1 Falso
2 Falso
tipo d: bool

Em [8]: pd.Series([True, False, np.nan], dtype="boolean") & True


Fora[8]:
0 Verdadeiro

Falso
<NA>
1 2 dtype: booleano

{{cabeçalho}}

2.15 Visualização de gráfico

Esta seção demonstra a visualização por meio de gráficos. Para obter informações sobre visualização de dados tabulares, consulte
a seção sobre Visualização de Tabela.

Usamos a convenção padrão para referenciar a API matplotlib:

Em [1]: importe matplotlib.pyplot como plt

Em [2]: plt.close("todos")

Fornecemos o básico em pandas para criar facilmente gráficos de aparência decente. Veja a seção do ecossistema para visualização
bibliotecas que vão além do básico documentado aqui.

Nota: Todas as chamadas para np.random são propagadas com 123456.

2.15. Visualização de gráfico 677


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.15.1 Plotagem básica: plotagem

Demonstraremos o básico, consulte o livro de receitas para algumas estratégias avançadas.

O método plot em Series e DataFrame é apenas um wrapper simples em torno de plt.plot():

Em [3]: ts = pd.Series(np.random.randn(1000), index=pd.date_range("1/1/2000",ÿ ÿÿperíodos=1000))

Em [4]: ts = ts.cumsum()

Em [5]: ts.plot();

Se o índice consistir em datas, ele chama gcf().autofmt_xdate() para tentar formatar bem o eixo x conforme acima.

No DataFrame, plot() é uma conveniência para plotar todas as colunas com rótulos:

Em [6]: df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=list("ABCD"))

Em [7]: df = df.cumsum()

Em [8]: plt.figure();

Em [9]: df.plot();

678 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Você pode plotar uma coluna versus outra usando as palavras-chave x e y em plot():

Em [10]: df3 = pd.DataFrame(np.random.randn(1000, 2), colunas=["B", "C"]).cumsum()

Em [11]: df3["A"] = pd.Series(list(range(len(df))))

Em [12]: df3.plot(x="A", y="B");

2.15. Visualização de gráfico 679


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Nota: Para obter mais opções de formatação e estilo, consulte formatação abaixo.

2.15.2 Outras parcelas

Os métodos de plotagem permitem vários estilos de plotagem além do gráfico de linha padrão. Esses métodos podem ser fornecidos como argumento de palavra-chave kind
para plot() e incluem:

• 'bar' ou 'barh' para gráficos de barras

• 'hist' para histograma

• 'caixa' para boxplot

• 'kde' ou 'densidade' para gráficos de densidade

• 'área' para parcelas de área

• 'dispersão' para gráficos de dispersão

• 'hexbin' para gráficos de caixas hexagonais

• 'torta' para gráficos de pizza

Por exemplo, um gráfico de barras pode ser criado da seguinte maneira:

680 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [13]: plt.figure();

Em [14]: df.iloc[5].plot(kind="bar");

Você também pode criar esses outros gráficos usando os métodos DataFrame.plot.<kind> em vez de fornecer o tipo
argumento de palavra-chave. Isso torna mais fácil descobrir os métodos de plotagem e os argumentos específicos que eles usam:

Em [15]: df = pd.DataFrame()

Em [16]: df.plot.<TAB> # noqa: E225, E999


df.plot.area df.plot.densitydf.plot.barh
df.plot.hist ÿÿplot.scatter df.plot.line df.

df.plot.bar df.plot.box df.plot.hexbin df.plot.kde df.plot.pie

Além desses kind s, existem os métodos DataFrame.hist() e DataFrame.boxplot() , que usam um método separado.
interface.

Finalmente, existem várias funções de plotagem em pandas.plotting que usam uma Série ou DataFrame como argumento.
Esses incluem:

• Matriz de Dispersão

• Curvas de Andrews

• Coordenadas Paralelas

2.15. Visualização de gráfico 681


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

• Gráfico de atraso

• Gráfico de autocorrelação

• Gráfico de inicialização

• RadViz

Os gráficos também podem ser adornados com barras de erro ou tabelas.

Gráficos de barras

Para dados rotulados e não de séries temporais, você pode querer produzir um gráfico de barras:

Em [17]: plt.figure();

Em [18]: df.iloc[5].plot.bar();

Em [19]: plt.axhline(0, color="k");

Chamar o método plot.bar() de um DataFrame produz um gráfico de barras múltiplas:

Em [20]: df2 = pd.DataFrame(np.random.rand(10, 4), colunas=["a", "b", "c", "d"])

Em [21]: df2.plot.bar();

682 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Para produzir um gráfico de barras empilhadas, passe stacked=True:

Em [22]: df2.plot.bar(stacked=True);

2.15. Visualização de gráfico 683


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Para obter gráficos de barras horizontais, use o método barh:

Em [23]: df2.plot.barh(stacked=True);

684 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Histogramas

Os histogramas podem ser desenhados usando os métodos DataFrame.plot.hist() e Series.plot.hist().

Em [24]: df4 = pd.DataFrame(


....: {
....: "a": np.random.randn(1000) + 1,
....: "b": np.random.randn(1000),
....: "c": np.random.randn(1000) - 1,
....: },
....: colunas=["a", "b", "c"],
....: )
....:

Em [25]: plt.figure();

Em [26]: df4.plot.hist(alfa=0,5);

2.15. Visualização de gráfico 685


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Um histograma pode ser empilhado usando stacked=True. O tamanho do compartimento pode ser alterado usando a palavra-chave bins.

Em [27]: plt.figure();

Em [28]: df4.plot.hist(stacked=True, bins=20);

686 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Você pode passar outras palavras-chave suportadas pelo matplotlib hist. Por exemplo, histogramas horizontais e cumulativos podem
ser desenhados por orientação='horizontal' e cumulativo=True.

Em [29]: plt.figure();

Em [30]: df4["a"].plot.hist(orientation="horizontal", cumulativo=True);

2.15. Visualização de gráfico 687


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Consulte o método hist e a documentação hist do matplotlib para obter mais informações.

A interface existente DataFrame.hist para traçar o histograma ainda pode ser usada.

Em [31]: plt.figure();

Em [32]: df["A"].diff().hist();

688 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

DataFrame.hist() traça os histogramas das colunas em vários subparcelas:

Em [33]: plt.figure();

Em [34]: df.diff().hist(color="k", alpha=0,5, bins=50);

2.15. Visualização de gráfico 689


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

A palavra-chave by pode ser especificada para traçar histogramas agrupados:

Em [35]: dados = pd.Series(np.random.randn(1000))

Em [36]: data.hist(by=np.random.randint(0, 4, 1000), figsize=(6, 4));

690 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Além disso, a palavra-chave by também pode ser especificada em DataFrame.plot.hist().

Alterado na versão 1.4.0.

Em [37]: dados = pd.DataFrame(


....: {
....: "a": np.random.choice(["x", "y", "z"], 1000),
....: "b": np.random.choice(["e", "f", "g"], 1000),
....: "c": np.random.randn(1000),
....: "d": np.random.randn(1000) - 1,
....: },
....: )
....:

Em [38]: data.plot.hist(by=["a", "b"], figsize=(10, 5));

2.15. Visualização de gráfico 691


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Gráficos de caixa

Boxplot pode ser desenhado chamando Series.plot.box() e DataFrame.plot.box(), ou DataFrame.boxplot() para visualizar a distribuição
de valores dentro de cada coluna.

Por exemplo, aqui está um boxplot representando cinco tentativas de 10 observações de uma variável aleatória uniforme em [0,1).

Em [39]: df = pd.DataFrame(np.random.rand(10, 5), colunas=["A", "B", "C", "D", "E"])

Em [40]: df.plot.box();

692 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

O Boxplot pode ser colorido passando a palavra-chave color. Você pode passar um ditado cujas chaves são caixas, bigodes, medianas
e bonés. Se algumas chaves estiverem faltando no dicionário, as cores padrão serão usadas para os artistas correspondentes. Além disso, boxplot
possui a palavra-chave sym para especificar o estilo dos panfletos.

Quando você passa outro tipo de argumento por meio da palavra-chave color, ele será passado diretamente para matplotlib para todas as caixas,
coloração de bigodes, medianas e gorros.

As cores são aplicadas a todas as caixas a serem desenhadas. Se você quiser uma colorização mais complicada, você pode desenhar cada um
artistas passando return_type.

Em [41]: cor = {
....: "caixas": "VerdeEscuro",
....: "bigodes": "Laranja Escuro",
....: "medianas": "Azul Escuro",
....: "caps": "Cinza",
....: }
....:

Em [42]: df.plot.box(color=color, sym="r+");

2.15. Visualização de gráfico 693


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Além disso, você pode passar outras palavras-chave suportadas pelo boxplot matplotlib. Por exemplo, boxplot horizontal e com posicionamento
personalizado podem ser desenhados por vert=False e posições palavras-chave.

Em [43]: df.plot.box(vert=False, positions=[1, 4, 5, 6, 8]);

694 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Consulte o método boxplot e a documentação do boxplot matplotlib para obter mais informações.

A interface existente DataFrame.boxplot para plotar boxplot ainda pode ser usada.

Em [44]: df = pd.DataFrame(np.random.rand(10, 5))

Em [45]: plt.figure();

Em [46]: bp = df.boxplot()

2.15. Visualização de gráfico 695


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Você pode criar um boxplot estratificado usando o argumento by palavra-chave para criar agrupamentos. Por exemplo,

Em [47]: df = pd.DataFrame(np.random.rand(10, 2), colunas=["Col1", "Col2"])

Em [48]: df["X"] = pd.Series(["A", "A", "A ", "A", "A", " B", "B", "B", " B", "B"])

Em [49]: plt.figure();

Em [50]: bp = df.boxplot(by="X")

696 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Você também pode passar um subconjunto de colunas para plotar, bem como agrupar por múltiplas colunas:

Em [51]: df = pd.DataFrame(np.random.rand(10, 3), colunas=["Col1", "Col2", "Col3"])

Em [52]: df["X"] = pd.Series(["A", "A", "A ", "A", "A", " B", "B", "B", " B", "B"])

Em [53]: df["Y"] = pd.Series(["A", "B", "A", "B", "A", "B", " A", "B", " A", "B"])

Em [54]: plt.figure();

Em [55]: bp = df.boxplot(column=["Col1", "Col2"], by=["X", "Y"])

2.15. Visualização de gráfico 697


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Você também pode criar agrupamentos com DataFrame.plot.box(), por exemplo:

Alterado na versão 1.4.0.

Em [56]: df = pd.DataFrame(np.random.rand(10, 3), colunas=["Col1", "Col2", "Col3"])

Em [57]: df["X"] = pd.Series(["A", "A", "A ", "A", "A", " B", "B", "B", " B", "B"])

Em [58]: plt.figure();

Em [59]: bp = df.plot.box(column=["Col1", "Col2"], by="X")

698 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

No boxplot, o tipo de retorno pode ser controlado pela palavra-chave return_type. As escolhas válidas são {"axes", "dict
", "both", None}. A facetação, criada por DataFrame.boxplot com a palavra-chave by, afetará o tipo de saída como
bem:

return_type Tipo de saída facetada


Nenhum Não eixos
Nenhum Sim Ndarray 2-D de eixos
'eixos' Não eixos
'eixos' Sim Série de eixos
'ditar' Não ditado de artistas
'ditar' Sim Série de dictos de artistas
'ambos' Não nomeadatupla
'ambos' Sim Série de duplas nomeadas

Groupby.boxplot sempre retorna uma série de return_type.

Em [60]: np.random.seed(1234)

Em [61]: df_box = pd.DataFrame(np.random.randn(50, 2))

Em [62]: df_box["g"] = np.random.choice(["A", "B"], tamanho=50)

Em [63]: df_box.loc[df_box["g"] == "B", 1] += 3


(continua na próxima página)

2.15. Visualização de gráfico 699


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [64]: bp = df_box.boxplot(by="g")

As subparcelas acima são divididas primeiro pelas colunas numéricas e depois pelo valor da coluna g. Abaixo, as subparcelas são
primeiro divididas pelo valor de g e depois pelas colunas numéricas.

Em [65]: bp = df_box.groupby("g").boxplot()

700 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Gráfico de área

Você pode criar gráficos de área com Series.plot.area() e DataFrame.plot.area(). Os gráficos de área são empilhados por padrão. Para
produzir um gráfico de área empilhada, cada coluna deve ter todos valores positivos ou negativos.

Quando os dados de entrada contiverem NaN, eles serão preenchidos automaticamente com 0. Se você quiser eliminar ou preencher com
valores diferentes, use dataframe.dropna() ou dataframe.fillna() antes de chamar plot.

Em [66]: df = pd.DataFrame(np.random.rand(10, 4), colunas=["a", "b", "c", "d"])

Em [67]: df.plot.area();

2.15. Visualização de gráfico 701


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Para produzir um gráfico não empilhado, passe stacked=False. O valor alfa é definido como 0,5, salvo especificação em contrário:

Em [68]: df.plot.area(stacked=False);

702 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Gráfico de dispersão

O gráfico de dispersão pode ser desenhado usando o método DataFrame.plot.scatter(). O gráfico de dispersão requer colunas
numéricas para os eixos x e y. Eles podem ser especificados pelas palavras-chave xey.

Em [69]: df = pd.DataFrame(np.random.rand(50, 4), colunas=["a", "b", "c", "d"])

Em [70]: df["espécie"] = pd.Categorical(


....: ["setosa"] * 20 + ["versicolor"] * 20 + ["virginica"] * 10
....: )
....:

Em [71]: df.plot.scatter(x="a", y="b");

2.15. Visualização de gráfico 703


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Para plotar vários grupos de colunas em um único eixo, repita o método de plotagem especificando o eixo de destino. Recomenda-se
especificar palavras-chave de cor e rótulo para distinguir cada grupo.

Em [72]: ax = df.plot.scatter(x="a", y="b", color="DarkBlue", label="Grupo 1")

Em [73]: df.plot.scatter(x="c", y="d", color="DarkGreen", label="Grupo 2", ax=ax);

704 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

A palavra-chave c pode ser fornecida como o nome de uma coluna para fornecer cores para cada ponto:

Em [74]: df.plot.scatter(x="a", y="b", c="c", s=50);

2.15. Visualização de gráfico 705


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Se uma coluna categórica for passada para c, uma barra de cores discreta será produzida:

Novo na versão 1.3.0.

Em [75]: df.plot.scatter(x="a", y="b", c="species", cmap="viridis", s=50);

706 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Você pode passar outras palavras-chave suportadas pelo scatter matplotlib. O exemplo abaixo mostra um gráfico de bolhas usando
uma coluna do DataFrame como tamanho da bolha.

Em [76]: df.plot.scatter(x="a", y="b", s=df["c"] * 200);

2.15. Visualização de gráfico 707


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Consulte o método de dispersão e a documentação de dispersão do matplotlib para obter mais informações.

Gráfico de caixa hexagonal

Você pode criar gráficos bin hexagonais com DataFrame.plot.hexbin(). Os gráficos hexbin podem ser uma alternativa útil aos gráficos de
dispersão se seus dados forem muito densos para representar cada ponto individualmente.

Em [77]: df = pd.DataFrame(np.random.randn(1000, 2), colunas=["a", "b"])

Em [78]: df["b"] = df["b"] + np.arange(1000)

Em [79]: df.plot.hexbin(x="a", y="b", gridsize=25);

708 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Um argumento de palavra-chave útil é gridsize; ele controla o número de hexágonos na direção x e o padrão é 100.
Um tamanho de grade maior significa mais caixas menores.

Por padrão, um histograma das contagens em torno de cada ponto (x, y) é calculado. Você pode especificar agregações alternativas
passando valores para os argumentos C e reduzir_C_function. C especifica o valor em cada ponto (x, y) e reduzir_C_função é uma
função de um argumento que reduz todos os valores em um compartimento a um único número (por exemplo, média, máximo, soma,
padrão). Neste exemplo as posições são dadas pelas colunas a e b, enquanto o valor é dado pela coluna z. As caixas são agregadas
com a função max do NumPy.

Em [80]: df = pd.DataFrame(np.random.randn(1000, 2), colunas=["a", "b"])

Em [81]: df["b"] = df["b"] + np.arange(1000)

Em [82]: df["z"] = np.random.uniform(0, 3, 1000)

Em [83]: df.plot.hexbin(x="a", y="b", C="z", reduza_C_function=np.max, gridsize=25);

2.15. Visualização de gráfico 709


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Consulte o método hexbin e a documentação hexbin do matplotlib para obter mais informações.

Gráfico de torta

Você pode criar um gráfico de pizza com DataFrame.plot.pie() ou Series.plot.pie(). Se seus dados incluírem qualquer NaN, eles
serão preenchidos automaticamente com 0. Um ValueError será gerado se houver algum valor negativo em seus dados.

Em [84]: série = pd.Series(3 * np.random.rand(4), index=["a", "b", "c", "d"], nome= ÿÿ"série")

Em [85]: series.plot.pie(figsize=(6, 6));

710 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Para gráficos de pizza, é melhor usar figuras quadradas, ou seja, uma proporção de figura 1. Você pode criar a figura com
largura e altura iguais ou forçar a proporção a ser igual após a plotagem chamando ax.set_aspect('equal') no objeto de eixos
retornado.

Observe que o gráfico de pizza com DataFrame requer que você especifique uma coluna de destino pelo argumento y ou subplots=True.
Quando y é especificado, o gráfico de pizza da coluna selecionada será desenhado. Se subplots=True for especificado, os gráficos de pizza
para cada coluna serão desenhados como subgráficos. Uma legenda será desenhada em cada gráfico de pizza por padrão; especifique
legend=False para ocultá-lo.

Em [86]: df = pd.DataFrame( 3 *
....: np.random.rand(4, 2), index=["a", "b", "c", "d"], colunas=["x" , "você"]
....: )
....:

Em [87]: df.plot.pie(subplots=True, figsize=(8, 4));

2.15. Visualização de gráfico 711


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Você pode usar as palavras-chave rótulos e cores para especificar os rótulos e cores de cada fatia.

Aviso: a maioria dos gráficos de pandas usa os argumentos rótulo e cor (observe a falta de “s” neles). Para ser consistente
com matplotlib.pyplot.pie() você deve usar rótulos e cores.

Se desejar ocultar rótulos de fatia, especifique rótulos=Nenhum. Se fontsize for especificado, o valor será aplicado à cunha
rótulos. Além disso, outras palavras-chave suportadas por matplotlib.pyplot.pie() podem ser usadas.

Em [88]: series.plot.pie(
....: rótulos=["AA", "BB", "CC", "DD"],
....: cores=["r", "g", "b", "c"],
....: autopct="%.2f",
....: tamanho da fonte=20,
....: tamanho da figura=(6, 6),
....: );
....:

712 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Se você passar valores cuja soma total seja menor que 1,0, o matplotlib desenha um semicírculo.

Em [89]: série = pd.Series([0.1] * 4, índice=["a", "b", "c", "d"], nome="série2")

Em [90]: series.plot.pie(figsize=(6, 6));

2.15. Visualização de gráfico 713


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Veja a documentação do matplotlib pie para mais informações.

2.15.3 Plotagem com dados faltantes

O pandas tenta ser pragmático ao traçar DataFrames ou séries que contêm dados ausentes. Os valores ausentes são eliminados, omitidos ou preenchidos
dependendo do tipo de gráfico.

714 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Tipo de lote Manipulação de NaN


Linha Deixe lacunas em NaNs
Linha (empilhada) Preencha 0's
Bar Preencha 0's

Dispersão Eliminar NaNs


Histograma Eliminar NaNs (em colunas)
Caixa Eliminar NaNs (em colunas)
Área Preencha 0's

KDE Eliminar NaNs (em colunas)


Hexbin Eliminar NaNs
Torta Preencha 0's

Se algum desses padrões não for o que você deseja ou se quiser ser explícito sobre como os valores ausentes são tratados,
considere usar fillna() ou dropna() antes de plotar.

2.15.4 Ferramentas de plotagem

Essas funções podem ser importadas de pandas.plotting e usar uma Série ou DataFrame como argumento.

Gráfico de matriz de dispersão

Você pode criar uma matriz de gráfico de dispersão usando o método scatter_matrix em pandas.plotting:

Em [91]: de pandas.plotting import scatter_matrix

Em [92]: df = pd.DataFrame(np.random.randn(1000, 4), colunas=["a", "b", "c", "d"])

Em [93]: scatter_matrix(df, alpha=0.2, figsize=(6, 6), diagonal="kde");

2.15. Visualização de gráfico 715


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Gráfico de densidade

Você pode criar gráficos de densidade usando os métodos Series.plot.kde() e DataFrame.plot.kde().

Em [94]: ser = pd.Series(np.random.randn(1000))

Em [95]: ser.plot.kde();

716 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Curvas de Andrews

As curvas de Andrews permitem traçar dados multivariados como um grande número de curvas que são criadas usando os atributos de
amostras como coeficientes para séries de Fourier, consulte a entrada da Wikipedia para obter mais informações. Ao colorir essas curvas
de forma diferente para cada classe é possível visualizar o agrupamento de dados. Curvas pertencentes a amostras da mesma classe
geralmente estarão mais próximas e formarão estruturas maiores.

Nota: O conjunto de dados “Iris” está disponível aqui.

Em [96]: de pandas.plotting import andrews_curves

Em [97]: dados = pd.read_csv("dados/iris.data")

Em [98]: plt.figure();

Em [99]: andrews_curves(dados, "Nome");

2.15. Visualização de gráfico 717


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Coordenadas paralelas

Coordenadas paralelas são uma técnica de plotagem para plotar dados multivariados; consulte a entrada da Wikipedia para obter uma introdução.
Coordenadas paralelas permitem ver clusters de dados e estimar outras estatísticas visualmente. Usando coordenadas paralelas, os
pontos são representados como segmentos de linha conectados. Cada linha vertical representa um atributo. Um conjunto de segmentos
de linha conectados representa um ponto de dados. Os pontos que tendem a se agrupar aparecerão mais próximos.

Em [100]: de pandas.plotting importar paralela_coordenadas

Em [101]: dados = pd.read_csv("data/iris.data")

Em [102]: plt.figure();

Em [103]: paralelo_coordenadas(dados, "Nome");

718 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Gráfico de atraso

Os gráficos de atraso são usados para verificar se um conjunto de dados ou série temporal é aleatório. Os dados aleatórios não devem exibir
nenhuma estrutura no gráfico de defasagem. A estrutura não aleatória implica que os dados subjacentes não são aleatórios. O argumento lag
pode ser passado, e quando lag=1 o gráfico é essencialmente data[:-1] vs. data[1:].

Em [104]: de pandas.plotting importar lag_plot

Em [105]: plt.figure();

Em [106]: espaçamento = np.linspace(-99 * np.pi, 99 * np.pi, num=1000)

Em [107]: dados = pd.Series(0,1 * np.random.rand(1000) + 0,9 * np.sin(espaçamento))

Em [108]: lag_plot(dados);

2.15. Visualização de gráfico 719


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Gráfico de autocorrelação

Gráficos de autocorrelação são frequentemente usados para verificar a aleatoriedade em séries temporais. Isso é feito calculando autocorrelações
para valores de dados em intervalos de tempo variados. Se a série temporal for aleatória, tais autocorrelações deverão ser próximas de zero para
toda e qualquer separação de intervalo de tempo. Se a série temporal não for aleatória, uma ou mais das autocorrelações serão significativamente
diferentes de zero. As linhas horizontais exibidas no gráfico correspondem às faixas de confiança de 95% e 99%. A linha tracejada representa a faixa
de confiança de 99%. Consulte a entrada da Wikipedia para obter mais informações sobre gráficos de autocorrelação.

Em [109]: de pandas.plotting import autocorrelation_plot

Em [110]: plt.figure();

Em [111]: espaçamento = np.linspace(-9 * np.pi, 9 * np.pi, num=1000)

Em [112]: dados = pd.Series(0,7 * np.random.rand(1000) + 0,3 * np.sin(espaçamento))

Em [113]: autocorrelation_plot(dados);

720 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Gráfico de inicialização

Os gráficos de bootstrap são usados para avaliar visualmente a incerteza de uma estatística, como média, mediana, intervalo médio, etc. Um
subconjunto aleatório de um tamanho especificado é selecionado de um conjunto de dados, a estatística em questão é calculada para este
subconjunto e o processo é repetido um determinado número de vezes. Os gráficos e histogramas resultantes são o que constitui o gráfico de bootstrap.

Em [114]: de pandas.plotting import bootstrap_plot

Em [115]: dados = pd.Series(np.random.rand(1000))

Em [116]: bootstrap_plot(dados, tamanho=50, amostras=500, color="cinza");

2.15. Visualização de gráfico 721


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

RadViz

RadViz é uma forma de visualizar dados multivariados. É baseado em um algoritmo simples de minimização da tensão da mola.
Basicamente você configura vários pontos em um avião. No nosso caso, eles estão igualmente espaçados em um círculo unitário. Cada
ponto representa um único atributo. Você então finge que cada amostra no conjunto de dados está presa a cada um desses pontos por
uma mola, cuja rigidez é proporcional ao valor numérico desse atributo (eles são normalizados para intervalo unitário).
O ponto no plano onde a nossa amostra se estabelece (onde as forças que atuam na nossa amostra estão em equilíbrio) é onde um
ponto representando a nossa amostra será desenhado. Dependendo da classe a que a amostra pertence, ela terá cores diferentes.
Consulte o pacote R Radviz para obter mais informações.

Nota: O conjunto de dados “Iris” está disponível aqui.

Em [117]: de pandas.plotting import radviz

Em [118]: dados = pd.read_csv("data/iris.data")

Em [119]: plt.figure();

Em [120]: radviz(dados, "Nome");

722 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.15.5 Formatação de plotagem

Configurando o estilo de plotagem

A partir da versão 1.5 e superior, o matplotlib oferece uma variedade de estilos de plotagem pré-configurados. A configuração do estilo
pode ser usada para dar facilmente aos gráficos a aparência geral desejada. Definir o estilo é tão fácil quanto chamar matplotlib.style.
use(my_plot_style) antes de criar seu gráfico. Por exemplo, você poderia escrever matplotlib.style.use('ggplot') para gráficos no estilo
ggplot.

Você pode ver os vários nomes de estilos disponíveis em matplotlib.style.available e é muito fácil experimentá-los.

Argumentos gerais de estilo de enredo

A maioria dos métodos de plotagem possui um conjunto de argumentos de palavras-chave que controlam o layout e a formatação do gráfico retornado:

Em [121]: plt.figure();

Em [122]: ts.plot(style="k--", label="Série");

2.15. Visualização de gráfico 723


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Para cada tipo de gráfico (por exemplo, linha, barra, dispersão) quaisquer palavras-chave de argumentos adicionais são
passadas para a função matplotlib correspondente (ax.plot(), ax.bar(), ax.scatter()). Eles podem ser usados para controlar estilos
adicionais, além do que o pandas oferece.

Controlando a lenda

Você pode definir o argumento da legenda como False para ocultar a legenda, que é mostrada por padrão.

Em [123]: df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=list("ABCD ÿÿ"))

Em [124]: df = df.cumsum()

Em [125]: df.plot(legend=False);

724 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Controlando os rótulos

Novo na versão 1.1.0.

Você pode definir os argumentos xlabel e ylabel para fornecer rótulos personalizados ao gráfico para os eixos x e y. Por padrão, o
pandas escolherá o nome do índice como xlabel, deixando-o vazio para ylabel.

Em [126]: df.plot();

Em [127]: df.plot(xlabel="novo x", ylabel="novo y");

2.15. Visualização de gráfico 725


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Balanças

Você pode passar na logia para obter um eixo Y em escala logarítmica.

Em [128]: ts = pd.Series(np.random.randn(1000), index=pd.date_range("1/1/2000",ÿ ÿÿperíodos=1000))

Em [129]: ts = np.exp(ts.cumsum())

Em [130]: ts.plot(logy=True);

726 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Consulte também os argumentos das palavras-chave logx e loglog.

Plotando em um eixo y secundário

Para plotar dados em um eixo y secundário, use a palavra-chave secundário_y:

Em [131]: df["A"].plot();

Em [132]: df["B"].plot(secondary_y=True, style="g");

2.15. Visualização de gráfico 727


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Para plotar algumas colunas em um DataFrame, forneça os nomes das colunas à palavra-chave secundário_y:

Em [133]: plt.figure();

Em [134]: ax = df.plot(secondary_y=["A", "B"])

Em [135]: ax.set_ylabel(" escala CD");

Em [136]: ax.right_ax.set_ylabel(" Escala AB");

728 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Observe que as colunas plotadas no eixo y secundário são automaticamente marcadas com “(direita)” na legenda. Para desativar a
marcação automática, use a palavra-chave mark_right=False:

Em [137]: plt.figure();

Em [138]: df.plot(secondary_y=["A", "B"], mark_right=False);

2.15. Visualização de gráfico 729


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Formatadores personalizados para gráficos de série temporal

Alterado na versão 1.0.0.

pandas fornece formatadores personalizados para gráficos de séries temporais. Eles alteram a formatação dos rótulos dos eixos
para datas e horas. Por padrão, os formatadores personalizados são aplicados apenas a gráficos criados por pandas com
DataFrame. plot() ou Series.plot(). Para que sejam aplicados a todos os gráficos, incluindo aqueles feitos pelo matplotlib, defina a
opção pd.options.plotting.matplotlib.register_converters = True ou use pandas.plotting. registrar_matplotlib_converters().

Suprimindo ajuste de resolução de tick

pandas inclui ajuste automático de resolução de ticks para dados de séries temporais de frequência regular. Para casos limitados em que os
pandas não podem inferir as informações de frequência (por exemplo, em um twinx criado externamente), você pode optar por suprimir esse
comportamento para fins de alinhamento.

Aqui está o comportamento padrão, observe como a rotulagem do eixo x é executada:

Em [139]: plt.figure();

Em [140]: df["A"].plot();

730 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Usando o parâmetro x_compat, você pode suprimir este comportamento:

Em [141]: plt.figure();

Em [142]: df["A"].plot(x_compat=True);

2.15. Visualização de gráfico 731


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Se você tiver mais de um gráfico que precisa ser suprimido, o método use em pandas.plotting.plot_params pode
ser usado em uma instrução with:

Em [143]: plt.figure();

Em [144]: com pd.plotting.plot_params.use("x_compat", True):


.....: df["A"].plot(color="r")
.....: df["B"].plot(color="g")
.....: df["C"].plot(color="b")
.....:

732 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Ajuste automático de data

TimedeltaIndex agora usa os métodos nativos de localização de ticks do matplotlib. É útil chamar o ajuste automático de ticks de data
do matplotlib para figuras cujos rótulos de ticks se sobrepõem.

Consulte o método autofmt_xdate e a documentação do matplotlib para obter mais informações.

2.15. Visualização de gráfico 733


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Subtramas

Cada série em um DataFrame pode ser plotada em um eixo diferente com a palavra-chave subplots:

Em [145]: df.plot(subplots=True, figsize=(6, 6));

734 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Usando layout e direcionando vários eixos

O layout das subparcelas pode ser especificado pela palavra-chave layout. Pode aceitar (linhas, colunas). A palavra-chave layout
também pode ser usada em hist e boxplot. Se a entrada for inválida, um ValueError será gerado.

O número de eixos que podem ser contidos por linhas x colunas especificadas pelo layout deve ser maior que o número de subparcelas
necessárias. Se o layout puder conter mais eixos do que o necessário, os eixos em branco não serão desenhados. Semelhante ao método de
remodelação de um array NumPy, você pode usar -1 para uma dimensão para calcular automaticamente o número de linhas ou colunas
necessárias, considerando a outra.

Em [146]: df.plot(subplots=True, layout=(2, 3), figsize=(6, 6), sharex=False);

O exemplo acima é idêntico ao uso:

Em [147]: df.plot(subplots=True, layout=(2, -1), figsize=(6, 6), sharex=False);

O número necessário de colunas (3) é inferido do número de séries a serem plotadas e do número fornecido de linhas (2).

2.15. Visualização de gráfico 735


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Você pode passar vários eixos criados anteriormente como uma lista por meio da palavra-chave ax. Isso permite layouts mais complicados. Os eixos
passados devem ter o mesmo número das subparcelas que estão sendo desenhadas.

Quando vários eixos são passados por meio da palavra-chave ax, as palavras-chave layout, sharex e sharey não afetam a saída.
Você deve passar explicitamente sharex=False e sharey=False, caso contrário você verá um aviso.

Em [148]: fig, axes = plt.subplots(4, 4, figsize=(9, 9))

Em [149]: plt.subplots_adjust(wspace=0,5, hspace=0,5)

Em [150]: alvo1 = [eixos[0][0], eixos[1][1], eixos[2][2], eixos[3][3]]

Em [151]: target2 = [eixos[3][0], eixos[2][1], eixos[1][2], eixos[0][3]]

Em [152]: df.plot(subplots=True, ax=target1, legend=False, sharex=False, sharey=False);

Em [153]: (-df).plot(subplots=True, ax=target2, legend=False, sharex=False,ÿ ÿÿsharey=False);

736 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Outra opção é passar um argumento ax para Series.plot() para plotar em um eixo específico:

Em [154]: fig, eixos = plt.subplots(nrows=2, ncols=2)

Em [155]: plt.subplots_adjust(wspace=0,2, hspace=0,5)

Em [156]: df["A"].plot(ax=axes[0, 0]);

Em [157]: eixos[0, 0].set_title("A");

Em [158]: df["B"].plot(ax=axes[0, 1]);

Em [159]: eixos[0, 1].set_title("B");

(continua na próxima página)

2.15. Visualização de gráfico 737


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [160]: df["C"].plot(ax=axes[1, 0]);

Em [161]: eixos[1, 0].set_title("C");

Em [162]: df["D"].plot(ax=axes[1, 1]);

Em [163]: eixos[1, 1].set_title("D");

Plotando com barras de erro

A plotagem com barras de erro é suportada em DataFrame.plot() e Series.plot().

Barras de erro horizontais e verticais podem ser fornecidas aos argumentos das palavras-chave xerr e yerr para plot(). Os valores
de erro podem ser especificados usando vários formatos:

• Como um DataFrame ou ditado de erros com nomes de colunas correspondentes ao atributo de colunas da plotagem
DataFrame ou correspondente ao atributo name da Série.

• Como uma str indicando quais das colunas do DataFrame plotado contém os valores de erro.

• Como valores brutos (lista, tupla ou np.ndarray). Deve ter o mesmo comprimento do DataFrame/Series de plotagem.

Aqui está um exemplo de uma maneira de representar facilmente as médias do grupo com desvios padrão dos dados brutos.

738 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

# Gere os dados
Em [164]: ix3 = pd.MultiIndex.from_arrays(
.....: [
.....: ["a", "a ", "a", "a", "a", "b ", "b", "b", "b", "b"],
.....: ["foo", "foo", "foo", "bar", "bar", "foo", "foo", "bar", "bar", "bar"],
.....: ],
.....: nomes=["letra", "palavra"],
..... :)
.....:

Em [165]: df3 = pd.DataFrame(


.....: {
.....: "dados1": [9, 3, 2, 4, 3, 2, 4, 6, 3, 2],
.....: "dados2": [9, 6, 5, 7, 5, 4, 5, 6, 5, 1],
.....: },
.....: índice=ix3,
..... :)
.....:

# Agrupe por rótulos de índice e obtenha as médias e desvios padrão


# para cada grupo
Em [166]: gp3 = df3.groupby(level=("letra", "palavra"))

Em [167]: significa = gp3.mean()

Em [168]: erros = gp3.std()

Em [169]: significa
Fora[169]:
dados1 dados2
palavra letra
a barra 3,500000 6,000000
foo 4.666667 6.666667
b barra 3,666667 4,000000
foo 3,000000 4,500000

Em [170]: erros
Fora[170]:
dados1 dados2
palavra letra
a barra 0,707107 1,414214
foo 3.785939 2.081666
b barra 2,081666 2,645751
foo 1,414214 0,707107

# Trama
Em [171]: fig, ax = plt.subplots()

Em [172]: significa.plot.bar(yerr=errors, ax=ax, capsize=4, rot=0);

2.15. Visualização de gráfico 739


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Barras de erro assimétricas também são suportadas, porém valores brutos de erro devem ser fornecidos neste caso. Para uma série de
comprimento N, uma matriz 2xN deve ser fornecida indicando erros inferiores e superiores (ou esquerdo e direito). Para um DataFrame
MxN, os erros assimétricos devem estar em uma matriz Mx2xN.

Aqui está um exemplo de uma maneira de traçar o intervalo mínimo/máximo usando barras de erro assimétricas.

Em [173]: minutos = gp3.min()

Em [174]: maxs = gp3.max()

# erros devem ser positivos e definidos na ordem inferior e superior In [175]: erros = [[means[c] -
mins[c], maxs[c] - mean[c]] for c in df3.columns ]

# Plotar
em [176]: fig, ax = plt.subplots()

Em [177]: significa.plot.bar(yerr=errors, ax=ax, capsize=4, rot=0);

740 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Plotando tabelas

A plotagem com tabela matplotlib agora é suportada em DataFrame.plot() e Series.plot() com uma palavra-chave de tabela. A palavra-
chave table pode aceitar bool, DataFrame ou Series. A maneira simples de desenhar uma tabela é especificar table=True. Os dados
serão transpostos para atender ao layout padrão do matplotlib.

Em [178]: fig, ax = plt.subplots(1, 1, figsize=(7, 6.5))

Em [179]: df = pd.DataFrame(np.random.rand(5, 3), colunas=["a", "b", "c"])

Em [180]: ax.xaxis.tick_top() # Exibe os ticks do eixo x na parte superior.

Em [181]: df.plot(table=True, ax=ax);

2.15. Visualização de gráfico 741


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Além disso, você pode passar um DataFrame ou Série diferente para a palavra-chave table. Os dados serão desenhados conforme exibidos
no método de impressão (não transpostos automaticamente). Se necessário, deve ser transposto manualmente conforme mostrado no
exemplo abaixo.

Em [182]: fig, ax = plt.subplots(1, 1, figsize=(7, 6,75))

Em [183]: ax.xaxis.tick_top() # Exibe os ticks do eixo x na parte superior.

Em [184]: df.plot(table=np.round(df.T, 2), ax=ax);

742 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Também existe uma função auxiliar pandas.plotting.table, que cria uma tabela de DataFrame ou Series e a adiciona a uma instância
matplotlib.Axes. Esta função pode aceitar palavras-chave que a tabela matplotlib possui.

Em [185]: da tabela de importação pandas.plotting

Em [186]: fig, ax = plt.subplots(1, 1)

Em [187]: table(ax, np.round(df.describe(), 2), loc="superior direito", colWidths=[0,2, 0,2,ÿ ÿÿ0,2]);

Em [188]: df.plot(ax=ax, ylim=(0, 2), legend=None);

2.15. Visualização de gráfico 743


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Nota: Você pode obter instâncias de tabela nos eixos usando a propriedade axes.tables para decorações adicionais. Consulte a documentação da tabela
matplotlib para obter mais informações.

Mapas de cores

Um possível problema ao plotar um grande número de colunas é que pode ser difícil distinguir algumas séries devido à repetição das
cores padrão. Para remediar isso, a plotagem DataFrame suporta o uso do argumento colormap, que aceita um mapa de cores Matplotlib
ou uma string que é o nome de um mapa de cores registrado no Matplotlib. Uma visualização dos mapas de cores matplotlib padrão
está disponível aqui.

Como matplotlib não oferece suporte direto a mapas de cores para gráficos baseados em linhas, as cores são selecionadas com base
em um espaçamento uniforme determinado pelo número de colunas no DataFrame. Não há consideração pela cor de fundo; portanto,
alguns mapas de cores produzirão linhas que não são facilmente visíveis.

Para usar o mapa de cores cubehelix, podemos passar colormap='cubehelix'.

Em [189]: df = pd.DataFrame(np.random.randn(1000, 10), index=ts.index)

Em [190]: df = df.cumsum()

Em [191]: plt.figure();

Em [192]: df.plot(colormap="cubehelix");

744 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Alternativamente, podemos passar o próprio mapa de cores:

Em [193]: de matplotlib import cm

Em [194]: plt.figure();

Em [195]: df.plot(colormap=cm.cubehelix);

2.15. Visualização de gráfico 745


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Os mapas de cores também podem ser usados em outros tipos de gráficos, como gráficos de barras:

Em [196]: dd = pd.DataFrame(np.random.randn(10, 10)).applymap(abs)

Em [197]: dd = dd.cumsum()

Em [198]: plt.figure();

Em [199]: dd.plot.bar(colormap="Verdes");

746 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Gráficos de coordenadas paralelas:

Em [200]: plt.figure();

Em [201]: paralelo_coordenadas(dados, "Nome", colormap="gist_rainbow");

2.15. Visualização de gráfico 747


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Gráficos de curvas de Andrews:

Em [202]: plt.figure();

Em [203]: andrews_curves(data, "Nome", colormap="inverno");

748 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.15.6 Plotando diretamente com matplotlib

Em algumas situações ainda pode ser preferível ou necessário preparar gráficos diretamente com matplotlib, por exemplo quando um
certo tipo de gráfico ou personalização (ainda) não é suportado pelo pandas. Os objetos Series e DataFrame se comportam como
arrays e podem, portanto, ser passados diretamente para funções matplotlib sem conversões explícitas.

O pandas também registra automaticamente formatadores e localizadores que reconhecem índices de data, estendendo assim o
suporte de data e hora a praticamente todos os tipos de gráficos disponíveis no matplotlib. Embora essa formatação não forneça o
mesmo nível de refinamento que você obteria ao plotar via pandas, ela pode ser mais rápida ao plotar um grande número de pontos.

Em [204]: preço =
.....: pd.Series( np.random.randn(150).cumsum(),
.....: index=pd.date_range("2000-1-1", períodos=150, freq="B"),
..... :)
.....:

Em [205]: ma = price.rolling(20).mean()

Em [206]: mstd = price.rolling(20).std()

Em [207]: plt.figure();

(continua na próxima página)

2.15. Visualização de gráfico 749


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [208]: plt.plot(price.index, price, "k");

Em [209]: plt.plot(ma.index, ma, "b");

Em [210]: plt.fill_between(mstd.index, ma - 2 * mstd, ma + 2 * mstd, color="b", alpha=0. ÿÿ2);

2.15.7 Plotando back-ends

A partir da versão 0.25, os pandas podem ser estendidos com backends de plotagem de terceiros. A ideia principal é permitir que os
usuários selecionem um backend de plotagem diferente daquele fornecido com base no Matplotlib.

Isso pode ser feito passando 'backend.module' como o argumento backend na função plot. Por exemplo:

>>> Série([1, 2, 3]).plot(backend="backend.module")

Alternativamente, você também pode definir esta opção globalmente, não é necessário especificar a palavra-chave em cada chamada de gráfico.
Por exemplo:

>>> pd.set_option("plotting.backend", "backend.module") >>> pd.Series([1, 2,


3]).plot()

750 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Ou:

>>> pd.options.plotting.backend = "backend.module" >>> pd.Series([1, 2,


3]).plot()

Isso seria mais ou menos equivalente a:

>>> importar backend.module >>>


backend.module.plot(pd.Series([1, 2, 3]))

O módulo backend pode então usar outras ferramentas de visualização (Bokeh, Altair, hvplot,...) para gerar os gráficos. Algumas bibliotecas
que implementam um backend para pandas estão listadas na página ecossistema ecossistema.visualization.

O guia do desenvolvedor pode ser encontrado em https://pandas.pydata.org/docs/dev/development/extending.html#plotting-backends

2.16 Visualização de Tabela

Esta seção demonstra a visualização de dados tabulares usando a classe Styler . Para obter informações sobre visualização com gráficos,
consulte Visualização de gráficos. Este documento foi escrito como um Jupyter Notebook e pode ser visualizado ou baixado aqui.

2.16.1 Objeto Styler e HTML

O estilo deve ser executado após o processamento dos dados em um DataFrame. O Styler cria uma <table> HTML e aproveita a linguagem
de estilo CSS para manipular muitos parâmetros, incluindo cores, fontes, bordas, plano de fundo, etc.
Veja aqui mais informações sobre como estilizar tabelas HTML. Isso permite muita flexibilidade imediata e até permite que os desenvolvedores
da Web integrem DataFrames em seus designs de interface de usuário existentes.

O atributo DataFrame.style é uma propriedade que retorna um objeto Styler . Ele possui um método _repr_html_ definido para que sejam
renderizados automaticamente no Jupyter Notebook.

[2]: importar pandas como pd importar


numpy como np importar
matplotlib como mpl

df = pd.DataFrame([[38,0, 2,0, 18,0, 22,0, 21, np.nan],[19, 439, 6, 452, 226.232]],


index=pd.Index(['Tumor (Positivo)', 'Não Tumor (Negativo)'], nome= ÿÿ'Rótulo Real:'),

columns=pd.MultiIndex.from_product([[' Árvore de Decisão', 'Regressão', ÿÿ'Aleatório'],['Tumor', 'Não Tumor']], nomes=['Modelo:',


'Previsto:'])) df.style

[2]: <pandas.io.formats.style.Styler em 0x7f556b02a1c0>

A saída acima é muito semelhante à representação HTML padrão do DataFrame. Mas o HTML aqui já anexou algumas classes CSS a cada
célula, mesmo que ainda não tenhamos criado nenhum estilo. Podemos visualizá-los chamando o método .to_html() , que retorna o HTML
bruto como string, o que é útil para processamento posterior ou adição a um arquivo - leia mais sobre CSS e HTML. A seguir mostraremos
como podemos usá-los para formatar o DataFrame para ser mais comunicativo. Por exemplo, como podemos construir s:

[4]: s

[4]: <pandas.io.formats.style.Styler em 0x7f556b084e80>

2.16. Visualização de tabela 751


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.16.2 Formatando a exibição

Formatando Valores

Antes de adicionar estilos, é útil mostrar que o Styler pode distinguir o valor de exibição do valor real , tanto nos valores de dados
quanto nos cabeçalhos de índices ou colunas. Para controlar o valor de exibição, o texto é impresso em cada célula como string, e
podemos usar os métodos .format() e .format_index() para manipular isso de acordo com uma string de especificação de formato ou
um callable que recebe um único valor e retorna uma linha. É possível definir isso para toda a tabela, ou índice, ou para colunas
individuais, ou níveis MultiIndex.

Além disso, a função format tem um argumento de precisão para ajudar especificamente na formatação de carros flutuantes,
bem como separadores decimais e de milhares para suportar outras localidades, um argumento na_rep para exibir dados
ausentes e um argumento de escape para ajudar a exibir HTML seguro ou LaTeX seguro. O formatador padrão está configurado
para adotar o styler.format do pandas. opção de precisão, controlável usando pd.option_context('format.precision', 2):

[5]: df.style.format(precision=0, na_rep='MISSING', milhares=" ", formatador={(' Árvore de decisão',


'Tumour'): "{:.2f}",
('Regressão', 'Não Tumor'): lambda x: "$ {:,.1f}".format(x*-
ÿÿ1e6)
})

[5]: <pandas.io.formats.style.Styler em 0x7f55a7e47160>

Usar o Styler para manipular a exibição é um recurso útil porque manter a indexação e os valores dos dados para outros fins
proporciona maior controle. Você não precisa sobrescrever seu DataFrame para exibi-lo como desejar. Aqui está um exemplo
de uso das funções de formatação enquanto ainda depende dos dados subjacentes para indexação e cálculos.

[6]: clima_df = pd.DataFrame(np.random.rand(10,2)*5,


index=pd.date_range(start="2021-01-01", períodos=10), colunas=["Tóquio",
"Pequim"])

def condição_de_chuva(v): se
v < 1,75:
retornar elif
"seco" v < 2,75:
retornar "Chuva"
retornar "Chuva Forte"

def make_pretty(styler):
styler.set_caption(" Condições climáticas")
styler.format(rain_condition)
styler.format_index(lambda v: v.strftime("%A"))
styler.background_gradient(axis=None, vmin=1, vmax=5, cmap="YlGnBu") modelador de
retorno

clima_df

[6]: Tóquio Pequim


2021-01-01 1,927556 1,244050 2021-01-02
1,036963 4,590397 2021-01-03 2,282043
0,490798 2021-01-04 2,181464 2,078760
202 01/01/05 4,799366 2,708158
06/01/2021 4,929870 3,772979 07/01/2021
0,884767 3.270572

(continua na próxima página)

752 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


2021-01-08 1.794581 0.738253
2021-01-09 1.243286 4.217605
2021-01-10 0,036861 4,175243

[7]: weather_df.loc["2021-01-04":"2021-01-08"].style.pipe(make_pretty)

[7]: <pandas.io.formats.style.Styler em 0x7f556b02a280>

Ocultando dados

Os cabeçalhos do índice e das colunas podem ser completamente ocultos, bem como subselecionar linhas ou colunas que se deseja excluir.
Ambas as opções são executadas usando os mesmos métodos.

O índice pode ser ocultado da renderização chamando .hide() sem nenhum argumento, o que pode ser útil se o seu índice for baseado em
números inteiros. Da mesma forma, os cabeçalhos das colunas podem ser ocultados chamando .hide(axis=“columns”) sem quaisquer
argumentos adicionais.

Linhas ou colunas específicas podem ser ocultadas da renderização chamando o mesmo método .hide() e passando um rótulo de linha/
coluna, um tipo de lista ou uma fatia de rótulos de linha/coluna para o argumento do subconjunto.

Ocultar não altera a disposição inteira das classes CSS, por exemplo, ocultar as duas primeiras colunas de um DataFrame significa que a
indexação da classe de coluna ainda começará em col2, já que col0 e col1 são simplesmente ignorados.

Podemos atualizar nosso objeto Styler anterior para ocultar alguns dados e formatar os valores.

[8]: s = df.style.format('{:.0f}').hide([('Random', 'Tumour'), ('Random', 'Non-Tumour')],ÿ


ÿÿeixo="colunas")
é

[8]: <pandas.io.formats.style.Styler em 0x7f55a7e1c100>

2.16.3 Métodos para adicionar estilos

Existem 3 métodos principais para adicionar estilos CSS personalizados ao Styler:

• Usando .set_table_styles() para controlar áreas mais amplas da tabela com CSS interno especificado. Embora os estilos de tabela permitam
flexibilidade para adicionar seletores e propriedades CSS que controlam todas as partes individuais da tabela, eles são difíceis de manejar
para especificações de células individuais. Além disso, observe que os estilos de tabela não podem ser exportados para Excel.

• Usar .set_td_classes() para vincular diretamente classes CSS externas às suas células de dados ou vincular as classes CSS internas
criadas por .set_table_styles(). Veja aqui. Eles não podem ser usados em linhas ou índices de cabeçalho de coluna e também não
serão exportados para Excel.

• Usando as funções .apply() e .applymap() para adicionar CSS interno direto a células de dados específicas. Veja aqui. A partir da
versão 1.4.0 também existem métodos que funcionam diretamente nas linhas ou índices do cabeçalho da coluna; .apply_index()
e .ap-plymap_index(). Observe que apenas esses métodos adicionam estilos que serão exportados para Excel. Esses métodos
funcionam de maneira semelhante a DataFrame.apply() e DataFrame.applymap().

2.16. Visualização de tabela 753


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.16.4 Estilos de Tabela

Os estilos de tabela são flexíveis o suficiente para controlar todas as partes individuais da tabela, incluindo cabeçalhos de colunas e índices. No
entanto, eles podem ser difíceis de digitar para células de dados individuais ou para qualquer tipo de formatação condicional, por isso recomendamos
que os estilos de tabela sejam usados para estilos amplos, como linhas ou colunas inteiras de uma vez.

Os estilos de tabela também são usados para controlar recursos que podem ser aplicados a toda a tabela de uma vez, como a criação de uma
funcionalidade genérica de foco. O pseudo-seletor :hover, assim como outros pseudo-seletores, só podem ser usados desta forma.

Para replicar o formato normal de seletores e propriedades CSS (pares de valores de atributos), por exemplo

tr:hover { cor
de fundo: #ffff99;
}

o formato necessário para passar estilos para .set_table_styles() é uma lista de dictos, cada um com uma tag seletora de CSS e
propriedades CSS. As propriedades podem ser uma lista de 2 tuplas ou uma string CSS regular, por exemplo:

[10]: cell_hover = { # para passar o mouse sobre a linha use <tr> em vez de <td>
'selector': 'td:hover', 'props':
[('background-color', '#ffffb3')]

} index_names =
{ 'seletor': '.index_name', 'props':
'estilo de fonte: itálico; cor: cinza escuro; peso da fonte:normal;'

} cabeçalhos = {
'seletor': 'th:not(.index_name)', 'props': 'cor de
fundo: #000066; cor branca;'

} s.set_table_styles([cell_hover, index_names, cabeçalhos])

[10]: <pandas.io.formats.style.Styler em 0x7f55a7e1c100>

Em seguida, apenas adicionamos mais alguns artefatos de estilo direcionados a partes específicas da tabela. Tenha cuidado aqui, já que
estamos encadeando métodos , precisamos instruir explicitamente o método a não sobrescrever os estilos existentes.

[12]: s.set_table_styles([ {'selector':


'th.col_heading', 'props': 'text-align: center;'}, {'selector': 'th.col_heading.level0', 'props' :
'tamanho da fonte: 1,5em;'}, {'selector': 'td', 'props': 'alinhamento de texto: centro; peso da fonte:
negrito;'}, ], substituir=Falso)

[12]: <pandas.io.formats.style.Styler em 0x7f55a7e1c100>

Como método de conveniência (desde a versão 1.2.0), também podemos passar um ditado para .set_table_styles() que contém chaves
de linha ou coluna. Nos bastidores, o Styler apenas indexa as chaves e adiciona classes .col<m> ou .row<n> relevantes conforme
necessário aos seletores CSS fornecidos.

[14]: s.set_table_styles({
('Regressão', 'Tumor'): [{'selector': 'th', 'props': 'border-left: 1px branco sólido ÿÿ'},

{'selector': 'td', 'props': 'border-left: 1px sólido


ÿÿ#000066'}] },
substituir=Falso, eixo=0)

754 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

[14]: <pandas.io.formats.style.Styler em 0x7f55a7e1c100>

2.16.5 Configurando Classes e Vinculando a CSS Externo

Se você projetou um site, é provável que já tenha um arquivo CSS externo que controla o estilo de tabelas e objetos de células
dentro dele. Você pode querer usar esses arquivos nativos em vez de duplicar todo o CSS em python (e duplicar qualquer trabalho
de manutenção).

Atributos da tabela

É muito fácil adicionar uma classe à <table> principal usando .set_table_attributes(). Este método também pode anexar estilos
embutidos - leia mais em Hierarquias CSS.

[16]: out = s.set_table_attributes('class="my-table-cls"').to_html() print(out[out.find('<table'):][:109])

<table id="T_xyz01" class="my-table-cls">


<thead>
<tr>
<th class="index_name level0" >Modelo:</th>

Classes CSS de células de dados

Novo na versão 1.2.0

O método .set_td_classes() aceita um DataFrame com índices e colunas correspondentes ao DataFrame do Styler subjacente . Esse
DataFrame conterá strings como classes css para adicionar a células de dados individuais: os elementos <td> da <table>. Em vez
de usar CSS externo, criaremos nossas classes internamente e as adicionaremos ao estilo da tabela. Salvaremos a adição de bordas
até a seção de dicas de ferramentas.

[17]: s.set_table_styles([ # cria classes CSS internas


{'seletor': '.true', 'props': 'cor de fundo: #e6ffe6;'}, {'seletor': '.false', 'props': 'cor de fundo:
#ffe6e6;'}, ], substituir=Falso) cell_color = pd.DataFrame([['true ', 'false ', 'true ', 'false '],
['false ', 'true ', 'false ', 'true
']], índice=df.index, colunas=df.columns[:4])

s.set_td_classes(cell_color)

[17]: <pandas.io.formats.style.Styler em 0x7f55a7e1c100>

2.16. Visualização de tabela 755


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.16.6 Funções do estilizador

Agindo com base nos dados

Usamos os seguintes métodos para passar suas funções de estilo. Ambos os métodos pegam uma função (e alguns outros argumentos
de palavras-chave) e aplicam-na ao DataFrame de uma determinada maneira, renderizando estilos CSS.

• .applymap() (elementwise): aceita uma função que recebe um único valor e retorna uma string com o atributo CSS-
par de valores.

• .apply() (coluna/linha/tabela): aceita uma função que pega uma Série ou DataFrame e retorna uma Série, DataFrame ou matriz
numpy com uma forma idêntica, onde cada elemento é uma string com um atributo CSS par de valores. Este método passa cada
coluna ou linha do seu DataFrame, uma de cada vez, ou a tabela inteira de uma vez, dependendo do argumento da palavra-
chave do eixo. Para coluna use axis=0, rowwise use axis=1, e para toda a tabela de uma vez use axis=None.

Este método é poderoso para aplicar lógica múltipla e complexa a células de dados. Criamos um novo DataFrame para demonstrar isso.

[19]: np.random.seed(0) df2 =


pd.DataFrame(np.random.randn(10,4), colunas=['A','B','C','D']) df2 .estilo

[19]: <pandas.io.formats.style.Styler em 0x7f556c6fde80>

Por exemplo, podemos construir uma função que colore o texto se for negativo e encadear isso com uma função que esmaece
parcialmente células de valor insignificante. Como isso analisa cada elemento, usamos applymap.

[20]: def style_negative(v, props=''): retorna adereços se


v < 0 else Nenhum
s2 = df2.style.applymap(style_negative, props='color:red;')\ .applymap(lambda v: 'opacity:
20%;' if (v < 0,3) e (v > -0,3) else Nenhum)
s2

[20]: <pandas.io.formats.style.Styler em 0x7f55a7df1bb0>

Também podemos construir uma função que destaque o valor máximo em linhas, colunas e DataFrame de uma só vez. Neste caso
usamos aplicar. Abaixo destacamos o máximo em uma coluna.

[22]: def destaque_max(s, adereços=''): return


np.where(s == np.nanmax(s.valores), adereços, '')
s2.apply(highlight_max, props='cor:branco;cor de fundo:azul escuro', eixo=0)

[22]: <pandas.io.formats.style.Styler em 0x7f55a7df1bb0>

Podemos usar a mesma função nos diferentes eixos, destacando aqui o máximo do DataFrame em roxo e os máximos das linhas em
rosa.

[24]: s2.apply(highlight_max, props='cor:branco;cor de fundo:rosa;', eixo=1)\


.apply(highlight_max, props='cor:branco;cor de fundo:roxo', eixo=Nenhum)

[24]: <pandas.io.formats.style.Styler em 0x7f55a7df1bb0>

Este último exemplo mostra como alguns estilos foram substituídos por outros. Em geral o estilo aplicado mais recentemente está ativo,
mas você pode ler mais na seção sobre hierarquias CSS. Você também pode aplicar esses estilos a partes mais granulares do
DataFrame - leia mais na seção sobre fatiamento de subconjuntos.

É possível replicar algumas dessas funcionalidades usando apenas classes, mas pode ser mais complicado. Veja item 3) de Otimização

756 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Dica de depuração: se você estiver tendo problemas para escrever sua função de estilo, tente simplesmente passá-la para
DataFrame.apply. Internamente, Styler.apply usa DataFrame.apply então o resultado deve ser o mesmo, e com DataFrame.apply
você poderá inspecionar a saída da string CSS da função pretendida em cada célula.

Atuando no índice e nos cabeçalhos das colunas

Aplicação semelhante é obtida para cabeçalhos usando:

• .applymap_index() (elementwise): aceita uma função que recebe um único valor e retorna uma string com o CSS
par atributo-valor.

• .apply_index() (nível): aceita uma função que pega uma Série e retorna uma Série, ou array numpy com formato idêntico onde
cada elemento é uma string com um par atributo-valor CSS. Este método passa cada nível do seu índice, um de cada vez.
Para estilizar o índice use axis=0 e para estilizar os cabeçalhos das colunas use axis=1.

Você pode selecionar um nível de MultiIndex, mas atualmente nenhum aplicativo de subconjunto semelhante está disponível para esses métodos.

[26]: s2.applymap_index(lambda v: "color:pink;" if v>4 else "color:darkblue;", eixo=0)


s2.apply_index(lambda s: np.where(s.isin(["A", "B"]), "cor:rosa;", "cor:azul escuro;"),ÿ ÿÿeixo=1)

[26]: <pandas.io.formats.style.Styler em 0x7f55a7df1bb0>

2.16.7 Dicas e legendas

As legendas da tabela podem ser adicionadas com o método .set_caption() . Você pode usar estilos de tabela para controlar o CSS relevante para
a legenda.

[27]: s.set_caption(" Matriz de confusão para vários modelos de previsão de câncer.")\


.set_table_styles([{ 'seletor':
'caption', 'props': 'caption-side:
bottom; font-size:1.25em;' }], overwrite=False)

[27]: <pandas.io.formats.style.Styler em 0x7f55a7e1c100>

Adicionar dicas de ferramentas (desde a versão 1.3.0) pode ser feito usando o método .set_tooltips() da mesma forma que você pode
adicionar classes CSS a células de dados, fornecendo um DataFrame baseado em string com índices e colunas que se cruzam. Você não
precisa especificar um nome css_class ou qualquer adereço css para as dicas de ferramentas, pois existem padrões padrão, mas a opção
existe se você quiser mais controle visual.

[29]: tt = pd.DataFrame([['Este modelo tem uma taxa de verdadeiros positivos muito forte', "O número total de
falsos negativos deste modelo é muito alto"]],
index=['Tumor (Positivo)'], colunas=df.columns[[0,3]])
s.set_tooltips(tt, props='visibilidade: oculto; posição: absoluto; índice z: 1; borda:ÿ ÿÿ1px sólido #000066;'

'cor de fundo: branco; cor: #000066; tamanho da fonte: 0,8em;' 'transformar: traduzir(0px,
-24px); preenchimento: 0,6em; fronteira-
ÿÿraio: 0,5em;')

[29]: <pandas.io.formats.style.Styler em 0x7f55a7e1c100>

2.16. Visualização de tabela 757


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

A única coisa que falta fazer em nossa tabela é adicionar bordas de destaque para chamar a atenção do público para as dicas de ferramentas.
Criaremos classes CSS internas como antes, usando estilos de tabela. Definir classes sempre sobrescreve, então precisamos ter
certeza de adicionar as classes anteriores.

[31]: s.set_table_styles([ # criar classes CSS internas {'selector': '.border-red', 'props':


'border: 2px dashed red;'}, {'selector': '.border-green ', 'props': 'border: 2px tracejado verde;'}, ],
overwrite=False) cell_border = pd.DataFrame([['border-green ', ' ', ' ', 'border-red '],

[' ', ' ', ' ', ' ']], índice=df.index,


colunas=df.columns[:4])
s.set_td_classes(cell_color +
cell_border)

[31]: <pandas.io.formats.style.Styler em 0x7f55a7e1c100>

2.16.8 Controle mais preciso com fatiamento

Os exemplos que mostramos até agora para as funções Styler.apply e Styler.applymap não demonstraram o uso do argumento subset.
Este é um argumento útil que permite muita flexibilidade: permite aplicar estilos a linhas ou colunas específicas, sem ter que codificar essa
lógica em sua função de estilo.

O valor passado para o subconjunto se comporta de maneira semelhante ao fatiamento de um DataFrame;

• Um escalar é tratado como um rótulo de coluna

• Uma lista (ou matriz de série ou NumPy) é tratada como vários rótulos de coluna

• Uma tupla é tratada como (row_indexer, column_indexer)

Considere usar pd.IndexSlice para construir a tupla do último. Criaremos um DataFrame MultiIndexed para demonstrar a funcionalidade.

[33]: df3 = pd.DataFrame(np.random.randn(4,4),


pd.MultiIndex.from_product([['A', 'B'], ['r1', 'r2']]), colunas=['c1','c2','c3','c4'])

df3

[33]: c1 c2 c3 c4 A r1 -1,048553 -1,420018


-1,706270 1,950775 r2 -0,509652 -0,438074 -1,252795 0,777490 B
r1 -1,613898 -0,212740 -0,895467 0,386 902 r2 -0,510805
-1,180632 -0,028182 0,428332

Usaremos subconjunto para destacar o máximo na terceira e quarta colunas com texto em vermelho. Destacaremos a região fatiada
do subconjunto em amarelo.

[34]: slice_ = ['c3', 'c4']


df3.style.apply(highlight_max, props='color:red;', axis=0, subset=slice_)\ .set_properties(**{'background- cor':
'#ffffb3'}, subconjunto=fatia_)

[34]: <pandas.io.formats.style.Styler em 0x7f55a7df7fd0>

Se combinado com o IndexSlice conforme sugerido, ele poderá indexar ambas as dimensões com maior flexibilidade.

758 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

[35]: idx = pd.IndexSlice slice_ =


idx[idx[:,'r1'], idx['c2':'c4']] df3.style.apply(highlight_max,
props='color:red;', eixo=0, subconjunto=fatia_)\ .set_properties(**{'cor de fundo': '#ffffb3'}, subconjunto=fatia_)

[35]: <pandas.io.formats.style.Styler em 0x7f55a7da00a0>

Isso também fornece flexibilidade para subselecionar linhas quando usado com o eixo = 1.

[36]: slice_ = idx[idx[:,'r2'], :]


df3.style.apply(highlight_max, props='color:red;', axis=1, subset=slice_)\ .set_properties(** {'cor de fundo':
'#ffffb3'}, subconjunto = fatia_)

[36]: <pandas.io.formats.style.Styler em 0x7f55a7df1b80>

Também há espaço para fornecer filtragem condicional.

Suponha que queiramos destacar o máximo nas colunas 2 e 4 apenas no caso de a soma das colunas 1 e 3 ser menor que -2,0
(essencialmente excluindo as linhas (:,'r2')).

[37]: fatia_ = idx[idx[(df3['c1'] + df3['c3']) < -2,0], ['c2', 'c4']]


df3.style.apply(highlight_max, props='color:red;', axis=1, subset=slice_)\ .set_properties(**{'background-color':
'#ffffb3'}, subset=slice_)

[37]: <pandas.io.formats.style.Styler em 0x7f55a7d8cd30>

Somente o fatiamento baseado em rótulo é suportado no momento, não posicional e não chamável.

Se sua função de estilo usa um argumento de palavra-chave de subconjunto ou eixo, considere agrupar sua função em um arquivo
functools. parcial, parcializando essa palavra-chave.

minha_func2 = functools.partial(minha_func, subconjunto=42)

2.16.9 Otimização

Geralmente, para tabelas menores e na maioria dos casos, o HTML renderizado não precisa ser otimizado e não recomendamos isso.
Existem dois casos em que vale a pena considerar:

• Se você estiver renderizando e estilizando uma tabela HTML muito grande, alguns navegadores terão problemas de desempenho.

• Se você estiver usando o Styler para criar dinamicamente parte de interfaces de usuário on-line e quiser melhorar o desempenho da rede
desempenho.

Aqui recomendamos as seguintes etapas para implementação:

1. Remova UUID e cell_ids

Ignore o uuid e defina cell_ids como False. Isso evitará HTML desnecessário.

Isso está abaixo do ideal:

[38]: df4 = pd.DataFrame([[1,2],[3,4]]) s4 = df4.style

2.16. Visualização de tabela 759


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Isto é melhor:

[39]: de pandas.io.formats.style importar Styler


s4 = Estilizador(df4, uuid_len=0, cell_ids=False)

2. Use estilos de tabela

Use estilos de tabela sempre que possível (por exemplo, para todas as células, linhas ou colunas de cada vez), pois o CSS é quase sempre
mais eficiente que outros formatos.

Isso está abaixo do ideal:

[40]: adereços = 'família de fontes: "Times New Roman", Times, serif; cor: #e83e8c; tamanho da fonte: 1,3em;'
df4.style.applymap(lambda x: adereços, subconjunto=[1])

[40]: <pandas.io.formats.style.Styler em 0x7f55a7d8c220>

Isto é melhor:

[41]: df4.style.set_table_styles([{'selector': 'td.col1', 'props': adereços}])

[41]: <pandas.io.formats.style.Styler em 0x7f55a7da0520>

3. Defina classes em vez de usar funções do Styler

Para DataFrames grandes onde o mesmo estilo é aplicado a muitas células, pode ser mais eficiente declarar os estilos como
classes e depois aplicar essas classes às células de dados, em vez de aplicar estilos diretamente às células. No entanto,
provavelmente ainda é mais fácil usar a API da função Styler quando você não está preocupado com a otimização.

Isso está abaixo do ideal:

[42]: df2.style.apply(highlight_max, props='color:white;background-color:darkblue;', axis=0)\ .apply(highlight_max,


props='color:white;background-color:pink; ', eixo=1)\ .apply(highlight_max, props='cor:branco;cor de
fundo:roxo', eixo=Nenhum)

[42]: <pandas.io.formats.style.Styler em 0x7f55a7df72e0>

Isto é melhor:

[43]: build = lambda x: pd.DataFrame (x, índice = df2.index, colunas = df2.columns)


cls1 = build(df2.apply(highlight_max, props='cls-1 ', eixo=0)) cls2 =
build(df2.apply(highlight_max, props='cls-2 ', eixo=1, result_type='expandir' ). ÿÿvalores) cls3 = build(highlight_max(df2,
props='cls-3
'))
(continua na próxima página)

760 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

df2.style.set_table_styles([
{'seletor': '.cls-1', 'props': 'cor:branco;cor de fundo:azul escuro;'}, {'seletor': '.cls-2', 'props': 'cor:branco ;cor de
fundo: rosa;'}, {'selector': '.cls-3', 'props': 'cor: branco; cor de fundo: roxo;'}

]).set_td_classes(cls1 + cls2 + cls3)

[43]: <pandas.io.formats.style.Styler em 0x7f556b78c820>

4. Não use dicas de ferramentas

As dicas de ferramentas exigem que cell_ids funcionem e geram elementos HTML extras para cada célula de dados.

5. Se cada byte contar, use a substituição de string

Você pode remover HTML desnecessário ou encurtar os nomes de classe padrão substituindo o ditado CSS padrão. Você pode ler
um pouco mais sobre CSS abaixo.

[44]: meu_css = {
"row_heading": "",
"col_heading": "",
"index_name": "", "col":
"c", "row": "r",
"col_trim": "",
"row_trim": "" , "nível":
"l", "dados": "", "em
branco": "",

} html = Styler(df4, uuid_len=0, cell_ids=False)


html.set_table_styles([{'seletor': 'td', 'props': adereços}, {'seletor': '.c1', 'adereços':
'color:green;'}, {'selector': '.l0', 'props': 'color:blue;'}],
css_class_names=my_css)

imprimir(html.to_html())

<style type="text/css"> #T_ td


{ font-family:
"Times New Roman", Times, serif; cor: #e83e8c; tamanho da
fonte: 1,3em;

}
#T_ .c1 { cor:
verde;
}
#T_ .l0 { cor:
azul;

} </style>
<table id="T_">
<thead>
(continua na próxima página)

2.16. Visualização de tabela 761


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


<tr>
<th class=" l0" >&nbsp;</th> <th class="
l0 c0" >0</th> <th class=" l0 c1" >1</
th> </tr> </thead> <corpo>

<tr>
<th class=" l0 r0" >0</th> <td class="
r0 c0" >1</td> <td class=" r0 c1" >2</
td> </tr>

<tr>
<th class=" l0 r1" >1</th> <td class="
r1 c0" >3</td> <td class=" r1 c1" >4</
td> </tr> </tbody> </tabela>

[45]: html

[45]: <pandas.io.formats.style.Styler em 0x7f55a7d8ce50>

2.16.10 Estilos integrados

Algumas funções de estilo são tão comuns que nós as “incorporamos” ao Styler, então você não precisa escrevê-las e aplicá-las
você mesmo. A lista atual de tais funções é:

• .highlight_null: para uso na identificação de dados faltantes.

• .highlight_min e .highlight_max: para uso na identificação de extremos em dados.

• .highlight_between e .highlight_quantile: para uso na identificação de classes dentro dos dados.

• .background_gradient: um método flexível para destacar células com base em seus ou outros valores em uma escala numérica.

• .text_gradient: método semelhante para destacar texto com base em seus ou outros valores em uma escala numérica.

• .bar: para exibir minigráficos nos fundos das células.

A documentação individual de cada função geralmente fornece mais exemplos de seus argumentos.

Destacar Nulo

[46]: df2.iloc[0,2] = np.nan df2.iloc[4,3]


= np.nan
df2.loc[:4].style.highlight_null(null_color='yellow')

[46]: <pandas.io.formats.style.Styler em 0x7f55a7dad250>

762 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Destaque Min ou Max

[47]: df2.loc[:4].style.highlight_max(axis=1, props='color:white; font-weight:bold; background- ÿÿcolor:darkblue;')

[47]: <pandas.io.formats.style.Styler em 0x7f55a7de6760>

Destacar entre

Este método aceita intervalos como float ou matrizes NumPy ou séries, desde que os índices correspondam.

[48]: esquerda = pd.Series([1.0, 0.0, 1.0], índice=["A", "B", "D"])


df2.loc[:4].style.highlight_between(esquerda=esquerda, direita=1,5, eixo=1, adereços='cor:branco;ÿ ÿÿcor de fundo:roxo;')

[48]: <pandas.io.formats.style.Styler em 0x7f55a7dad460>

Destacar Quantil

Útil para detectar os valores percentuais mais altos ou mais baixos

[49]: df2.loc[:4].style.highlight_quantile(q_left=0,85, axis=None, color='yellow')

[49]: <pandas.io.formats.style.Styler em 0x7f55a7da0fa0>

Gradiente de fundo e gradiente de texto

Você pode criar “mapas de calor” com os métodos background_gradient e text_gradient. Eles requerem matplotlib, e usaremos
Seaborn para obter um bom mapa de cores.

[50]: importar seaborn como sns cm =


sns.light_palette("green", as_cmap=True)

df2.style.background_gradient(cmap=cm)

[50]: <pandas.io.formats.style.Styler em 0x7f55a7dadcd0>

[51]: df2.style.text_gradient(cmap=cm)

[51]: <pandas.io.formats.style.Styler em 0x7f55a7da0250>

.background_gradient e .text_gradient possuem vários argumentos de palavras-chave para personalizar os gradientes e cores.
Veja a documentação.

2.16. Visualização de tabela 763


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Definir propriedades

Use Styler.set_properties quando o estilo não depender realmente dos valores. Este é apenas um wrapper simples para .applymap
onde a função retorna as mesmas propriedades para todas as células.

[52]: df2.loc[:4].style.set_properties(**{'cor de fundo': 'preto',


'cor': 'gramado', 'cor da
borda': 'branco'})

[52]: <pandas.io.formats.style.Styler em 0x7f555b156520>

Gráficos de barra

Você pode incluir “gráficos de barras” em seu DataFrame.

[53]: df2.style.bar(subset=['A', 'B'], color='#d65f5f')

[53]: <pandas.io.formats.style.Styler em 0x7f55a7da0b50>

Argumentos de palavras-chave adicionais fornecem mais controle sobre centralização e posicionamento, e você pode passar uma
lista de [color_negative, color_positivo] para destacar valores mais baixos e mais altos ou um mapa de cores matplotlib.

Para mostrar um exemplo, veja como você pode alterar o acima com a nova opção de alinhamento, combinada com a configuração
dos limites vmin e vmax, a largura da figura e os adereços css subjacentes das células, deixando espaço para exibir o texto e as
barras. Também usamos text_gradient para colorir o texto da mesma forma que as barras usando um mapa de cores matplotlib
(embora neste caso a visualização seja provavelmente melhor sem este efeito adicional).

[54]: df2.style.format('{:.3f}', na_rep="")\ .bar(align=0, vmin=-2.5,


vmax=2.5, cmap="bwr", height=50,
largura=60, props="largura: 120px; borda direita: 1px preto sólido;")\
.text_gradient(cmap="bwr", vmin=-2,5, vmax=2,5)

[54]: <pandas.io.formats.style.Styler em 0x7f555b158b50>

O exemplo a seguir visa dar um destaque ao comportamento das novas opções de alinhamento:

[56]: HTML (cabeçalho)

[56]: <objeto IPython.core.display.HTML>

2.16.11 Compartilhando estilos

Digamos que você tenha um estilo adorável criado para um DataFrame e agora queira aplicar o mesmo estilo a um segundo DataFrame.
Exporte o estilo com df1.style.export e importe-o no segundo DataFrame com df1.style.set

[57]: style1 =
df2.style\ .applymap(style_negative, props='color:red;')\ .applymap(lambda v:
'opacity: 20%;' if (v < 0,3) e (v > -0,3 ) else Nenhum)\ .set_table_styles([{"selector": "th", "props": "color:
blue;"}])\ .hide(axis="index")

estilo1

[57]: <pandas.io.formats.style.Styler em 0x7f55a7da0df0>

764 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

[58]: estilo2 = df3.estilo


estilo2.use(estilo1.export()) estilo2

[58]: <pandas.io.formats.style.Styler em 0x7f55a7da0fd0>

Observe que você pode compartilhar os estilos mesmo que eles reconheçam os dados. Os estilos são reavaliados no novo
DataFrame em que foram usados.

2.16.12 Limitações

• Somente DataFrame (use Series.to_frame().style)

• O índice e as colunas não precisam ser exclusivos, mas determinadas funções de estilo só podem funcionar com índices exclusivos.

• Não há grande repr e o desempenho da construção não é ótimo; embora tenhamos algumas otimizações de HTML

• Você só pode aplicar estilos, não pode inserir novas entidades HTML, exceto através de subclasses.

2.16.13 Outras coisas divertidas e úteis

Aqui estão alguns exemplos interessantes.

Widgets

O Styler interage muito bem com widgets. Se você estiver visualizando isso on-line em vez de executar o notebook sozinho, estará
perdendo o ajuste interativo da paleta de cores.

[59]: de ipywidgets importar widgets @widgets.interact


def f(h_neg=(0, 359, 1),
h_pos=(0, 359), s=(0., 99,9), l=(0., 99,9) ):
retornar df2.style.background_gradient(
cmap=sns.palettes.diverging_palette(h_neg=h_neg, h_pos=h_pos, s=s, l=l, as_cmap=True)

interativo(filhos=(IntSlider(valor=179, descrição='h_neg', max=359),ÿ ÿÿIntSlider(valor=179, descrição='h_...

Ampliar

[60]: def magnify(): return


[dict(selector="th", props=[("tamanho
da fonte", "4pt")]), dict(selector="td",
props=[('padding ', "0em
0em")]), dict(selector="th:hover",
props=[("tamanho da fonte", "12pt")]),

dict(selector="tr:hover td:hover",
adereços=[('largura máxima', '200px'),
('tamanho da fonte', '12pt')])
]

2.16. Visualização de tabela 765


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

[61]: np.random.seed(25) cmap


= cmap=sns.diverging_palette(5, 250, as_cmap=True) bigdf =
pd.DataFrame(np.random.randn(20, 25)).cumsum()

bigdf.style.background_gradient(cmap,
axis=1)\ .set_properties(**{'max-width': '80px', 'font-size': '1pt'})\ .set_caption("Passe o
mouse para ampliar")

\ .format(precisão=2)\ .set_table_styles(magnificar())

[61]: <pandas.io.formats.style.Styler em 0x7f555b0f9e80>

Cabeçalhos fixos

Se você exibir uma matriz grande ou DataFrame em um notebook, mas quiser sempre ver os cabeçalhos das colunas e
linhas, poderá usar o método .set_sticky que manipula os estilos de tabela CSS.

[62]: bigdf = pd.DataFrame(np.random.randn(16, 100))


bigdf.style.set_sticky(axis="index")

[62]: <pandas.io.formats.style.Styler em 0x7f555b08edf0>

Também é possível colar MultiIndexes e até mesmo níveis específicos.

[63]: bigdf.index = pd.MultiIndex.from_product([["A","B"],[0,1],[0,1,2,3]]) bigdf.style.set_sticky(axis=


"índice", pixel_size=18, níveis=[1,2])

[63]: <pandas.io.formats.style.Styler em 0x7f555b08e4f0>

Escape de HTML

Suponha que você precise exibir HTML dentro de HTML, o que pode ser um pouco complicado quando o renderizador não consegue distinguir.
Você pode usar a opção de formatação de escape para lidar com isso e até mesmo usá-la em um formatador que contenha o próprio HTML.

[64]: df4 = pd.DataFrame([['<div></div>', '"&other"', '<span>']])


df4.style

[64]: <pandas.io.formats.style.Styler em 0x7f555b07ad60>

[65]: df4.style.format(escape="html")

[65]: <pandas.io.formats.style.Styler em 0x7f555b07a9a0>

[66]: df4.style.format(' <a href="https://pandas.pydata.org" target="_blank"> {}</a>', escape=


ÿÿ"html")

[66]: <pandas.io.formats.style.Styler em 0x7f555b06bd30>

766 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.16.14 Exportar para Excel

Algum suporte (desde a versão 0.20.0) está disponível para exportar DataFrames estilizados para planilhas do Excel usando os
mecanismos OpenPyXL ou XlsxWriter. As propriedades CSS2.2 tratadas incluem:

• cor de fundo

• cor

• família de fontes

• estilo de fonte

• espessura da fonte

• alinhamento de texto

• decoração de texto

• alinhamento vertical

• espaço em branco: nowrap

• Atualmente quebrado: estilo de borda, largura de borda, cor de borda e suas {variáveis superior, direita, inferior, esquerda
formigas}

• Somente cores nomeadas CSS2 e cores hexadecimais no formato #rgb ou #rrggbb são atualmente suportadas.

• As seguintes propriedades pseudo CSS também estão disponíveis para definir propriedades de estilo específicas do Excel:

– formato numérico

Estilos de nível de tabela e classes CSS de células de dados não estão incluídos na exportação para Excel: células individuais devem
ter suas propriedades mapeadas pelos métodos Styler.apply e/ou Styler.applymap.

[67]: df2.style.\
applymap(style_negative, props='color:red;').\ destaque_max(axis=0).
\ to_excel('styled.xlsx',
engine='openpyxl')

Uma captura de tela da saída:

2.16. Visualização de tabela 767


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.16.15 Exportar para LaTeX

Existe suporte (desde a versão 1.3.0) para exportar Styler para LaTeX. A documentação do método .to_latex fornece mais detalhes e
vários exemplos.

2.16.16 Mais sobre CSS e HTML

A linguagem Cascading Style Sheet (CSS), projetada para influenciar como um navegador renderiza elementos HTML, tem suas
próprias peculiaridades. Ele nunca relata erros: apenas os ignora silenciosamente e não renderiza seus objetos como você deseja, o
que às vezes pode ser frustrante. Aqui está uma breve introdução sobre como o Styler cria HTML e interage com CSS, com conselhos
sobre armadilhas comuns a serem evitadas.

Classes e IDs CSS

A estrutura precisa da classe CSS anexada a cada célula é a seguinte.

• Células com nomes de índice e coluna incluem index_name e level<k> onde k é seu nível em um MultiIndex

• As células do rótulo do índice incluem

– cabeçalho_da_linha

– level<k> onde k é o nível em um MultiIndex

– row<m> onde m é a posição numérica da linha

• As células do rótulo da coluna incluem

– col_heading

– level<k> onde k é o nível em um MultiIndex

– col<n> onde n é a posição numérica da coluna

• As células de dados incluem

– dados

– linha<m>, onde m é a posição numérica da célula.

– col<n>, onde n é a posição numérica da célula.

• Células em branco incluem espaços em branco

• As células aparadas incluem col_trim ou row_trim

A estrutura do id é T_uuid_level<k>_row<m>_col<n> onde level<k> é usado apenas em títulos, e os cabeçalhos terão apenas
row<m> ou col<n> o que for necessário. Por padrão, também acrescentamos cada identificador de linha/coluna com um UUID
exclusivo para cada DataFrame para que o estilo de um não colida com o estilo de outro dentro do mesmo bloco de notas ou página.
Você pode ler mais sobre o uso de UUIDs na Otimização.

Podemos ver um exemplo de HTML chamando o método .to_html() .

[68]: print(pd.DataFrame([[1,2],[3,4]], índice=['i1', 'i2'], colunas=['c1', 'c2']).style .para_


ÿÿhtml())

<style type="text/css"> </style>


<table
id="T_208c9"> <thead>

<tr>
(continua na próxima página)

768 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

<th class="blank level0" >&nbsp;</th> <th


id="T_208c9_level0_col0" class="col_heading level0 col0" >c1</th> <th id="T_208c9_level0_col1"
class="col_heading level0 col1" > c2</th> </tr> </thead> <tbody>

<tr>
<th id="T_208c9_level0_row0" class="row_heading level0 row0" >i1</th> <td id="T_208c9_row0_col0"
class="dados row0 col0" >1</td> <td id="T_208c9_row0_col1" class=" dados linha0 col1"
>2</td> </tr>

<tr>
<th id="T_208c9_level0_row1" class="row_heading level0 row1" >i2</th> <td id="T_208c9_row1_col0"
class="dados row1 col0" >3</td> <td id="T_208c9_row1_col1" class=" dados linha1 col1"
>4</td> </tr> </tbody> </table>

Hierarquias CSS

Os exemplos mostraram que quando os estilos CSS se sobrepõem, aquele que vem por último na renderização HTML tem precedência.
Portanto, o seguinte produz resultados diferentes:

[69]: df4 = pd.DataFrame([['text']])


df4.style.applymap(lambda x: 'color:green;')\ .applymap(lambda x:
'color:red;')

[69]: <pandas.io.formats.style.Styler em 0x7f556c290dc0>

[70]: df4.style.applymap(lambda x: 'color:red;')\ .applymap(lambda x:


'color:green;')

[70]: <pandas.io.formats.style.Styler em 0x7f555b06b610>

Isso só é verdade para regras CSS equivalentes em hierarquia ou importância. Você pode ler mais sobre a especificidade do CSS aqui ,
mas para nossos propósitos é suficiente resumir os pontos principais:

Uma pontuação de importância CSS para cada elemento HTML é derivada começando em zero e adicionando:

• 1.000 para um atributo de estilo in-line

• 100 para cada ID

• 10 para cada atributo, classe ou pseudoclasse

• 1 para cada nome de elemento ou pseudoelemento

Vamos usar isso para descrever a ação das seguintes configurações

[71]: df4.style.set_uuid('a_')
\ .set_table_styles([{'selector': 'td', 'props': 'color:red;'}])\ .applymap(lambda x: 'color :verde;')

2.16. Visualização de tabela 769


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

[71]: <pandas.io.formats.style.Styler em 0x7f556c2b3970>

Este texto é vermelho porque o seletor gerado #T_a_ td vale 101 (ID mais elemento), enquanto #T_a_row0_col0 vale apenas 100 (ID),
portanto é considerado inferior mesmo que no HTML venha depois do anterior.

[72]: df4.style.set_uuid('b_')
\ .set_table_styles([{'selector': 'td', 'props': 'color:red;'}, {'selector': '.cls-1 ', 'adereços': 'cor:azul;'}])
\
.applymap(lambda x: 'cor:verde;')
\ .set_td_classes(pd.DataFrame([['cls-1']]))

[72]: <pandas.io.formats.style.Styler em 0x7f555b07a8e0>

No caso acima o texto é azul porque o seletor #T_b_ .cls-1 vale 110 (ID mais classe), que tem precedência.

[73]: df4.style.set_uuid('c_')
\ .set_table_styles([{'selector': 'td', 'props': 'color:red;'}, {'selector': '.cls-1 ', 'props': 'color:blue;'},
{'selector': 'td.data', 'props': 'color:yellow;'}])\ .applymap(lambda x:
'color:green; ')\ .set_td_classes(pd.DataFrame([['cls-1']]))

[73]: <pandas.io.formats.style.Styler em 0x7f555b07a970>

Agora criamos outro estilo de tabela, desta vez o seletor T_c_td.data (ID mais elemento mais classe) aumenta para 111.

Se o seu estilo não for aplicado e for realmente frustrante, experimente o !important trunfo.

[74]: df4.style.set_uuid('d_')
\ .set_table_styles([{'selector': 'td', 'props': 'color:red;'}, {'selector': '.cls-1 ', 'props': 'color:blue;'},
{'selector': 'td.data', 'props': 'color:yellow;'}])\

.applymap(lambda x: 'color:green !important;')


\ .set_td_classes(pd.DataFrame([['cls-1']]))

[74]: <pandas.io.formats.style.Styler em 0x7f556c290f40>

Afinal, finalmente consegui aquele texto verde!

2.16.17 Extensibilidade

O núcleo do pandas é, e continuará sendo, suas “estruturas de dados de alto desempenho e fáceis de usar”. Com isso em mente, esperamos
que DataFrame.style atinja dois objetivos

• Fornecer uma API que seja agradável de usar de forma interativa e que seja “boa o suficiente” para muitas tarefas

• Fornecer as bases para bibliotecas dedicadas desenvolverem

Se você construir uma ótima biblioteca com base nisso, informe-nos e colocaremos um link para ela.

770 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Subclassificação

Se o modelo padrão não atender às suas necessidades, você pode criar uma subclasse de Styler e estender ou substituir o modelo.
Mostraremos um exemplo de extensão do modelo padrão para inserir um cabeçalho personalizado antes de cada tabela.

[75]: do ambiente de importação jinja2 , ChoiceLoader, FileSystemLoader


de IPython.display importar HTML de
pandas.io.formats.style importar Styler

Usaremos o seguinte modelo:

[76]: com open("templates/myhtml.tpl") como f:


imprimir(f.ler())

{% extends "html_table.tpl" %} {% tabela de


blocos %} <h1>{{ table_title|
default("Minha Tabela") }}</h1> {{ super() }} {% tabela endblock %}

Agora que criamos um modelo, precisamos configurar uma subclasse de Styler que o conheça.

[77]: class MyStyler(Styler): env =

Environment( loader=ChoiceLoader([ FileSystemLoader("templates"), # contém o


nosso Styler.loader, # o padrão
])

) template_html_table = env.get_template("meuhtml.tpl")

Observe que incluímos o carregador original no carregador do nosso ambiente. Isso ocorre porque estendemos o modelo original,
então o ambiente Jinja precisa ser capaz de encontrá-lo.

Agora podemos usar esse estilizador personalizado. É __init__ que leva um DataFrame.

[78]: MeuStyler(df3)

[78]: <__main__.MyStyler em 0x7f556c2b3fd0>

Nosso modelo personalizado aceita uma palavra-chave table_title. Podemos fornecer o valor no método .to_html.

[79]: HTML(MyStyler(df3).to_html(table_title=" Exemplo de extensão"))

[79]: <objeto IPython.core.display.HTML>

Por conveniência, fornecemos o método Styler.from_custom_template que faz o mesmo que a subclasse personalizada.

[80]: EasyStyler = Styler.from_custom_template("modelos", "myhtml.tpl")


HTML(EasyStyler(df3).to_html(table_title="Outro título"))

[80]: <objeto IPython.core.display.HTML>

2.16. Visualização de tabela 771


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Estrutura do modelo

Esta é a estrutura do modelo para o modelo de geração de estilo e para o modelo de geração de tabela:

Modelo de estilo:

[82]: HTML(estilo_estrutura)

[82]: <objeto IPython.core.display.HTML>

Modelo de tabela:

[84]: HTML (estrutura_tabela)

[84]: <objeto IPython.core.display.HTML>

Consulte o modelo no repositório GitHub para obter mais detalhes.

2.17 Ferramentas computacionais

2.17.1 Funções estatísticas

Mudança percentual

Series e DataFrame têm um método pct_change() para calcular a variação percentual em um determinado número de períodos
(usando fill_method para preencher valores NA/nulos antes de calcular a alteração percentual).

Em [1]: ser = pd.Series(np.random.randn(8))

Em [2]: ser.pct_change()
Fora[2]:
0 NaN
1 -1,602976
2 4.334938
3-0,247456
4 -2,067345
5 -1.142903
6 -1,688214
7 -9,759729
tipo d: float64

Em [3]: df = pd.DataFrame(np.random.randn(10, 4))

Em [4]: df.pct_change(períodos=3)
Fora[4]:
0 1 2 3
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 NaN NaN NaN NaN
3 -0,218320 -1,054001 1,987147 -0,510183
4 -0,439121 -1,816454 0,649715 -4,822809
5 -0,127833 -3,042065 -5,866604 -1,776977
(continua na próxima página)

772 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

6 -2,596833 -1,959538 -2,111697 -3,798900


7 -0,117826 -2,169058 0,036094 -0,067696
8 2,492606 -1,357320 -1,205802 -1,558697
9 -1,012977 2,324558 -1,003744 -0,371806

Covariância

Series.cov() pode ser usado para calcular a covariância entre séries (excluindo valores ausentes).

Em [5]: s1 = pd.Series(np.random.randn(1000))

Em [6]: s2 = pd.Series(np.random.randn(1000))

Em [7]: s1.cov(s2)
Saída[7]: 0,0006801088174310875

Analogamente, DataFrame.cov() para calcular covariâncias pareadas entre as séries no DataFrame, excluindo também valores NA/nulos.

Nota: Supondo que os dados faltantes estejam faltando aleatoriamente, isso resulta em uma estimativa para a matriz de covariância
que é imparcial. No entanto, para muitas aplicações esta estimativa pode não ser aceitável porque não é garantido que a matriz de
covariância estimada seja positiva semidefinida. Isto pode levar a correlações estimadas com valores absolutos superiores a um e/ou a
uma matriz de covariância não invertível. Consulte Estimativa de matrizes de covariância para obter mais detalhes.

Em [8]: frame = pd.DataFrame(np.random.randn(1000, 5), columns=["a", "b", "c", "d", "e"])

Em [9]: frame.cov()
Fora[9]:
a b c d e
a 1,000882 -0,003177 -0,002698 -0,006889 0,031912 b -0,003177 1,024721
0,000191 0,009212 0,000857 c -0,002698 0,000191 0,950735 -0 0,031743
-0,005087 d -0,006889 0,009212 -0,031743 1,002983 -0,047952 e 0,031912
0,000857 -0,005087 -0,047952 1,042487

DataFrame.cov também suporta uma palavra-chave opcional min_periods que especifica o número mínimo necessário de observações
para cada par de colunas para ter um resultado válido.

Em [10]: frame = pd.DataFrame(np.random.randn(20, 3), columns=["a", "b", "c"])

Em [11]: frame.loc[frame.index[:5], "a"] = np.nan

Em [12]: frame.loc[frame.index[5:10], "b"] = np.nan

Em [13]: frame.cov()
Fora[13]:
a b c
a 1,123670 -0,412851 0,018169 b -0,412851
1,154141 0,305260 c 0,018169 0,305260
1,301149
(continua na próxima página)

2.17. Ferramentas computacionais 773


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [14]: frame.cov(min_periods=12)
Fora[14]:
a b c
um 1,123670 NaN 0,018169
b NaN 1,154141 0,305260
c 0,018169 0,305260 1,301149

Correlação

A correlação pode ser calculada usando o método corr() . Usando o parâmetro método, vários métodos para calcular
correlações são fornecidas:

Nome do método Descrição


Pearson Coeficiente de correlação padrão
(padrão)
Kendall Coeficiente de correlação Kendall Tau
lanceiro Coeficiente de correlação de classificação de Spearman

Todos estes são atualmente calculados usando observações completas aos pares. A Wikipedia tem artigos que cobrem o acima
coeficientes de correlação:

• Coeficiente de correlação de Pearson

• Coeficiente de correlação de classificação Kendall

• Coeficiente de correlação de classificação de Spearman

Nota: Consulte as advertências associadas a este método de cálculo de matrizes de correlação na seção de covariância.

Em [15]: frame = pd.DataFrame(np.random.randn(1000, 5), columns=["a", "b", "c", "d", "e


ÿÿ"])

Em [16]: frame.iloc[::2] = np.nan

# Série com Série


Em [17]: frame["a"].corr(frame["b"])
Fora[17]: 0,013479040400098775

Em [18]: frame["a"].corr(frame["b"], método="spearman")


Saída[18]: -0,007289885159540637

# Correlação pareada de colunas DataFrame


Em [19]: frame.corr()
Fora[19]:
a b c d e
1,000000 0,013479 -0,049269 -0,042239 -0,028525
b 0,013479 1,000000 -0,020433 -0,011139 0,005654
c -0,049269 -0,020433 1,000000 0,018587 -0,054269
d -0,042239 -0,011139 0,018587 1,000000 -0,017060
e -0,028525 0,005654 -0,054269 -0,017060 1,000000

774 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Observe que as colunas não numéricas serão automaticamente excluídas do cálculo de correlação.

Assim como cov, corr também suporta a palavra-chave opcional min_periods:

Em [20]: frame = pd.DataFrame(np.random.randn(20, 3), columns=["a", "b", "c"])

Em [21]: frame.loc[frame.index[:5], "a"] = np.nan

Em [22]: frame.loc[frame.index[5:10], "b"] = np.nan

Em [23]: frame.corr()
Fora[23]:
a b c
a 1,000000 -0,121111 0,069544 b -0,121111
1,000000 0,051742 c 0,069544 0,051742
1,000000

Em [24]: frame.corr(min_periods=12)
Fora[24]:
a c
um 1.000000 bNaN 0,069544
b NaN 1,000000 0,051742
c 0,069544 0,051742 1,000000

O argumento do método também pode ser chamado para um cálculo de correlação genérico. Nesse caso, deve ser uma função
única que produza um único valor a partir de duas entradas ndarray. Suponha que quiséssemos calcular a correlação com base
na interseção do histograma:

# interseção do histograma Em [25]:


def histogram_intersection(a, b): return np.minimum(np.true_divide(a,
....: a.sum()), np.true_divide(b, b.sum())).
ÿÿsoma()
....:

Em [26]: frame.corr(method=histogram_intersection)
Fora[26]:
a b c
a 1,000000 -6,404882 -2,058431 b -6,404882
1,000000 -19,255743
c -2,058431 -19,255743 1,000000

Um método relacionado corrwith() é implementado no DataFrame para calcular a correlação entre séries com rótulos semelhantes
contidas em diferentes objetos DataFrame.

Em [27]: índice = ["a", "b", "c", "d", "e"]

Em [28]: colunas = ["um", "dois", "três", "quatro"]

Em [29]: df1 = pd.DataFrame(np.random.randn(5, 4), índice=índice, colunas=colunas)

Em [30]: df2 = pd.DataFrame(np.random.randn(4, 4), índice=índice[:4], colunas=colunas)

Em [31]: df1.corrwith(df2)
Fora[31]:
(continua na próxima página)

2.17. Ferramentas computacionais 775


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

um -0,125501
dois -0,493244
três 0,344056
quatro 0,004183
dtype: float64

Em [32]: df2.corrwith(df1, eixo=1)


Fora[32]:
-0,675817
b 0,458296
c 0,190809
d-0,186275
e NaN
tipo d: float64

Classificação de dados

O método rank() produz uma classificação de dados com empates sendo atribuídos à média das classificações (por padrão) para o grupo:

Em [33]: s = pd.Series(np.random.randn(5), index=list("abcde"))

Em [34]: s["d"] = s["b"] # então há empate

Em [35]: s.rank()
Fora[35]:
a 5,0
b 2,5
c 1,0
d 2,5
e 4,0
tipo d: float64

rank() também é um método DataFrame e pode classificar as linhas (eixo=0) ou as colunas (eixo=1). Os valores NaN são
excluído da classificação.

Em [36]: df = pd.DataFrame(np.random.randn(10, 6))

Em [37]: df[4] = df[2][:5] # alguns empates

Em [38]: df
Fora[38]:
0 1 25 3 4
0 -0,904948 -1,163537 -1,457187 0,135463 -1,457187 0,294650
1 -0,976288 -0,244652 -0,748406 -0,999601 -0,748406 -0,800809
2 0,401965 1,460840 1,256057 1,308127 1,256057 0,876004
3 0,205954 0,369552 -0,669304 0,038378 -0,669304 1,140296
4 -0,477586 -0,730705 -1,129149 -0,601463 -1,129149 -0,211196
5 -1,092970 -0,689246 0,908114 0,204848 NaN 0,463347
6 0,376892 0,959292 0,095572 -0,593740 NaN-0,069180
7 -1,002601 1,957794 -0,120708 0,094214 NaN -1,467422
8 -0,547231 0,664402 -0,519424 -0,073254 NaN -1,263544
(continua na próxima página)

776 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


9 -0,250277 -0,237428 -1,056443 0,419477 NaN 1,375064

Em [39]: df.rank(1)
Fora[39]:
0 1 2 3 4 5
0 4,0 3,0 1,5 5,0 1,5 6,0
1 2,0 6,0 4,5 1,0 4,5 3,0
2 1,0 6,0 3,5 5,0 3,5 2,0
3 4,0 5,0 1,5 3,0 1,5 6,0
4 5,0 3,0 1,5 4,0 1,5 6,0
5 1,0 2,0 5,0 3,0 NaN 4,0 6 4,0 5,0 3,0 1,0 NaN
2,0 7 2,0 5,0 3,0 4,0 NaN 1,0 8 2,0 5,0 3,0 4,0
NaN 1,0 9 2,0 3,0 1,0 4,0 NaN 5,0

rank opcionalmente leva um parâmetro crescente que por padrão é verdadeiro; quando falso, os dados são classificados inversamente, com valores
maiores atribuídos a uma classificação menor.

rank suporta diferentes métodos de desempate, especificados com o parâmetro method:

• média: classificação média do grupo empatado

• min: classificação mais baixa no grupo

• max: classificação mais alta no grupo

• primeiro: classificações atribuídas na ordem em que aparecem na matriz

Funções de janelas

Consulte o guia do usuário de operações de janela para obter uma visão geral das funções de janelamento.

2.18 Agrupar por: dividir-aplicar-combinar

Por “agrupar por” estamos nos referindo a um processo que envolve uma ou mais das seguintes etapas:

• Dividir os dados em grupos com base em alguns critérios.

• Aplicar uma função a cada grupo de forma independente.

• Combinar os resultados em uma estrutura de dados.

Destes, o passo dividido é o mais direto. Na verdade, em muitas situações podemos desejar dividir o conjunto de dados em grupos e fazer
algo com esses grupos. Na etapa de aplicação, podemos desejar fazer o seguinte:

• Agregação: calcule uma estatística resumida (ou estatísticas) para cada grupo. Alguns exemplos:

– Calcular somas ou médias de grupos.

– Calcular tamanhos/contagens de grupos.

• Transformação: execute alguns cálculos específicos do grupo e retorne um objeto indexado semelhante. Alguns exemplos:

– Padronize os dados (zscore) dentro de um grupo.

– Preenchimento de NAs dentro dos grupos com um valor derivado de cada grupo.

2.18. Agrupar por: dividir-aplicar-combinar 777


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

• Filtração: descarta alguns grupos, de acordo com um cálculo de grupo que avalia Verdadeiro ou Falso. Alguns
exemplos:

– Descarte dados que pertençam a grupos com poucos membros.

– Filtre os dados com base na soma ou média do grupo.

• Alguma combinação dos itens acima: GroupBy examinará os resultados da etapa de aplicação e tentará retornar um resultado sensato
resultado combinado se não se enquadrar em nenhuma das duas categorias acima.

Como o conjunto de métodos de instância de objeto nas estruturas de dados do pandas é geralmente rico e expressivo, muitas vezes simplesmente
deseja invocar, digamos, uma função DataFrame em cada grupo. O nome GroupBy deve ser bastante familiar para quem
usei uma ferramenta baseada em SQL (ou itertools), na qual você pode escrever código como:

SELECIONE Coluna1, Coluna2, média(Coluna3), soma(Coluna4)


DE alguma tabela
GRUPO POR Coluna1, Coluna2

Nosso objetivo é tornar operações como essa naturais e fáceis de expressar usando pandas. Abordaremos cada área do GroupBy
funcionalidade, em seguida, forneça alguns exemplos/casos de uso não triviais.

Consulte o livro de receitas para algumas estratégias avançadas.

2.18.1 Dividindo um objeto em grupos

objetos pandas podem ser divididos em qualquer um de seus eixos. A definição abstrata de agrupamento é fornecer um mapeamento de rótulos
para agrupar nomes. Para criar um objeto GroupBy (mais sobre o que é o objeto GroupBy posteriormente), você pode fazer o seguinte:

Em [1]: df = pd.DataFrame(
...: [
...: ("pássaro", "Falconiformes", 389,0),
...: ("pássaro", "Psittaciformes", 24,0),
...: ("mamífero", "Carnívoro", 80,2),
...: ("mamífero", "Primatas", np.nan),
...: ("mamífero", "Carnívoro", 58),
...: ],
...: index=["falcão", "papagaio", "leão", "macaco", "leopardo"],
...: colunas=("classe", "ordem", "max_speed"),
... :)
...:

Em [2]: df
Fora[2]:
ordem de classe max_speed
falcão pássaro Falconiformes 389,0
papagaio pássaro Psittaciformes Carnivora 24,0
leão mamífero Primatas 80,2
macaco mamífero Carnivora NaN
leopardo mamífero 58,0

# padrão é eixo=0
Em [3]: agrupado = df.groupby("class")

Em [4]: agrupado = df.groupby("ordem", eixo="colunas")

Em [5]: agrupado = df.groupby(["classe", "ordem"])

778 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

O mapeamento pode ser especificado de muitas maneiras diferentes:

• Uma função Python, a ser chamada em cada um dos rótulos dos eixos.

• Uma lista ou array NumPy do mesmo comprimento que o eixo selecionado.

• Um dict ou Series, fornecendo um rótulo -> mapeamento de nome de grupo.

• Para objetos DataFrame, uma string indicando um nome de coluna ou um nome de nível de índice a ser usado para agrupar.

• df.groupby('A') é apenas açúcar sintático para df.groupby(df['A']).

• Uma lista de qualquer um dos itens acima.

Coletivamente, nos referimos ao agrupamento de objetos como chaves. Por exemplo, considere o seguinte DataFrame:

Nota: Uma string passada para groupby pode referir-se a uma coluna ou a um nível de índice. Se uma string corresponder a uma coluna
nome e um nome de nível de índice, um ValueError será gerado.

Em [6]: df = pd.DataFrame(
...: {
...: "A": ["foo", "bar", "foo", "bar", "foo", "bar", "foo", "foo"],
...: "B": ["um", "um", "dois", "três", "dois", "dois", "um", "três"],
...: "C": np.random.randn(8),
...: "D": np.random.randn(8),
...: }
... :)
...:

Em [7]: df
Fora[7]:
A B C D
0 foo 1 um 0,469112 -0,861849
compasso um -0,282863 -2,104569
2 foo 3 dois -1,509059 -0,494929
compasso três -1,135632 1,071804
4 foo 5 dois 1,212112 0,721555
compasso dois -0,173215 -0,706771
6 foo 7 um 0,119209 -1,039575
foo três -1,044236 0,271860

Em um DataFrame, obtemos um objeto GroupBy chamando groupby(). Poderíamos naturalmente agrupar por A ou B
colunas ou ambas:

Em [8]: agrupado = df.groupby("A")

Em [9]: agrupado = df.groupby(["A", "B"])

Se também tivermos um MultiIndex nas colunas A e B, podemos agrupar por todas, exceto as colunas especificadas

Em [10]: df2 = df.set_index(["A", "B"])

Em [11]: agrupado = df2.groupby(level=df2.index.names.difference(["B"]))

Em [12]: grouped.sum()
Fora[12]:
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 779


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

C D
A
barra -1,591710 -1,739537
foo -0,752861 -1,402938

Isso dividirá o DataFrame em seu índice (linhas). Também poderíamos dividir pelas colunas:

Em [13]: def get_letter_type(letra):


....: se letter.lower() em 'aeiou':
....: retornar 'vogal'
....: outro:
....: retornar 'consoante'
....:

Em [14]: agrupado = df.groupby(get_letter_type, axis=1)

Os objetos de índice do pandas suportam valores duplicados. Se um índice não exclusivo for usado como chave de grupo em uma operação groupby,
todos os valores para o mesmo valor de índice serão considerados em um grupo e, portanto, a saída das funções de agregação
conterá apenas valores de índice exclusivos:

Em [15]: lst = [1, 2, 3, 1, 2, 3]

Em [16]: s = pd.Series([1, 2, 3, 10, 20, 30], lst)

Em [17]: agrupado = s.groupby(nível=0)

Em [18]: grouped.first()
Fora[18]:
11

22

33

tipo d: int64

Em [19]: grouped.last()
Fora[19]:
1 10
2 20
3 30
tipo d: int64

Em [20]: grouped.sum()
Fora[20]:
1 11
2 22
3 33

tipo d: int64

Observe que nenhuma divisão ocorre até que seja necessária. A criação do objeto GroupBy apenas verifica se você passou um valor válido
mapeamento.

Nota: Muitos tipos de manipulações complicadas de dados podem ser expressas em termos de operações GroupBy (embora não possam
ser garantidamente a mais eficiente). Você pode ser bastante criativo com as funções de mapeamento de rótulos.

780 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Grupo por classificação

Por padrão, as chaves de grupo são classificadas durante a operação groupby. No entanto, você pode passar sort=False para possíveis
acelerações:

Em [21]: df2 = pd.DataFrame({"X": ["B", "B", "A", "A"], "Y": [1, 2, 3, 4]})

Em [22]: df2.groupby(["X"]).sum()
Fora[22]:
Y
X
Um 7
B3

Em [23]: df2.groupby(["X"], sort=False).sum()


Fora[23]:
Y
X
B3
Um 7

Observe que groupby preservará a ordem em que as observações são classificadas dentro de cada grupo. Por exemplo, os
grupos criados por groupby() abaixo estão na ordem em que apareceram no DataFrame original:

Em [24]: df3 = pd.DataFrame({"X": ["A", "B", "A", "B"], "Y": [1, 4, 3, 2]})

Em [25]: df3.groupby(["X"]).get_group("A")
Fora[25]:
XY
0A1
2A3

Em [26]: df3.groupby(["X"]).get_group("B")
Saída[26]:
XY 1
B43B2

Novo na versão 1.1.0.

Grupo por dropna

Por padrão, os valores NA são excluídos das chaves de grupo durante a operação groupby. No entanto, caso você queira incluir valores
NA nas chaves de grupo, você pode passar dropna=False para conseguir isso.

Em [27]: df_list = [[1, 2, 3], [1, Nenhum, 4], [2, 1, 3], [1, 2, 2]]

Em [28]: df_dropna = pd.DataFrame(df_list, columns=["a", "b", "c"])

Entrada [29]: df_dropna


Saída [29]:
a bc 0
1 2,0 3
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 781


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

1 1 NaN 4
2 2 1,0 3
3 1 2,0 2

# Dropna padrão é definido como True, o que excluirá NaNs nas chaves Em [30]:
df_dropna.groupby(by=["b"], dropna=True).sum()
Fora[30]:
ac
b
1,0 2 3
2,0 2 5

# Para permitir NaN nas chaves, defina dropna como False In [31]:
df_dropna.groupby(by=["b"], dropna=False).sum()
Fora[31]:
ac

b 1,0 2 3 2,0
2 5 NaN 1 4

A configuração padrão do argumento dropna é True, o que significa que NA não está incluído nas chaves de grupo.

Atributos do objeto GroupBy

O atributo groups é um dict cujas chaves são os grupos únicos computados e os valores correspondentes são os rótulos
dos eixos pertencentes a cada grupo. No exemplo acima temos:

In [32]: df.groupby("A").groups Out[32]: {'bar':


[1, 3, 5], 'foo': [0, 2, 4, 6, 7]}

In [33]: df.groupby(get_letter_type, axis=1).groups Out[33]: {'consoante': ['B',


'C', 'D'], 'vogal': ['A'] }

Chamar a função len padrão do Python no objeto GroupBy apenas retorna o comprimento do ditado de grupos, portanto,
é apenas uma conveniência:

Em [34]: agrupado = df.groupby(["A", "B"])

In [35]: grouped.groups Out[35]:


{('bar', 'one'): [1], ('bar', 'três'): [3], ('bar', 'dois' ): [5], ('foo', 'um ÿÿ'): [0, 6], ('foo', 'três'): [7], ('foo', 'dois'): [2 , 4]}

Em [36]: len(agrupado)
Fora[36]: 6

GroupBy tabulará os nomes completos das colunas (e outros atributos):

Em [37]: df
Fora[37]:
altura peso sexo masculino
01/01/2000 42,849980 157,500553
(continua na próxima página)

782 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


02-01-2000 49.607315 177.340407 macho
03-01-2000 56.293531 171.524640 macho
04-01-2000 48.421077 144.251986 feminino
05-01-2000 46.556882 152.526206 macho
06-01-2000 68.448851 168.272968 feminino
07-01-2000 70.757698 136.431469 macho
08/01/2000 58,909500 176,499753 feminino
09-01-2000 76.435631 174.094104 feminino
10-01-2000 45.306120 177.540920 macho

Em [38]: gb = df.groupby("gênero")

Em [39]: gb.<TAB> # noqa: E225, E999


gb.agg gb.boxplot gb.cummin ÿÿaltura gb.último ÿÿstd gb.describe gb.filter gb.ngroups gb.plot gb.get_group gb.
gb.transform gb.median gb.classificação gb.

gb.agregado gb.count ÿÿhist gb.max gb.cumprod gb.dtype gb.primeiro gb.grupos gb.


gb.var gb.min gb.nth gb.prod gb.resample gb.
ÿÿsoma

gb.apply gb.cummax gb.cumsum gb.fillna gb.ohlc gb.gênero gb.cabeça gb.quantil GB.


ÿÿíndices gb.média gb.nome gb.tamanho GB.
ÿÿcauda gb.peso

GroupBy com MultiIndex

Com dados indexados hierarquicamente, é bastante natural agrupar por um dos níveis da hierarquia.

Vamos criar uma série com um MultiIndex de dois níveis.

Em [40]: matrizes = [
....: ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"],
....: ["um", "dois", "um ", "dois ", "um" , " dois", "um", "dois"],
....: ]
....:

Em [41]: index = pd.MultiIndex.from_arrays(arrays, names=["primeiro", "segundo"])

Em [42]: s = pd.Series(np.random.randn(8), índice=índice)

Em [43]: s
Fora[43]:
primeiro segundo
bar um -0,919854
dois -0,042379
baz um 1.247642
dois -0,009920
foo um 0,290213
dois 0,495767
qx um 0,362949
dois 1.548106
tipo d: float64

2.18. Agrupar por: dividir-aplicar-combinar 783


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Podemos então agrupar por um dos níveis em s.

Em [44]: agrupado = s.groupby(nível=0)

Em [45]: grouped.sum()
Fora[45]:
primeiro
barra -0,962232
baz 1.237723
foo 0,785980
qux 1.911055
dtype: float64

Se o MultiIndex tiver nomes especificados, estes podem ser passados em vez do número do nível:

Em [46]: s.groupby(level="second").sum()
Fora[46]:
segundo
um 0,980950
dois 1.991575
tipo d: float64

O agrupamento com vários níveis é suportado.

Em [47]: s
Fora[47]:
primeiro segundo terceiro
bar doo um -1,131345
dois -0,089329
baz abelha um 0,337863
dois -0,945867
foo bop um -0,932132
dois 1.956030
qx bop um 0,017587
dois -0,016692
tipo d: float64

Em [48]: s.groupby(level=["first", "second"]).sum()


Fora[48]:
primeiro segundo
bar doo baz -1,220674
abelha foo bop -0,608004
bop qux dtype: 1.023898
0,000895
float64

Os nomes dos níveis de índice podem ser fornecidos como chaves.

Em [49]: s.groupby(["primeiro", "segundo"]).sum()


Fora[49]:
primeiro segundo
bar doo -1,220674
baz abelha -0,608004
foo bop 1.023898
(continua na próxima página)

784 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

qux bop 0,000895


dtype: float64

Mais sobre a função de soma e agregação posteriormente.

Agrupando DataFrame com níveis e colunas de índice

Um DataFrame pode ser agrupado por uma combinação de colunas e níveis de índice, especificando os nomes das colunas como strings
e os níveis de índice como objetos pd.Grouper.

Em [50]: matrizes = [
....: ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"],
....: ["um", "dois", "um ", "dois ", "um" , " dois", "um", "dois"],
....: ]
....:

Em [51]: index = pd.MultiIndex.from_arrays(arrays, names=["primeiro", "segundo"])

Em [52]: df = pd.DataFrame({"A": [1, 1, 1, 1, 2, 2, 3, 3], "B": np.arange(8)},ÿ


ÿÿíndice=índice)

Em [53]: df
Fora[53]:
AB
primeiro segundo
barra um 10
dois 11

baz um 12
dois 13
foo um 24
dois 25
qx um 36
dois 37

O exemplo a seguir agrupa df pelo segundo nível de índice e pela coluna A.

Em [54]: df.groupby([pd.Grouper(level=1), "A"]).sum()


Fora[54]:
B
segundo A
um 12
24
36
dois 14
2 5
37

Os níveis de índice também podem ser especificados por nome.

Em [55]: df.groupby([pd.Grouper(level="second"), "A"]).sum()


Fora[55]:
B
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 785


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

segundo A
um 12
24
36
dois 14
2 5
37

Os nomes dos níveis de índice podem ser especificados como chaves diretamente para groupby.

Em [56]: df.groupby(["segundo", "A"]).sum()


Fora[56]:
B
segundo A
um 12
24
36
dois 14
2 5
37

Seleção de coluna DataFrame em GroupBy

Depois de criar o objeto GroupBy a partir de um DataFrame, você pode querer fazer algo diferente para cada um deles.
as colunas. Assim, usando [] semelhante a obter uma coluna de um DataFrame, você pode fazer:

Em [57]: df = pd.DataFrame(
....: {
....: "A": ["foo", "bar", "foo", "bar", "foo", "bar", "foo", "foo"],
....: "B": ["um", "um", "dois", "três", "dois", "dois", "um", "três"],
....: "C": np.random.randn(8),
....: "D": np.random.randn(8),
....: }
....: )
....:

Em [58]: df
Fora[58]:
DE ANÚNCIOS B C
0 foo um -0,575247 1,346061
1 barra um 0,254161 1,511763
2 pés dois -1,143704 1,627081
3 barra três 0,215897 -0,990582
4 pés dois 1,193555 -0,441652
5 barras dois -0,077118 1,211526
6 foo um -0,408530 0,268520
7 foo três -0,862495 0,024580

Em [59]: agrupado = df.groupby(["A"])

Em [60]: agrupado_C = agrupado["C"]


(continua na próxima página)

786 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [61]: agrupado_D = agrupado["D"]

Este é principalmente um açúcar sintático para a alternativa e muito mais detalhado:

Em [62]: df["C"].groupby(df["A"])
Out[62]: <objeto pandas.core.groupby.generic.SeriesGroupBy em 0x7f0eaf5addc0>

Além disso, este método evita recalcular as informações de agrupamento interno derivadas da chave passada.

2.18.2 Iterando através de grupos

Com o objeto GroupBy em mãos, iterar pelos dados agrupados é muito natural e funciona de maneira semelhante a
itertools.groupby():

Em [63]: agrupado = df.groupby('A')

Em [64]: para nome, grupo em agrupado:


....: imprimir(nome)
....: imprimir(grupo)
....:
bar
A B C D
1 barra um 0,254161 1,511763
3 barra três 0,215897 -0,990582
5 bar foo dois -0,077118 1,211526

A B C D
0 foo um -0,575247 1,346061
2 pés dois -1,143704 1,627081
4 pés dois 1,193555 -0,441652
6 foo um -0,408530 0,268520
7 foo três -0,862495 0,024580

No caso de agrupamento por múltiplas chaves, o nome do grupo será uma tupla:

Em [65]: para nome, grupo em df.groupby(['A', 'B']):


....: imprimir(nome)
....: imprimir(grupo)
....:
('barra', 'um')
A B C D
1 barra um 0,254161 1,511763
('barra', 'três')
A B C D
3 barra três 0,215897 -0,990582
('barra', 'dois')
A B C D
5 barras dois -0,077118 1,211526
('foo', 'um')
A B C D
0 foo um -0,575247 1,346061
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 787


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

6 foo um -0,408530 0,268520


('foo', 'três')
A B C D
7 foo três -0,862495 0,02458
('foo', 'dois')
A B C D
2 pés dois -1,143704 1,627081
4 pés dois 1,193555 -0,441652

Consulte Iterando por meio de grupos.

2.18.3 Selecionando um grupo

Um único grupo pode ser selecionado usando get_group():

Em [66]: grouped.get_group("bar")
Fora[66]:
A B C D
1 barra um 0,254161 1,511763
3 barra três 0,215897 -0,990582
5 barras dois -0,077118 1,211526

Ou para um objeto agrupado em múltiplas colunas:

Em [67]: df.groupby(["A", "B"]).get_group(("bar", "one"))


Fora[67]:
A B C D
1 barra um 0,254161 1,511763

2.18.4 Agregação

Depois que o objeto GroupBy for criado, vários métodos estarão disponíveis para realizar um cálculo no objeto agrupado.
dados. Essas operações são semelhantes à API de agregação, à API de janela e à API de reamostragem.

Um método óbvio é a agregação por meio do método agregada() ou equivalentemente agg():

Em [68]: agrupado = df.groupby("A")

Em [69]: agrupado.agregado(np.sum)
Fora[69]:
C D
A
barra 0,392940 1,732707
foo -1,796421 2,824590

Em [70]: agrupado = df.groupby(["A", "B"])

Em [71]: agrupado.agregado(np.sum)
Fora[71]:
C D
AB
(continua na próxima página)

788 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


barra um 0,254161 1,511763
três 0,215897 -0,990582
dois -0,077118 1,211526
foo um -0,983776 1,614581
três -0,862495 0,024580
dois 0,049851 1,185429

Como você pode ver, o resultado da agregação terá os nomes dos grupos como o novo índice ao longo do eixo agrupado. No
caso de múltiplas chaves, o resultado é um MultiIndex por padrão, embora isso possa ser alterado usando a opção as_index:

Em [72]: agrupado = df.groupby(["A", "B"], as_index=False)

Em [73]: agrupado.agregado(np.sum)
Fora[73]:
DE ANÚNCIOS B C
0 barra um 0,254161 1,511763
1 barra três 0,215897 -0,990582
2 barras dois -0,077118 1,211526
3 foo um -0,983776 1,614581
4 foo três -0,862495 0,024580
5 foo dois 0,049851 1,185429

Em [74]: df.groupby("A", as_index=False).sum()


Fora[74]:
A C D
0 barra 0,392940 1,732707
1 foo -1,796421 2,824590

Observe que você pode usar a função reset_index DataFrame para obter o mesmo resultado que os nomes das colunas são
armazenado no MultiIndex resultante:

Em [75]: df.groupby(["A", "B"]).sum().reset_index()


Fora[75]:
A B C D
0 barra um 0,254161 1,511763
1 barra três 0,215897 -0,990582
2 barras dois -0,077118 1,211526
3 foo um -0,983776 1,614581
4 foo três -0,862495 0,024580
5 foo dois 0,049851 1,185429

Outro exemplo simples de agregação é calcular o tamanho de cada grupo. Isso está incluído no GroupBy como o tamanho
método. Retorna uma Série cujo índice são os nomes dos grupos e cujos valores são os tamanhos de cada grupo.

Em [76]: grouped.size()
Fora[76]:
Tamanho B
A0 um 1
compasso 1 1
compasso dois 1
três 2 um 2
compasso 3 foo 4 1
foo três 5 foo dois 2

2.18. Agrupar por: dividir-aplicar-combinar 789


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [77]: grouped.describe()
Fora[77]:
C ... D ÿ

ÿÿ

contar significar padrão min 25% 50% 75% ... significar ÿ

ÿÿpadrão min 25% 50% 75% máx.


0 1,0 0,254161 NaN 0,254161 0,254161 0,254161 0,254161 ... 1,511763 ÿ

ÿÿNaN 1,511763 1,511763 1,511763 1,511763 1,511763


1 1,0 0,215897 ÿÿNaN NaN 0,215897 0,215897 0,215897 0,215897 ... -0,990582 ÿ

-0,990582 -0,990582 -0,990582 -0,990582 -0,990582


2 1,0 -0,077118 NaN -0,077118 -0,077118 -0,077118 -0,077118 ... 1,211526 ÿ

ÿÿNaN 1,211526 1,211526 1,211526 1,211526 1,211526


3 2,0 -0,491888 0,117887 -0,575247 -0,533567 -0,491888 -0,450209 ... 0,807291 0.
ÿÿ761937 0,268520 0,537905 0,807291 1,076676 1,346061
4 1,0 -0,862495 NaN -0,862495 -0,862495 -0,862495 -0,862495 ... 0,024580 ÿ

ÿÿNaN 0,024580 0,024580 0,024580 0,024580 0,024580


5 2,0 0,024925 1,652692 -1,143704 -0,559389 0,024925 0,609240 ... 0,592714 1.
ÿÿ462816 -0,441652 0,075531 0,592714 1,109898 1,627081

[6 linhas x 16 colunas]

Outro exemplo de agregação é calcular o número de valores exclusivos de cada grupo. Isto é semelhante ao
função value_counts, exceto que conta apenas valores únicos.

Em [78]: ll = [['foo', 1], ['foo', 2], ['foo', 2], ['bar', 1], ['bar', 1]]

Em [79]: df4 = pd.DataFrame(ll, colunas=["A", "B"])

Em [80]: df4
Fora[80]:
AB
0 foo 1
1 foo 2
2 foo 2
3 barra 1
4 barra 1

Em [81]: df4.groupby("A")["B"].nunique()
Fora[81]:
A
bar 1
foo 2
Nome: B, dtype: int64

Nota: As funções de agregação não retornarão os grupos sobre os quais você está agregando se eles forem colunas nomeadas, quando
as_index=True, o padrão. As colunas agrupadas serão os índices do objeto retornado.

Passar as_index=False retornará os grupos que você está agregando, se eles forem colunas nomeadas.

Funções agregadoras são aquelas que reduzem a dimensão dos objetos retornados. Algumas agregações comuns
funções estão tabeladas abaixo:

790 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Função Descrição
média() Calcular média de grupos
soma() Calcular a soma dos valores do grupo
tamanho() Calcular tamanhos de grupo
contagem() Calcular contagem do grupo
std() Desvio padrão dos grupos
var() Calcular variância de grupos
sem() Erro padrão da média dos grupos
descrever() Gera estatísticas descritivas
primeiro() Calcule o primeiro dos valores do grupo
último() Calcular o último valor do grupo
nth() Pegue o enésimo valor ou um subconjunto se n for uma lista

min() Calcular min de valores de grupo


max() Calcular o máximo de valores de grupo

As funções de agregação acima excluirão os valores NA. Qualquer função que reduz uma série a um valor escalar é uma
função de agregação e funcionará, um exemplo trivial é df.groupby('A').agg(lambda ser: 1). Observe que nth()
pode atuar como redutor ou filtro, veja aqui.

Aplicando múltiplas funções ao mesmo tempo

Com séries agrupadas você também pode passar uma lista ou ditado de funções para agregar, gerando um DataFrame:

Em [82]: agrupado = df.groupby("A")

Em [83]: agrupado["C"].agg([np.sum, np.mean, np.std])


Fora[83]:
soma significar padrão

A
barra 0,392940 0,130980 0,181231
foo -1,796421 -0,359284 0,912265

Em um DataFrame agrupado, você pode passar uma lista de funções para aplicar a cada coluna, o que produz um valor agregado
resultado com um índice hierárquico:

Em [84]: agrupado[["C", "D"]].agg([np.sum, np.mean, np.std])


Fora[84]:
C D
soma significar padrão soma significar padrão

A
barra 0,392940 0,130980 0,181231 1,732707 0,577569 1,366330
foo -1,796421 -0,359284 0,912265 2,824590 0,564918 0,884785

As agregações resultantes são nomeadas de acordo com as próprias funções. Se precisar renomear, você pode adicionar um encadeado
operação para uma série como esta:

Em [85]: (
....: agrupado["C"]
....: .agg([np.sum, np.mean, np.std])
....: .rename(colunas={"sum": "foo", "mean": "bar", "std": "baz"})
....: )
....:
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 791


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[85]:
foo bar baz
A
barra 0,392940 0,130980 0,181231
foo -1,796421 -0,359284 0,912265

Para um DataFrame agrupado, você pode renomear de maneira semelhante:

Em [86]: (
....: agrupado[["C", "D"]].agg([np.sum, np.mean, np.std]).rename(
....: colunas={"sum": "foo", "mean": "bar", "std": "baz"}
....: )
....: )
....:
Fora[86]:
D
C foo bar baz foo bar baz
A
barra 0,392940 0,130980 0,181231 1,732707 0,577569 1,366330
foo -1,796421 -0,359284 0,912265 2,824590 0,564918 0,884785

Nota: Em geral, os nomes das colunas de saída devem ser exclusivos. Você não pode aplicar a mesma função (ou duas funções
com o mesmo nome) para a mesma coluna.

Em [87]: agrupado["C"].agg(["soma", "soma"])


Fora[87]:
soma soma
A
barra 0,392940 0,392940
foo -1,796421 -1,796421

pandas permite fornecer vários lambdas. Neste caso, os pandas irão alterar o nome do lambda (sem nome)
funções, anexando _<i> a cada lambda subsequente.

Em [88]: agrupado["C"].agg([lambda x: x.max() - x.min(), lambda x: x.median() - x.mean()])


Fora[88]:
<lambda_0> <lambda_1>
A
bar 0,331279 0,084917
foo 2,337259 -0,215962

792 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Agregação nomeada

Novo na versão 0.25.0.

Para suportar agregação específica de coluna com controle sobre os nomes das colunas de saída, o pandas aceita a sintaxe especial
em GroupBy.agg(), conhecido como “agregação nomeada”, onde

• As palavras-chave são os nomes das colunas de saída

• Os valores são tuplas cujo primeiro elemento é a coluna a ser selecionada e o segundo elemento é a agregação a ser aplicada
para essa coluna. pandas fornece ao pandas.NamedAgg nomeadotuple os campos ['column', 'aggfunc']
para deixar mais claro quais são os argumentos. Como de costume, a agregação pode ser um alias chamável ou de string.

Em [89]: animais = pd.DataFrame(


....: {
....: "tipo": ["gato", "cachorro", "gato", "cachorro"],
....: "altura": [9,1, 6,0, 9,5, 34,0],
....: "peso": [7,9, 7,5, 9,9, 198,0],
....: }
....: )
....:

Em [90]: animais
Fora[90]:
tipo altura peso
0 gato 9,1 7,9
1 cachorro 6,0 7,5
2 gato 9,5 9,9
3 cachorro 34,0 198,0

Em [91]: animais.groupby("tipo").agg(
....: min_height=pd.NamedAgg(coluna="altura", aggfunc="min"),
....: max_height=pd.NamedAgg(coluna="altura", aggfunc="max"),
....: peso_médio=pd.NamedAgg(coluna="peso", aggfunc=np.mean),
....: )
....:
Fora[91]:
min_height max_height peso_médio
tipo
gato 9.1 9,5 8,90
cachorro 6,0 34,0 102,75

pandas.NamedAgg é apenas uma tupla nomeada. Tuplas simples também são permitidas.

Em [92]: animais.groupby("tipo").agg(
....: min_height=("altura", "min"),
....: max_height=("altura", "máx"),
....: peso_médio=("peso", np.mean),
....: )
....:
Fora[92]:
min_height max_height peso_médio
tipo
gato 9.1 9,5 8,90
cachorro 6,0 34,0 102,75

2.18. Agrupar por: dividir-aplicar-combinar 793


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Se os nomes das colunas de saída desejadas não forem palavras-chave Python válidas, construa um dicionário e descompacte a palavra-chave
argumentos

Em [93]: animais.groupby("tipo").agg(
....: **{
....: "peso total": pd.NamedAgg(column="peso", aggfunc=sum)
....: }
....: )
....:
Fora[93]:
peso total
tipo
gato 17,8
cachorro 205,5

Argumentos adicionais de palavras-chave não são passados para as funções de agregação. Apenas pares de (coluna,
aggfunc) deve ser passado como **kwargs. Se suas funções de agregação exigirem argumentos adicionais, aplique parcialmente
eles com functools.partial().

Nota: Para Python 3.5 e versões anteriores, a ordem de **kwargs em funções não foi preservada. Isto significa que a saída
a ordem das colunas não seria consistente. Para garantir uma ordenação consistente, as chaves (e, portanto, as colunas de saída) sempre serão
ser classificado para Python 3.5.

A agregação nomeada também é válida para agregações agrupadas em série. Neste caso não há seleção de coluna, então os valores
são apenas as funções.

Em [94]: animais.groupby("tipo").height.agg(
....: min_height="min",
....: max_height = "máx",
....: )
....:
Fora[94]:
altura_min_altura_máxima
tipo
gato 9,1 9,5
cachorro 6,0 34,0

Aplicando diferentes funções às colunas DataFrame

Ao passar um dict para agregar você pode aplicar uma agregação diferente às colunas de um DataFrame:

Em [95]: grouped.agg({"C": np.sum, "D": lambda x: np.std(x, ddof=1)})


Fora[95]:
C D
A
barra 0,392940 1,366330
foo -1,796421 0,884785

Os nomes das funções também podem ser strings. Para que uma string seja válida ela deve ser implementada em GroupBy ou
disponível via despacho:

794 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [96]: grouped.agg({"C": "sum", "D": "std"})


Fora[96]:
C D
A
barra 0,392940 1,366330 foo
-1,796421 0,884785

Funções de agregação otimizadas para Cython

Algumas agregações comuns, atualmente apenas soma, média, padrão e sem, otimizaram implementações Cython:

Em [97]: df.groupby("A").sum()
Fora[97]:
C D
A
barra 0,392940 1,732707 foo
-1,796421 2,824590

Em [98]: df.groupby(["A", "B"]).mean()


Fora[98]:
C D
AB
barra um 0,254161 1,511763 três
0,215897 -0,990582 dois -0,077118
1,211526
foo um -0,491888 0,807291
três -0,862495 0,024580
dois 0,024925 0,592714

É claro que soma e média são implementadas em objetos pandas, então o código acima funcionaria mesmo sem as versões especiais via
despacho (veja abaixo).

Agregações com funções definidas pelo usuário

Os usuários também podem fornecer suas próprias funções para agregações personalizadas. Ao agregar com uma função definida
pelo usuário (UDF), a UDF não deve alterar a série fornecida; consulte Mutação com métodos de função definida pelo usuário (UDF)
para obter mais informações.

Em [99]: Animals.groupby("kind")[["height"]].agg(lambda x: set(x))


Fora[99]:
altura
tipo
gato {9,1, 9,5}
cachorro {34,0, 6,0}

O dtype resultante refletirá o da função de agregação. Se os resultados de grupos diferentes tiverem dtypes diferentes, então um dtype comum
será determinado da mesma forma que a construção do DataFrame.

Em [100]: Animals.groupby("kind")[["height"]].agg(lambda x: x.astype(int).sum())


Fora[100]:
altura
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 795


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

tipo
gato 18
cachorro 40

2.18.5 Transformação

O método transform retorna um objeto indexado do mesmo (mesmo tamanho) que aquele que está sendo agrupado. A transformação
função deve:

• Retornar um resultado que seja do mesmo tamanho do bloco do grupo ou que possa ser transmitido para o tamanho do bloco do grupo
(por exemplo, um escalar, grouped.transform(lambda x: x.iloc[-1])).

• Operar coluna por coluna no bloco do grupo. A transformação é aplicada ao primeiro pedaço do grupo usando
pedaço.apply.

• Não realizar operações no local no bloco do grupo. Os pedaços do grupo devem ser tratados como imutáveis e as alterações
para um pedaço de grupo pode produzir resultados inesperados. Por exemplo, ao usar fillna, inplace deve ser False
(agrupado.transform(lambda x: x.fillna(inplace=False))).

• (Opcionalmente) opera em todo o bloco do grupo. Se isso for suportado, um caminho rápido será usado a partir do segundo
pedaço.

Semelhante às agregações com funções definidas pelo usuário, o dtype resultante refletirá o da função de transformação.
Se os resultados de grupos diferentes tiverem tipos diferentes, então um tipo comum será determinado da mesma maneira que
Construção de DataFrame.

Suponha que desejemos padronizar os dados dentro de cada grupo:

Em [101]: índice = pd.date_range("01/10/1999", períodos=1100)

Em [102]: ts = pd.Series(np.random.normal(0,5, 2, 1100), índice)

Em [103]: ts = ts.rolling(window=100, min_periods=100).mean().dropna()

Em [104]: ts.head()
Fora[104]:
2000-01-08 0,779333
2000-01-09 0,778852
2000-01-10 0,786476
2000-01-11 0,782797
2000-01-12 0,798110
Freq: D, dtype: float64

Em [105]: ts.tail()
Fora[105]:
30/09/2002 0,660294
01-10-2002 0,631095
02-10-2002 0,673601
03/10/2002 0,709213
04-10-2002 0,719369
Freq: D, tipo d: float64

Em [106]: transformado = ts.groupby(lambda x: x.year).transform(


.....: lambda x: (x - x.mean()) / x.std()
(continua na próxima página)

796 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

..... :)
.....:

Esperamos que o resultado agora tenha média 0 e desvio padrão 1 dentro de cada grupo, o que podemos verificar facilmente:

# Dados Originais
Em [107]: agrupado = ts.groupby(lambda x: x.ano)

Em [108]: grouped.mean()
Fora[108]:
2000 0,442441
2001 0,526246
2002 0,459365
tipo d: float64

Em [109]: grouped.std()
Fora[109]:
2000 0,131752
2001 0,210945
2002 0,128753
tipo d: float64

# Dados transformados
Em [110]: grouped_trans = transformado.groupby(lambda x: x.ano)

Em [111]: grouped_trans.mean()
Fora[111]:
2000 1.193722e-15
2001 1.945476e-15
2002 1.272949e-15
tipo d: float64

Em [112]: grouped_trans.std()
Fora[112]:
2000 1,0
2001 1.0
2002 1.0
tipo d: float64

Também podemos comparar visualmente os conjuntos de dados originais e transformados.

Em [113]: compare = pd.DataFrame({"Original": ts, "Transformado": transformado})

Em [114]: compare.plot()
Saída[114]: <AxesSubplot:>

2.18. Agrupar por: dividir-aplicar-combinar 797


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Funções de transformação que possuem saídas de dimensão inferior são transmitidas para corresponder ao formato da matriz de entrada.

Em [115]: ts.groupby(lambda x: x.year).transform(lambda x: x.max() - x.min())


Fora[115]:
08/01/2000 0,623893
09/01/2000 0,623893
10/01/2000 0,623893
11/01/2000 0,623893
12/01/2000 0,623893
...
30/09/2002 0,558275
01-10-2002 0,558275
02/10/2002 0,558275
03/10/2002 0,558275
04/10/2002 0,558275
Freq: D, Comprimento: 1001, tipo d: float64

Alternativamente, os métodos integrados podem ser usados para produzir os mesmos resultados.

Em [116]: max = ts.groupby(lambda x: x.year).transform("max")

Em [117]: min = ts.groupby(lambda x: x.year).transform("min")

Em [118]: máximo - mínimo


(continua na próxima página)

798 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[118]:
08/01/2000 0,623893
09/01/2000 0,623893
10/01/2000 0,623893
11/01/2000 0,623893
12/01/2000 0,623893
...
30/09/2002 0,558275
01-10-2002 0,558275
02-10-2002 0,558275
03/10/2002 0,558275
04/10/2002 0,558275
Freq: D, Comprimento: 1001, tipo d: float64

Outra transformação de dados comum é substituir os dados ausentes pela média do grupo.

Em [119]: dados_df
Fora[119]:
A B C
0 1,539708 -1,166480 0,533026
1 1,302092 -0,505754 NaN
2 -0,371983 1,104803 -0,651520
3 -1,309622 1,118697 -1,161657
4 -1,924296 0,396437 0,812436
.. ... ... ...
995 -0,093110 0,683847 -0,774753
996 -0,185043 1,438572 NaN
997 -0,394469 -0,642343 0,011374
998 -1,174126 1,857148 999 NaN
0,234564 0,517098 0,393534

[1000 linhas x 3 colunas]

Em [120]: países = np.array(["EUA", "Reino Unido", "GR", "JP"])

Em [121]: chave = países[np.random.randint(0, 4, 1000)]

Em [122]: agrupado = data_df.groupby(chave)

# Contagem de não-NA em cada grupo


Em [123]: grouped.count()
Fora[123]:
A B C
GR 209 217 189
JP 240 255 217
Reino Unido 216 231 193
EUA 239 250 217

Em [124]: transformado = agrupado.transform(lambda x: x.fillna(x.mean()))

Podemos verificar que as médias do grupo não mudaram nos dados transformados e que os dados transformados contêm
sem NA.

2.18. Agrupar por: dividir-aplicar-combinar 799


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [125]: grouped_trans = transformado.groupby(chave)

Em [126]: grouped.mean() # grupo original significa


Fora[126]:
A B C
GR -0,098371 -0,015420 0,068053
JP 0,069025 0,023100 -0,077324
Reino Unido 0,034069 -0,052580 -0,116525
EUA 0,058664 -0,020399 0,028603

Em [127]: grouped_trans.mean() # transformação não alterou as médias do grupo


Fora[127]:
A B C
GR -0,098371 -0,015420 0,068053
JP 0,069025 0,023100 -0,077324
Reino Unido 0,034069 -0,052580 -0,116525
EUA 0,058664 -0,020399 0,028603

Em [128]: grouped.count() # original tem alguns pontos de dados ausentes


Fora[128]:
A B C
GR 209 217 189
JP 240 255 217
Reino Unido 216 231 193
EUA 239 250 217

Em [129]: grouped_trans.count() # contagens após a transformação


Fora[129]:
A B C
GR 228 228 228
JP 267 267 267
Reino Unido 247 247 247
EUA 258 258 258

Em [130]: grouped_trans.size() # Verifique se a contagem não-NA é igual ao tamanho do grupo


Fora[130]:
GR 228
JP 267
Reino Unido 247

EUA 258

tipo d: int64

Nota: Algumas funções transformarão automaticamente a entrada quando aplicadas a um objeto GroupBy, mas retornarão um
objeto com a mesma forma do original. Passar as_index=False não afetará esses métodos de transformação.

Por exemplo: fillna, ffill, bfill, shift..

Em [131]: grouped.ffill()
Fora[131]:
A B C
0 1,539708 -1,166480 0,533026
1 1,302092 -0,505754 0,533026
(continua na próxima página)

800 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

2 -0,371983 1,104803 -0,651520


3 -1,309622 1,118697 -1,161657
4 -1,924296 0,396437 0,812436
.. ... ... ...
995 -0,093110 0,683847 -0,774753
996 -0,185043 1,438572 -0,774753
997 -0,394469 -0,642343 0,011374
998 -1,174126 1,857148 -0,774753
999 0,234564 0,517098 0,393534

[1000 linhas x 3 colunas]

Operações de janela e reamostragem

É possível usar resample(), expandindo() e rolando() como métodos em groupbys.

O exemplo abaixo aplicará o método rolling() nas amostras da coluna B com base nos grupos de colunas
A.

Em [132]: df_re = pd.DataFrame({"A": [1] * 10 + [5] * 10, "B": np.arange(20)})

Em [133]: df_re
Fora[133]:
A B
0 1 0
1 1 1
2 1 2
3 1 3
4 1 4
.. .. ..
15 5 15
16 5 16
17 5 17
18 5 18
19 5 19

[20 linhas x 2 colunas]

Em [134]: df_re.groupby("A").rolling(4).B.mean()
Fora[134]:
A
101 NaN
NaN
NaN
1,5
234 2,5
...
5 15 16 13,5
14,5
17 15,5
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 801


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

18 16,5
19 17,5
Nome: B, Comprimento: 20, dtype: float64

O método expandindo() acumulará uma determinada operação (sum() no exemplo) para todos os membros de cada
determinado grupo.

Em [135]: df_re.groupby("A").expanding().sum()
Fora[135]:
B
A
10 0,0
1,0
3,0
123 6,0
4 10,0
... ...
5 15 75,0
16 91,0
17 108,0
18 126,0
19 145,0

[20 linhas x 1 coluna]

Suponha que você queira usar o método resample() para obter uma frequência diária em cada grupo do seu dataframe e desejar
para completar os valores ausentes com o método ffill().

Em [136]: df_re = pd.DataFrame(


.....: {
.....: "data": pd.date_range(start="2016-01-01", períodos=4, freq="W"),
.....: "grupo": [1, 1, 2, 2],
.....: "valor": [5, 6, 7, 8],
.....: }
.....: .set_index("data")
.....:

Em [137]: df_re
Fora[137]:
valor do grupo
data
03/01/2016 1 5
10/01/2016 1 6
17/01/2016 2 7
24/01/2016 2 8

Em [138]: df_re.groupby("grupo").resample("1D").ffill()
Fora[138]:
valor do grupo
data do grupo
1 03/01/2016 5
04/01/2016 11 5
(continua na próxima página)

802 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

05/01/2016 1 5
06/01/2016 1 5
07/01/2016 1 5
... ... ...
2 20/01/2016 2 7
21/01/2016 2 7
22/01/2016 2 7
23/01/2016 2 7
24/01/2016 2 8

[16 linhas x 2 colunas]

2.18.6 Filtragem

O método filter retorna um subconjunto do objeto original. Suponha que queiramos pegar apenas elementos que pertencem a
grupos com soma de grupo maior que 2.

Em [139]: sf = pd.Series([1, 1, 2, 3, 3, 3])

Em [140]: sf.groupby(sf).filter(lambda x: x.sum() > 2)


Fora[140]:
3 3
4 3
5 3
tipo d: int64

O argumento do filtro deve ser uma função que, aplicada ao grupo como um todo, retorne Verdadeiro ou Falso.

Outra operação útil é filtrar elementos que pertencem a grupos com apenas alguns membros.

Em [141]: dff = pd.DataFrame({"A": np.arange(8), "B": list("aabbbbcc")})

Em [142]: dff.groupby("B").filter(lambda x: len(x) > 2)


Fora[142]:
AB
2 2b
3 3b
4 4b
5 5b

Alternativamente, em vez de descartar os grupos ofensivos, podemos retornar objetos indexados de forma semelhante, onde os grupos que o fazem
não passam no filtro são preenchidos com NaNs.

Em [143]: dff.groupby("B").filter(lambda x: len(x) > 2, dropna=False)


Fora[143]:
A B
0 NaN NaN
1 NaN NaN
2 2,0 b
3 3,0 4 b
4,0 5 5,0 b
b
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 803


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

6 NaN NaN
7 NaN NaN

Para DataFrames com múltiplas colunas, os filtros devem especificar explicitamente uma coluna como critério de filtro.

Em [144]: dff["C"] = np.arange(8)

Em [145]: dff.groupby("B").filter(lambda x: len(x["C"]) > 2)


Fora[145]:
ABC 2 2
b233b3

44b4
55b5

Nota: Algumas funções, quando aplicadas a um objeto groupby, atuarão como um filtro na entrada, retornando uma
forma reduzida do original (e potencialmente eliminando grupos), mas com o índice inalterado. Passar as_index=False
não afetará esses métodos de transformação.

Por exemplo: cabeça, cauda.

Em [146]: dff.groupby("B").head(2)
Fora[146]:
ABC
00a0
11a1
22b2
33b3
66c6
77c7

2.18.7 Despachando para métodos de instância

Ao fazer uma agregação ou transformação, talvez você queira apenas chamar um método de instância em cada grupo de dados.
Isso é muito fácil de fazer passando funções lambda:

Em [147]: agrupado = df.groupby("A")

Em [148]: grouped.agg(lambda x: x.std())


Fora[148]:
C D
A
barra 0,181231 1,366330 foo
0,912265 0,884785

Porém, é bastante detalhado e pode ser confuso se você precisar passar argumentos adicionais. Usando um pouco de inteligência de
metaprogramação, GroupBy agora tem a capacidade de “despachar” chamadas de método para os grupos:

Em [149]: grouped.std()
Fora[149]:
(continua na próxima página)

804 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

C D
A
barra 0,181231 1,366330
foo 0,912265 0,884785

O que realmente está acontecendo aqui é que um wrapper de função está sendo gerado. Quando invocado, leva qualquer passado
argumentos e invoca a função com quaisquer argumentos em cada grupo (no exemplo acima, a função std). O
os resultados são então combinados no estilo agg e transform (na verdade, usa apply para inferir a colagem,
documentado a seguir). Isso permite que algumas operações sejam realizadas de forma bastante sucinta:

Em [150]: tsdf = pd.DataFrame(


.....: np.random.randn(1000, 3),
.....: índice=pd.date_range("1/1/2000", períodos=1000),
.....: colunas=["A", "B", "C"],
..... :)
.....:

Em [151]: tsdf.iloc[::2] = np.nan

Em [152]: agrupado = tsdf.groupby(lambda x: x.ano)

Em [153]: grouped.fillna(method="pad")
Fora[153]:
abc
2000-01-01 NaN NaN NaN
02/01/2000 -0,353501 -0,080957 -0,876864
03-01-2000 -0,353501 -0,080957 -0,876864
04-01-2000 0,050976 0,044273 -0,559849
05-01-2000 0,050976 0,044273 -0,559849
... ... ... ...
22/09/2002 0,005011 0,053897 -1,026922
23/09/2002 0,005011 0,053897 -1,026922
24/09/2002 -0,456542 -1,849051 1,559856
25/09/2002 -0,456542 -1,849051 1,559856
26/09/2002 1,123162 0,354660 1,128135

[1000 linhas x 3 colunas]

Neste exemplo, dividimos a coleção de séries temporais em pedaços anuais e então chamados independentemente de fillna no
grupos.

Os métodos nlargest e nsmallest funcionam em groupbys de estilo Series:

Em [154]: s = pd.Series([9, 8, 7, 5, 19, 1, 4,2, 3,3])

Em [155]: g = pd.Series(list("abababab"))

Em [156]: gb = s.groupby(g)

Em [157]: gb.nlargest(3)
Fora[157]:
um 4 19,0
0 9,0
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 805


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

2 7,0
b1 8,0
3 5,0
7 3.3
tipo d: float64

Em [158]: gb.nsmallest(3)
Fora[158]:
um 6 4.2
2 7,0
9,0
0b 5 1,0
7 3.3
3 5,0
tipo d: float64

2.18.8 Aplicação flexível

Algumas operações nos dados agrupados podem não se enquadrar nas categorias agregada ou de transformação. Ou você pode simplesmente
deseja que GroupBy infira como combinar os resultados. Para estes, use a função apply, que pode ser substituída por ambos
agregar e transformar em muitos casos de uso padrão. No entanto, apply pode lidar com alguns casos de uso excepcionais, por
exemplo:

Em [159]: df
Fora[159]:
A B C D
0 foo um -0,575247 1,346061
1 barra um 0,254161 1,511763
2 pés dois -1,143704 1,627081
3 barra três 0,215897 -0,990582
4 pés dois 1,193555 -0,441652
5 barras dois -0,077118 1,211526
6 foo um -0,408530 0,268520
7 foo três -0,862495 0,024580

Em [160]: agrupado = df.groupby("A")

# também poderia simplesmente chamar .describe()


Em [161]: agrupado["C"].apply(lambda x: x.describe())
Fora[161]:
A
contagem de barras 3.000.000
significar 0,130980
padrão 0,181231
mínimo -0,077118
25% 0,069390
...
foo min 25% -1.143704
50% -0,862495
75% -0,575247
-0,408530
(continua na próxima página)

806 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


máx. 1.193555
Nome: C, Comprimento: 16, dtype: float64

A dimensão do resultado retornado também pode mudar:

Em [162]: agrupado = df.groupby('A')['C']

Em [163]: def f(grupo):


.....: return pd.DataFrame({'original': grupo,
.....: 'rebaixado': grupo - group.mean()})
.....:

Em [164]: grouped.apply(f)
Fora[164]:
original humilhado
0 -0,575247 -0,215962
1 0,254161 0,123181
2 -1,143704 -0,784420
3 0,215897 0,084917
4 1,193555 1,552839
5 -0,077118 -0,208098
6 -0,408530 -0,049245
7 -0,862495 -0,503211

aplicar em uma série pode operar em um valor retornado da função aplicada, que é em si uma série e possivelmente upcast
o resultado para um DataFrame:

Em [165]: def f(x):


.....: retornar pd.Series([x, x ** 2], índice=["x", "x^2"])
.....:

Em [166]: s = pd.Series(np.random.rand(5))

Em [167]: s
Fora[167]:
0 0,321438
1 0,493496
2 0,139505
3 0,910103
4 0,194158
tipo d: float64

Em [168]: s.apply(f)
Fora[168]:
x x^2
0 0,321438 0,103323
1 0,493496 0,243538
2 0,139505 0,019462
3 0,910103 0,828287
4 0,194158 0,037697

Nota: apply pode atuar como uma função redutora, transformadora ou de filtro, dependendo exatamente do que é passado para ela. Então

2.18. Agrupar por: dividir-aplicar-combinar 807


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

dependendo do caminho percorrido e exatamente do que você está agrupando. Assim, as colunas agrupadas podem ser incluídas no
saída, bem como definir os índices.

Semelhante às agregações com funções definidas pelo usuário, o dtype resultante refletirá o da função apply. Se
os resultados de grupos diferentes têm tipos diferentes, então um tipo comum será determinado da mesma maneira que
Construção de DataFrame.

2.18.9 Rotinas aceleradas Numba


Novo na versão 1.1.

Se o Numba estiver instalado como uma dependência opcional, os métodos de transformação e agregação suportam engine='numba'
e argumentos engine_kwargs. Veja como melhorar o desempenho com Numba para uso geral dos argumentos e
considerações de desempenho.

A assinatura da função deve começar com valores, indexar exatamente como os dados pertencentes a cada grupo serão passados para
valores, e o índice do grupo será passado para index.

Aviso: Ao usar engine='numba', não haverá comportamento de “retrocesso” internamente. Os dados do grupo e
o índice do grupo será passado como matrizes NumPy para a função JITed definida pelo usuário e nenhuma tentativa alternativa de execução
será tentado.

2.18.10 Outros recursos úteis

Exclusão automática de colunas “incômodas”

Considere novamente o exemplo de DataFrame que vimos:

Em [169]: df
Fora[169]:
A B C D
0 foo 1 um -0,575247 1,346061
barra um 0,254161 1,511763
2 pés dois -1,143704 1,627081
3 barra três 0,215897 -0,990582
4 pés dois 1,193555 -0,441652
5 barras dois -0,077118 1,211526
6 foo um -0,408530 0,268520
7 foo três -0,862495 0,024580

Suponha que desejemos calcular o desvio padrão agrupado pela coluna A. Há um pequeno problema, nomeadamente que
não nos importamos com os dados da coluna B. Chamamos isso de coluna “incômodo”. Se a função de agregação passada
não puder ser aplicado a algumas colunas, as colunas problemáticas serão descartadas (silenciosamente). Assim, isto não representa qualquer
problemas:

Em [170]: df.groupby("A").std()
Fora[170]:
C D
A
barra 0,181231 1,366330
foo 0,912265 0,884785

808 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Observe que df.groupby('A').colname.std(). é mais eficiente que df.groupby('A').std().colname, então se o


o resultado de uma função de agregação só é interessante em uma coluna (aqui nome da coluna), ele pode ser filtrado antes de aplicar
a função de agregação.

Nota: Qualquer coluna de objeto, mesmo que contenha valores numéricos como objetos Decimais, é considerada um “incômodo”
colunas. Eles são excluídos das funções agregadas automaticamente no groupby.

Se desejar incluir colunas decimais ou de objeto em uma agregação com outros tipos de dados não incômodos, você deverá
faça isso explicitamente.

Em [171]: da importação decimal Decimal

Em [172]: df_dec = pd.DataFrame(


.....: {
.....: "id": [1, 2, 1, 2],
.....: "int_column": [1, 2, 3, 4],
.....: "dec_column": [
.....: Decimal("0,50"),
.....: Decimal("0,15"),
.....: Decimal("0,25"),
.....: Decimal("0,40"),
.....: ],
.....: }
..... :)
.....:

# Colunas decimais podem ser somadas explicitamente por si mesmas...


Em [173]: df_dec.groupby(["id"])[["dec_column"]].sum()
Fora[173]:
coluna_dez
eu ia

0,75
12 0,55

# ...mas não podem ser combinados com tipos de dados padrão ou serão excluídos
Em [174]: df_dec.groupby(["id"])[["int_column", "dec_column"]].sum()
Fora[174]:
coluna_int
eu ia

1 4
2 6

# Use a função .agg para agregar tipos de dados padrão e "incômodos"


# ao mesmo tempo
Em [175]: df_dec.groupby(["id"]).agg({"int_column": "soma", "dec_column": "soma"})
Fora[175]:
int_column dec_column
eu ia

1 4 0,75
2 6 0,55

2.18. Agrupar por: dividir-aplicar-combinar 809


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Tratamento de valores categóricos (não) observados

Ao usar uma garoupa categórica (como uma única garoupa ou como parte de várias garoupas), a palavra-chave observada
controla se deve retornar um produto cartesiano de todos os valores possíveis de garoupas (observed=False) ou apenas aqueles que são
garoupas observadas (observado = Verdadeiro).

Mostrar todos os valores:

Em [176]: pd.Series([1, 1, 1]).groupby(


.....: pd.Categorical(["a", "a", "a"], categorias=["a", "b"]), observado=Falso
.....: .count()
.....:
Fora[176]:
a 3
0
tipo b: int64

Mostre apenas os valores observados:

Em [177]: pd.Series([1, 1, 1]).groupby(


.....: pd.Categorical(["a", "a", "a"], categorias=["a", "b"]), observado=Verdadeiro
.....: .count()
.....:
Fora[177]:
a 3
tipo d: int64

O dtype retornado do agrupado sempre incluirá todas as categorias que foram agrupadas.

Em [178]: s = (
.....: pd.Série([1, 1, 1])
.....: .groupby(pd.Categorical(["a", "a", "a"], categorias=["a", "b"]),ÿ
ÿÿobservado=Falso)
.....: .contar()
..... :)
.....:

Em [179]: s.index.dtype
Out[179]: CategoricalDtype(categories=['a', 'b'], ordenado=Falso)

810 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Tratamento de grupos NA e NaT

Se houver algum valor NaN ou NaT na chave de agrupamento, estes serão automaticamente excluídos. Em outras palavras, haverá
nunca seja um “grupo NA” ou “grupo NaT”. Este não era o caso nas versões mais antigas do pandas, mas os usuários geralmente eram
descartar o grupo de NA de qualquer maneira (e apoiá-lo foi uma dor de cabeça na implementação).

Agrupamento com fatores ordenados

Variáveis categóricas representadas como instância da classe Categorical do pandas podem ser usadas como chaves de grupo. Se assim for, o
a ordem dos níveis será preservada:

Em [180]: dados = pd.Series(np.random.randn(100))

Em [181]: fator = pd.qcut(dados, [0, 0,25, 0,5, 0,75, 1,0])

Em [182]: data.groupby(fator).mean()
Fora[182]:
(-2,645, -0,523] -1,362896
(-0,523, 0,0296] -0,260266
(0,0296, 0,654] 0,361802
(0,654, 2,21] 1,073801
tipo d: float64

Agrupando com uma especificação de garoupa

Pode ser necessário especificar um pouco mais de dados para agrupar corretamente. Você pode usar o pd.Grouper para fornecer esse controle local.

Em [183]: importar data e hora

Em [184]: df = pd.DataFrame(
.....: {
.....: "Filial": "AAAAAA B".split(),
.....: "Comprador": "Carl Mark Carl Carl Joe Joe Joe Carl".split(),
.....: "Quantidade": [1, 3, 5, 1, 8, 1, 9, 3],
.....: "Data": [
.....: datahora.datehora(2013, 1, 1, 13, 0),
.....: datahora.datehora(2013, 1, 1, 13, 5),
.....: datahora.datehora(2013, 10, 1, 20, 0),
.....: datahora.datehora(2013, 10, 2, 10, 0),
.....: datahora.datehora(2013, 10, 1, 20, 0),
.....: datahora.datehora(2013, 10, 2, 10, 0),
.....: datahora.datehora(2013, 12, 2, 12, 0),
.....: datahora.datehora(2013, 12, 2, 14, 0),
.....: ],
.....: }
..... :)
.....:

Em [185]: df
Fora[185]:
Quantidade do comprador da filial Data
0 Um Carl 101/01/2013 13:00:00
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 811


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

1 Uma marca 3 01-01-2013 13:05:00


2 Um Carl 5 01/10/2013 20:00:00
3 Um Carl 12/10/2013 10:00:00
4 Um Joe 8 01/10/2013 20:00:00
5 Um Joe 12/10/2013 10:00:00
6 Um Joe 9 02/12/2013 12:00:00
7 Carlos B 3 02/12/2013 14:00:00

Agrupar por uma coluna específica com a frequência desejada. Isso é como reamostrar.

Em [186]: df.groupby([pd.Grouper(freq="1M", key="Data"), "Comprador"]).sum()


Fora[186]:
Quantidade
Data Comprador

31/01/2013 Carlos 1
Marca 3
31/10/2013 Carlos 6
Joe 9
31/12/2013 Carlos 3
Joe 9

Você tem uma especificação ambígua, pois possui um índice nomeado e uma coluna que pode ser garoupas em potencial.

Em [187]: df = df.set_index("Data")

Em [188]: df["Data"] = df.index + pd.offsets.MonthEnd(2)

Em [189]: df.groupby([pd.Grouper(freq="6M", key="Data"), "Comprador"]).sum()


Fora[189]:
Quantidade
Data Comprador

28/02/2013 Carlos 1
Marca 3
28/02/2014 Carlos 9
Joe 18

Em [190]: df.groupby([pd.Grouper(freq="6M", level="Data"), "Comprador"]).sum()


Fora[190]:
Quantidade
Data Comprador

31/01/2013 Carlos 1
Marca 3
31/01/2014 Carlos 9
Joe 18

812 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Tomando as primeiras linhas de cada grupo

Assim como para um DataFrame ou Série, você pode chamar head e tail em um groupby:

Em [191]: df = pd.DataFrame([[1, 2], [1, 4], [5, 6]], colunas=["A", "B"])

Em [192]: df
Fora[192]:
AB
01211
4256

Em [193]: g = df.groupby("A")

Em [194]: g.head(1)
Fora[194]:
AB 0
12256

Em [195]: g.tail(1)
Fora[195]: AB

114
256

Isso mostra as primeiras ou últimas n linhas de cada grupo.

Tomando a enésima linha de cada grupo

Para selecionar em um DataFrame ou Série o enésimo item, use nth(). Este é um método de redução e retornará uma única linha (ou
nenhuma linha) por grupo se você passar um int para n:

Em [196]: df = pd.DataFrame([[1, np.nan], [1, 4], [5, 6]], colunas=["A", "B"])

Em [197]: g = df.groupby("A")

Em [198]: g.nth(0)
Fora[198]:
B
A
1 NaN 5
6,0

Em [199]: g.nth(-1)
Fora[199]: B

A 1 4,0
5 6,0

Em [200]: g.nth(1)
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 813


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[200]:
B
A
1 4,0

Se você deseja selecionar o enésimo item não nulo, use o dropna kwarg. Para um DataFrame, deve ser 'qualquer' ou 'todos', assim como
você passaria para dropna:

# nth(0) é o mesmo que g.first()


Em [201]: g.nth(0, dropna="qualquer")
Fora[201]: B

A 1 4,0
5 6,0

Em [202]: g.first()
Fora[202]:
B
A
1 4,0
5 6,0

# nth(-1) é o mesmo que g.last()


In [203]: g.nth(-1, dropna="any") # NaNs denotam grupo exausto ao usar dropna Out[203]:

B
A
1 4,0 5
6,0

Em [204]: g.last()
Fora[204]: B

A 1 4,0
5 6,0

Em [205]: gBnth(0, dropna="all")


Fora[205]: A

1 4,0
5 6,0
Nome: B, dtype: float64

Tal como acontece com outros métodos, passar as_index=False alcançará uma filtragem, que retorna a linha agrupada.

Em [206]: df = pd.DataFrame([[1, np.nan], [1, 4], [5, 6]], colunas=["A", "B"])

Em [207]: g = df.groupby("A", as_index=False)

Em [208]: g.nth(0)
(continua na próxima página)

814 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[208]:
A B
0 1 NaN
2 5 6,0

Em [209]: g.nth(-1)
Fora[209]:
A B
1 1 4,0
2 5 6,0

Você também pode selecionar várias linhas de cada grupo especificando vários enésimos valores como uma lista de inteiros.

Em [210]: business_dates = pd.date_range(start="4/1/2014", end="6/30/2014", freq="B")

Em [211]: df = pd.DataFrame(1, index=business_dates, columns=["a", "b"])

# obtém o primeiro, o quarto e o último índice de data para cada mês Em [212]:
df.groupby([df.index.year, df.index.month]).nth([0, 3, -1])
Fora[212]: ab

2014 4 1 1
411
411
5 11
5 11
5 11
611
611611

Enumerar itens do grupo

Para ver a ordem em que cada linha aparece em seu grupo, use o método cumcount:

Em [213]: dfg = pd.DataFrame(list("aaabba"), colunas=["A"])

Em [214]: dfg
Fora[214]:

A0a
1a2
a3b

4b
5 uma

Em [215]: dfg.groupby("A").cumcount()
Fora[215]:
0 0
1 1
(continua na próxima página)

2.18. Agrupar por: dividir-aplicar-combinar 815


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

2 2
3 0
4 1
5 3
tipo d: int64

Em [216]: dfg.groupby("A").cumcount(ascendente=Falso)
Fora[216]:
0 3
1 2
2 1
3 1
4 0
5 0
tipo d: int64

Enumerar grupos

Para ver a ordem dos grupos (em oposição à ordem das linhas dentro de um grupo dada por cumcount), você pode usar
ngrupo().

Observe que os números dados aos grupos correspondem à ordem em que os grupos seriam vistos ao iterar sobre o
groupby objeto, não a ordem em que são observados pela primeira vez.

Em [217]: dfg = pd.DataFrame(list("aaabba"), colunas=["A"])

Em [218]: dfg
Fora[218]:
A
0 uma
1 uma
2 uma
3b
4b
5 uma

Em [219]: dfg.groupby("A").ngroup()
Fora[219]:
00
10

20

31

41
50

tipo d: int64

Em [220]: dfg.groupby("A").ngroup(ascendente=Falso)
Fora[220]:
0 1
1 1
2 1
(continua na próxima página)

816 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


3 0
4 0
5 1
tipo d: int64

Plotagem

Groupby também funciona com alguns métodos de plotagem. Por exemplo, suponhamos que suspeitamos que alguns recursos em um DataFrame
podem diferir por grupo, neste caso, os valores na coluna 1 onde o grupo é “B” são 3 superiores em média.

Em [221]: np.random.seed(1234)

Em [222]: df = pd.DataFrame(np.random.randn(50, 2))

Em [223]: df["g"] = np.random.choice(["A", "B"], tamanho=50)

Em [224]: df.loc[df["g"] == "B", 1] += 3

Podemos visualizar isso facilmente com um boxplot:

Em [225]: df.groupby("g").boxplot()
Fora[225]:
A Subtrama de Eixos(0,1,0,15;0,363636x0,75)
B Subtrama de Eixos(0,536364,0,15;0,363636x0,75)
dtype: objeto

2.18. Agrupar por: dividir-aplicar-combinar 817


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

O resultado da chamada do boxplot é um dicionário cujas chaves são os valores da nossa coluna de agrupamento g (“A” e “B”). Os
valores do dicionário resultante podem ser controlados pela palavra-chave return_type do boxplot. Consulte a documentação de
visualização para obter mais informações.

Aviso: Por razões históricas, df.groupby("g").boxplot() não é equivalente a df.boxplot(by="g").


Veja aqui uma explicação.

Chamadas de função de tubulação

Semelhante à funcionalidade fornecida por DataFrame e Series, funções que usam objetos GroupBy podem ser encadeadas usando um
método pipe para permitir uma sintaxe mais limpa e legível. Para ler sobre .pipe em termos gerais, veja aqui.

Combinar .groupby e .pipe geralmente é útil quando você precisa reutilizar objetos GroupBy.

Como exemplo, imagine ter um DataFrame com colunas de lojas, produtos, receita e quantidade vendida. Gostaríamos de fazer um
cálculo de preços em grupo (ou seja, receita/quantidade) por loja e por produto. Poderíamos fazer isso em uma operação de várias
etapas, mas expressá-lo em termos de tubulação pode tornar o código mais legível. Primeiro definimos os dados:

Em [226]: n = 1000

Em [227]: df = pd.DataFrame(
(continua na próxima página)

818 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


.....: {
.....: "Loja": np.random.choice(["Loja_1", "Loja_2"], n),
.....: "Produto": np.random.choice(["Produto_1", "Produto_2"], n),
.....: "Receita": (np.random.random(n) * 50 + 10).round(2),
.....: "Quantidade": np.random.randint(1, 10, tamanho=n),
.....: }
..... :)
.....:

Em [228]: df.head(2)
Fora[228]:
Loja Quantidade de receita do produto
0 Loja_2 Produto_1 26,12 1
1 Loja_2 Produto_1 28,86 1

Agora, para encontrar preços por loja/produto, podemos simplesmente fazer:

Em [229]: (
.....: df.groupby(["Loja", "Produto"])
.....: .pipe(lambda grp: grp.Revenue.sum() / grp.Quantity.sum())
.....: .unstack()
.....: .2 ª rodada)
..... :)
.....:
Fora[229]:
Produto Produto_1 Produto_2
Loja
Loja_1 6,82 7.05
Loja_2 6h30 6,64

A tubulação também pode ser expressiva quando você deseja entregar um objeto agrupado para alguma função arbitrária, por exemplo:

Em [230]: def média(agrupar):


.....: retornar groupby.mean()
.....:

Em [231]: df.groupby(["Loja", "Produto"]).pipe(média)


Fora[231]:
Quantidade de receita
Armazenar produto
Loja_1 Produto_1 34.622727 5.075758
Produto_2 35.482815 5.029630
Loja_2 Produto_1 32.972837 5.237589
Produto_2 34.684360 5.224000

onde média pega um objeto GroupBy e encontra a média das colunas Receita e Quantidade, respectivamente, para cada
Combinação Loja-Produto. A função média pode ser qualquer função que receba um objeto GroupBy; o .pipe irá
passe o objeto GroupBy como parâmetro para a função que você especificar.

2.18. Agrupar por: dividir-aplicar-combinar 819


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.18.11 Exemplos

Reagrupamento por fator

Reagrupe colunas de um DataFrame de acordo com sua soma e some as agregadas.

Em [232]: df = pd.DataFrame({"a": [1, 0, 0], "b": [0, 1, 0], "c": [1, 0, 0], "d ": [2, 3,ÿÿ ÿ4]})

Em [233]: df
Fora[233]:
ABCD
01012
10103
20004

Em [234]: df.groupby(df.sum(), axis=1).sum()


Fora[234]:
19
02 2
11320
4

Fatoração multicoluna

Usando ngroup(), podemos extrair informações sobre os grupos de uma forma semelhante a factorize() (conforme descrito mais
adiante na API de remodelagem), mas que se aplica naturalmente a múltiplas colunas de tipo misto e fontes diferentes. Isso pode ser
útil como uma etapa intermediária de processamento do tipo categórico, quando os relacionamentos entre as linhas do grupo são
mais importantes que seu conteúdo, ou como entrada para um algoritmo que aceita apenas a codificação inteira. (Para obter mais
informações sobre o suporte em pandas para dados categóricos completos, consulte a introdução categórica e a documentação da API.)

Em [235]: dfg = pd.DataFrame({"A": [1, 1, 2, 3, 2], "B": list("aaaba")})

Em [236]: dfg
Fora[236]:
AB
0 1 uma
1 1 uma
2 2 uma
3 3b
4 2 uma

Em [237]: dfg.groupby(["A", "B"]).ngroup()


Fora[237]:
0 0
1 0
2

4
1 2 1 tipo de d: int64

Em [238]: dfg.groupby(["A", [0, 0, 0, 1, 1]]).ngroup()


(continua na próxima página)

820 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[238]: 0
0
1 0
2 1
3 3
4 2
tipo d: int64

Groupby por indexador para 'reamostrar' dados

A reamostragem produz novas amostras hipotéticas (resamostras) a partir de dados observados já existentes ou de um modelo que
gera dados. Essas novas amostras são semelhantes às amostras pré-existentes.

Para fazer uma nova amostragem para trabalhar em índices que não sejam semelhantes a data e hora, o procedimento a seguir pode ser utilizado.

Nos exemplos a seguir, df.index // 5 retorna um array binário que é usado para determinar o que é selecionado para a operação groupby.

Nota: O exemplo abaixo mostra como podemos reduzir a resolução consolidando as amostras em menos amostras. Aqui, usando
df.index // 5, estamos agregando as amostras em caixas. Ao aplicar a função std() , agregamos as informações contidas em muitas
amostras em um pequeno subconjunto de valores que é o seu desvio padrão, reduzindo assim o número de amostras.

Em [239]: df = pd.DataFrame(np.random.randn(10, 2))

Em [240]: df
Fora[240]:
0 1
0 -0,793893 0,321153
1 0,342250 1,618906
2 -0,975807 1,918201
3 -0,810847 -1,405919
4 -1,977759 0,461659
5 0,730057 -1,316938
6 -0,751328 0,528290
7 -0,257759 -1,081009
8 0,505895 -1,701948
9 -1,006349 0,020208

In [241]: df.index // 5 Out[241]:


Int64Index([0, 0, 0, 0, 0, 1, 1, 1, 1, 1], dtype='int64')

Em [242]: df.groupby(df.index // 5).std()


Fora[242]:
0 1 0 0,823647
1,312912 1 0,760109 0,942941

2.18. Agrupar por: dividir-aplicar-combinar 821


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Retornando uma série para propagar nomes

Agrupe colunas do DataFrame, calcule um conjunto de métricas e retorne uma série nomeada. O nome da série é usado como o nome
para o índice da coluna. Isto é especialmente útil em conjunto com operações de remodelagem, como empilhamento, nas quais o
o nome do índice da coluna será usado como o nome da coluna inserida:

Em [243]: df = pd.DataFrame(
.....: {
.....: "a": [0, 0, 0, 0 , 1, 1, 1, 1, 2, 2, 2, 2],
.....: "b": [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1],
.....: "c": [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
.....: "d": [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
.....: }
..... :)
.....:

Em [244]: def computar_metrics(x):


.....: resultado = {"b_sum": x["b"].sum(), "c_mean": x["c"].mean()}
.....: retornar pd.Series (resultado, nome = "métricas")
.....:

Em [245]: resultado = df.groupby("a").apply(compute_metrics)

Em [246]: resultado
Fora[246]:
métricas b_sum c_mean
a
0 2,0 0,5
1 2,0 0,5
2 2,0 0,5

Em [247]: result.stack()
Fora[247]:
uma métrica
0 b_soma 2,0
c_média 0,5
1 b_soma 2,0
c_média 0,5
2 b_soma 2,0
c_média 0,5
tipo d: float64

2.19 Operações de janelas

pandas contém um conjunto compacto de APIs para realizar operações de janelas - uma operação que realiza uma agregação
sobre uma partição deslizante de valores. A API funciona de forma semelhante à API groupby naquela chamada Series e DataFrame
o método de janelamento com os parâmetros necessários e, posteriormente, chamar a função de agregação.

Em [1]: s = pd.Series(intervalo(5))

Em [2]: s.rolling(window=2).sum()
(continua na próxima página)

822 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[2]:
0 NaN
1 1,0
2 3,0
3 5,0
4 7,0
tipo d: float64

As janelas são compostas pela observação do comprimento da janela a partir da observação atual. O resultado acima
pode ser derivado tomando a soma das seguintes partições de dados em janelas:

Em [3]: para janela em s.rolling(window=2):


...: imprimir (janela)
...:
00

tipo d: int64
00
1 1
tipo d: int64
11

2 2
tipo d: int64
22

3 3
tipo d: int64
33

4 4
tipo d: int64

2.19.1 Visão Geral

pandas suporta 4 tipos de operações de janelas:

1. Janela rolante: Janela genérica fixa ou variável deslizante sobre os valores.

2. Janela ponderada: janela ponderada não retangular fornecida pela biblioteca scipy.signal.

3. Janela de expansão: Janela de acumulação sobre os valores.

4. Janela Exponencialmente Ponderada: Janela acumulativa e exponencialmente ponderada sobre os valores.

Conceito Método Objeto Retornado Apoia Apoia Apoia Apoia


baseado no tempo acorrentado mesa operações on-
janelas agrupar por método line
Janela rolante rolanteRolando Sim Sim Sim (a partir de Não

versão 1.3)
Janela ponderada janela rolante Não Não Não Não

Janela em expandindoExpandindo Não Sim Sim (a partir de Não


expansão versão 1.3)
Exponencialmente Sem ewm ExponentialMovingWindow Sim (a partir da Não Sim (a partir da
Janela ponderada versão 1.2) versão 1.3)

2.19. Operações de janelas 823


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Conforme observado acima, algumas operações suportam a especificação de uma janela com base em um deslocamento de horário:

Em [4]: s = pd.Series(range(5), index=pd.date_range('2020-01-01', period=5, freq='1D'))

Em [5]: s.rolling(window='2D').sum()
Fora[5]:
01/01/2020 0,0
2020-01-02 1,0
2020-01-03 3.0
2020-01-04 5.0
05/01/2020 7,0
Freq: D, tipo d: float64

Além disso, alguns métodos suportam o encadeamento de uma operação groupby com uma operação de janela que primeiro agrupará
os dados pelas chaves especificadas e, em seguida, execute uma operação de janelas por grupo.

Em [6]: df = pd.DataFrame({'A': ['a', 'b', 'a', 'b', 'a'], 'B': range(5)})

Em [7]: df.groupby('A').expanding().sum()
Fora[7]:
B
A
um 0 0,0
2 2,0
4 6,0
b 1 1,0
3 4,0

Nota: Atualmente, as operações de janelas suportam apenas dados numéricos (inteiro e flutuante) e sempre retornarão float64
valores.

Aviso: alguns métodos de agregação de janelas, média, soma, var e std podem sofrer de imprecisão numérica devido aos algoritmos de
janelas subjacentes que acumulam somas. Quando os valores diferem com a magnitude
1/ . isso resulta . truncamento.
( em ). Deve-se notar que grandes valores podem ter um impacto sobre
janelas, que não incluem esses valores. A soma de Kahan é usada para calcular as somas contínuas para preservar
precisão tanto quanto possível.

Novo na versão 1.3.0.

Algumas operações de janelas também suportam a opção method='table' no construtor que executa a operação de janelas em um DataFrame
inteiro em vez de uma única coluna ou linha por vez. Isto pode fornecer um útil
benefício de desempenho para um DataFrame com muitas colunas ou linhas (com o argumento do eixo correspondente) ou o
capacidade de utilizar outras colunas durante a operação de janelas. A opção method='table' só pode ser usada se
engine='numba' é especificado na chamada de método correspondente.

Por exemplo, um cálculo de média ponderada pode ser calculado com apply() especificando uma coluna separada de pesos.

Em [8]: def média_ponderada(x):


...: arr = np.ones((1, x.forma[1]))
...: arr[:, :2] = (x[:, :2] * x[:, 2]).soma(eixo=0) / x[:, 2].soma()
...: retorno _
(continua na próxima página)

824 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

...:

Em [9]: df = pd.DataFrame([[1, 2, 0,6], [2, 3, 0,4], [3, 4, 0,2], [4, 5 , 0,7]])

Em [10]: df.rolling(2, method="table", min_periods=0).apply(weighted_mean, raw=True,ÿ ÿÿengine="numba") # noqa:E501 Out[10]:

0 1 2
0 1,000000 2,000000 1,0
1 1,800000 2,000000 1,0
2 3,333333 2,333333 1,0 3 1,555556
7,000000 1,0

Novo na versão 1.3.

Algumas operações de janelamento também suportam um método online após a construção de um objeto de janelamento que
retorna um novo objeto que suporta a passagem de novos objetos DataFrame ou Série para continuar o cálculo de janelamento
com os novos valores (ou seja, cálculos online).

Os métodos nesses novos objetos de janelamento devem chamar primeiro o método de agregação para “preparar” o estado inicial
do cálculo online. Em seguida, novos objetos DataFrame ou Series podem ser passados no argumento de atualização para
continuar o cálculo de janelas.

Em [11]: df = pd.DataFrame([[1, 2, 0,6], [2, 3, 0,4], [3, 4, 0,2], [4, 5 , 0,7]])

Em [12]: df.ewm(0.5).mean()
Fora[12]:
0 1 2
0 1,000000 2,000000 0,600000
1 1,750000 2,750000 0,450000 2 2,615385
3,615385 0,276923 3 3,550000 4,550000
0,562500

Em [13]: online_ewm = df.head(2).ewm(0.5).online()

Em [14]: online_ewm.mean()
Fora[14]: 0
1 2
0 1,00 2,00 0,60
1 1,75 2,75 0,45

Em [15]: online_ewm.mean(update=df.tail(1))
Fora[15]:
0 1 2
3 3,307692 4,307692 0,623077

Todas as operações de janelas suportam um argumento min_periods que determina a quantidade mínima de valores não-np.nan
que uma janela deve ter; caso contrário, o valor resultante será np.nan. min_periods tem como padrão 1 para janelas baseadas
em tempo e janela para janelas fixas

Em [16]: s = pd.Series([np.nan, 1, 2, np.nan, np.nan, 3])

Em [17]: s.rolling(window=3, min_periods=1).sum()


(continua na próxima página)

2.19. Operações de janelas 825


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Fora[17]:
0 NaN
1 1,0
2 3,0
3 3,0
4 2,0
5 3,0
tipo d: float64

Em [18]: s.rolling(window=3, min_periods=2).sum()


Fora[18]:
0 NaN
NaN
1 2 3,0
3 3,0
4NaN
5NaN
tipo d: float64

# Equivalente a min_periods=3
Em [19]: s.rolling(window=3, min_periods=None).sum()
Fora[19]:
0 NaN
1 NaN
2NaN
3NaN
4NaN
5NaN
tipo d: float64

Além disso, todas as operações de janelas suportam o método agregado para retornar um resultado de múltiplas agregações
aplicado a uma janela.

Em [20]: df = pd.DataFrame({"A": range(5), "B": range(10, 15)})

Em [21]: df.expanding().agg([np.sum, np.mean, np.std])


Fora[21]:
A B
média da soma soma padrão significa padrão

0 0,0 0,0 1 1,0 0,5 NaN 10,0 10,0 NaN


0,707107 21,0 10,5 0,707107
2 3,0 1,0 1,000000 33,0 11,0 1,000000
3 6,0 1,5 1,290994 46,0 11,5 1,290994
4 10,0 2,0 1,581139 60,0 12,0 1,581139

826 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.19.2 Janela rolante


Janelas rolantes genéricas suportam a especificação de janelas como um número fixo de observações ou um número variável de observações com
base em um deslocamento. Se um deslocamento baseado em tempo for fornecido, o índice baseado em tempo correspondente deverá ser monotônico.

Em [22]: tempos = ['2020-01-01', '2020-01-03', '2020-01-04', '2020-01-05', '2020-01-29']

Em [23]: s = pd.Series(range(5), index=pd.DatetimeIndex(times))

Em [24]: s
Fora[24]:
01/01/2020 0
03/01/2020 1
04/01/2020 2
05/01/2020 3
29/01/2020 tipo 4
d: int64

# Janela com 2 observações


Em [25]: s.rolling(window=2).sum()
Fora[25]:
01/01/2020 NaN
03-01-2020 1,0
2020-01-04 3,0
05-01-2020 5,0
2020-01-29 7,0
tipo d: float64

# Janela com 2 dias de observações


Em [26]: s.rolling(window='2D').sum()
Fora[26]:
01/01/2020 0,0
2020-01-03 1.0
2020-01-04 3.0
05-01-2020 5.0
2020-01-29 4.0
tipo d: float64

Para todas as funções de agregação suportadas, consulte Funções de janela contínua.

Centralizando janelas

Por padrão, os rótulos são definidos na borda direita da janela, mas uma palavra-chave central está disponível para que os rótulos possam ser definidos
no centro.

Em [27]: s = pd.Series(intervalo(10))

Em [28]: s.rolling(window=5).mean()
Fora[28]:
0 NaN
1 NaN
2 NaN
3 NaN
(continua na próxima página)

2.19. Operações de janelas 827


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

4 2,0
5 3,0
6 4,0
7 5,0
8 6,0
9 7,0
tipo d: float64

Em [29]: s.rolling(window=5, center=True).mean()


Fora[29]:
0 NaN
NaN
1 2 2,0
3 3,0
4 4,0
5 5,0
6 6,0
7 7,0
8NaN
9NaN
tipo d: float64

Isso também pode ser aplicado a índices semelhantes a data e hora.

Novo na versão 1.3.0.

Em [30]: df = pd.DataFrame(
....: {"A": [0, 1, 2, 3, 4]}, index=pd.date_range("2020", períodos=5, freq="1D")
....: )
....:

Em [31]: df
Fora[31]:
A
2020-01-01 0
2020-01-02 1
2020-01-03 2
2020-01-04 3
2020-01-05 4

Em [32]: df.rolling("2D", center=False).mean()


Fora[32]:
A
01/01/2020 0,0
02/01/2020 0,5
03/01/2020 1,5
2020-01-04 2.5
05/01/2020 3,5

Em [33]: df.rolling("2D", center=True).mean()


Fora[33]:
A
01/01/2020 0,5
(continua na próxima página)

828 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


02/01/2020 1,5
2020-01-03 2.5
04/01/2020 3,5
2020-01-05 4.0

Extremidades da janela rolante

A inclusão dos pontos finais do intervalo nos cálculos da janela rolante pode ser especificada com o parâmetro fechado:

Valor Comportamento

'certo' fecha o ponto final direito


'esquerda' fecha o ponto final esquerdo

'ambos' fecham ambos os pontos finais

'nenhum' endpoints abertos

Por exemplo, ter o ponto final correto aberto é útil em muitos problemas que exigem que não haja contaminação
das informações atuais para as informações passadas. Isso permite que a janela contínua calcule estatísticas “até aquele
momento”, mas não incluindo esse momento.

Em [34]: df = pd.DataFrame(
....: {"x": 1},
....: índice=[
....: pd.Timestamp("20130101 09:00:01"),
....: pd.Timestamp("20130101 09:00:02"),
....: pd.Timestamp("20130101 09:00:03"),
....: pd.Timestamp("20130101 09:00:04"),
....: pd.Timestamp("20130101 09:00:06"),
....: ],
....: )
....:

Em [35]: df["right"] = df.rolling("2s", closed="right").x.sum() # padrão

Em [36]: df["ambos"] = df.rolling("2s", fechado="ambos").x.sum()

Em [37]: df["left"] = df.rolling("2s", closed="left").x.sum()

Em [38]: df["neither"] = df.rolling("2s", closed="neither").x.sum()

Em [39]: df
Fora[39]:
x direita ambos esquerda nem
01-01-2013 09:00:01 1 01-01-2013 1,0 1,0 NaN 2,0 2,0 1,0 NaN
09:00:02 1 01-01-2013 09:00:03 1 2,0 3,0 2,0 2,0 3,0 2,0 1,0
01-01-2013 09:00:04 1 01-01-2013 1,0 2,0 1,0 1,0
09 :00:06 1 1,0
NaN

2.19. Operações de janelas 829


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Rolamento de janela personalizado

Novo na versão 1.0.

Além de aceitar um número inteiro ou deslocamento como argumento de janela, roll também aceita uma subclasse BaseIndexer
que permite ao usuário definir um método personalizado para calcular os limites da janela. A subclasse BaseIndexer precisará
para definir um método get_window_bounds que retorna uma tupla de dois arrays, sendo o primeiro os índices iniciais do
janelas e em segundo lugar os índices finais das janelas. Além disso, num_values, min_periods, center,
fechado e será passado automaticamente para get_window_bounds e o método definido deve sempre aceitar estes
argumentos.

Por exemplo, se tivermos o seguinte DataFrame

Em [40]: use_expanding = [Verdadeiro, Falso, Verdadeiro, Falso, Verdadeiro]

Em [41]: use_expanding
Out[41]: [Verdadeiro, Falso, Verdadeiro, Falso, Verdadeiro]

Em [42]: df = pd.DataFrame({"valores": range(5)})

Em [43]: df
Fora[43]:
valores
0 0
1 1
2 2
3 3
4 4

e queremos usar uma janela de expansão onde use_expanding é True, caso contrário, uma janela de tamanho 1, podemos criar
a seguinte subclasse BaseIndexer:

Em [2]: de pandas.api.indexers importa BaseIndexer

Em [3]: classe CustomIndexer(BaseIndexer):


...: def get_window_bounds(self, num_values, min_periods, center, closed):
...: iniciar = np.empty(num_valores, dtype=np.int64)
...: fim = np.empty(num_valores, dtype=np.int64)
...: para i no intervalo (num_values):
...: se self.use_expanding[i]:
...: começar[i] = 0
...: fim[i] = i + 1
...: outro:
...: começar[i] = eu
...: fim[i] = i + self.window_size
...: retorno início, fim

Em [4]: indexador = CustomIndexer(window_size=1, use_expanding=use_expanding)

Em [5]: df.rolling(indexer).sum()
Fora[5]:
valores
0 0,0
1 1,0
2 3,0
(continua na próxima página)

830 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

3 3,0
4 10,0

Você pode ver outros exemplos de subclasses BaseIndexer aqui

Novo na versão 1.1.

Uma subclasse digna de nota nesses exemplos é a VariableOffsetWindowIndexer, que permite operações contínuas em um deslocamento
não fixo, como BusinessDay.

Em [44]: de pandas.api.indexers import VariableOffsetWindowIndexer

Em [45]: df = pd.DataFrame(range(10), index=pd.date_range("2020", períodos=10))

Em [46]: deslocamento = pd.offsets.BDay(1)

Em [47]: indexador = VariableOffsetWindowIndexer(index=df.index, offset=offset)

Em [48]: df
Fora[48]:
0
2020-01-01 0
2020-01-02 1
2020-01-03 2
2020-01-04 3
2020-01-05 4
2020-01-06 5
2020-01-07 6
2020-01-08 7
2020-01-09 8
2020-01-10 9

Em [49]: df.rolling(indexer).sum()
Fora[49]:

0 01/01/2020 0,0
02/01/2020 1,0
03/01/2020 2,0
04/01/2020 3,0
05/01/2020 7,0
06/01/2020 12,0
07/01/2020 6,0
08/01/2020 7,0
2020-01-09 8.0
2020-01-10 9,0

Para alguns problemas, o conhecimento do futuro está disponível para análise. Por exemplo, isso ocorre quando cada ponto de dados é uma
série temporal completa lida de um experimento e a tarefa é extrair condições subjacentes. Nestes casos, pode ser útil realizar cálculos de
janelas contínuas prospectivas. A classe FixedForwardWindowIndexer está disponível para essa finalidade. Esta subclasse BaseIndexer
implementa uma janela contínua fechada de largura fixa e podemos usá-la da seguinte maneira:

Em [50]: de pandas.api.indexers import FixedForwardWindowIndexer


(continua na próxima página)

2.19. Operações de janelas 831


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [51]: indexador = FixedForwardWindowIndexer(window_size=2)

Em [52]: df.rolling(indexer, min_periods=1).sum()


Fora[52]:
0
2020-01-01 1.0
2020-01-02 3.0
2020-01-03 5.0
2020-01-04 7.0
05/01/2020 9,0
06-01-2020 11.0
2020-01-07 13.0
08/01/2020 15,0
2020-01-09 17.0
2020-01-10 9,0

Também podemos conseguir isso usando fatiamento, aplicando agregação contínua e, em seguida, invertendo o resultado, conforme mostrado no exemplo
abaixo:

Em [53]: df = pd.DataFrame(
....: dados=[
....: [pd.Timestamp("01/01/2018 00:00:00"), 100],
....: [pd.Timestamp("01/01/2018 00:00:01"), 101],
....: [pd.Timestamp("01/01/2018 00:00:03"), 103],
....: [pd.Timestamp("01/01/2018 00:00:04"), 111],
....: ],
....: colunas=["hora", "valor"],
....: ).set_index("tempo")
....:

Em [54]: df
Fora[54]:
valor
tempo
01-01-2018 00:00:00 100
01-01-2018 00:00:01 101
01-01-2018 00:00:03 103
01-01-2018 00:00:04 111

Em [55]: reversed_df = df[::-1].rolling("2s").sum()[::-1]

Em [56]: invertido_df
Fora[56]:
valor
tempo
01/01/2018 00:00:00 201,0
01/01/2018 00:00:01 101,0
01/01/2018 00:00:03 214,0
01/01/2018 00:00:04 111,0

832 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Aplicação de rolamento

A função apply() recebe um argumento func extra e executa cálculos contínuos genéricos. O argumento funcional
deve ser uma função única que produza um único valor a partir de uma entrada ndarray. raw especifica se as janelas são
lançado como objetos Series (raw=False) ou objetos ndarray (raw=True).

Em [57]: def louco(x):


....: retornar np.fabs(x - x.mean()).mean()
....:

Em [58]: s = pd.Series(intervalo(10))

Em [59]: s.rolling(window=4).apply(mad, raw=True)


Fora[59]:
0 NaN
1 NaN
2 NaN
3 1,0
4 1,0
5 1,0
6 1,0
7 1,0
8 1,0
9 1,0
tipo d: float64

Motor Numba

Novo na versão 1.0.

Além disso, apply() pode aproveitar o Numba se instalado como uma dependência opcional. A agregação de aplicação pode ser
executado usando Numba especificando os argumentos engine='numba' e engine_kwargs (raw também deve ser definido como
Verdadeiro). Consulte melhorando o desempenho com Numba para uso geral dos argumentos e considerações de desempenho.

Numba será aplicado potencialmente em duas rotinas:

1. Se func for uma função padrão do Python, o mecanismo fará o JIT da função passada. func também pode ser uma função JITed
nesse caso, o motor não executará o JIT novamente.

2. O mecanismo fará JIT no loop for onde a função apply é aplicada a cada janela.

O argumento engine_kwargs é um dicionário de argumentos de palavras-chave que serão passados para o decorador numba.jit.
Esses argumentos de palavra-chave serão aplicados à função passada (se for uma função Python padrão) e ao aplicativo para
faça um loop sobre cada janela.

Novo na versão 1.3.0.

média, mediana, máximo, mínimo e soma também suportam os argumentos motor e motor_kwargs.

2.19. Operações de janelas 833


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Funções de janela binária

cov() e corr() podem calcular estatísticas de janelas móveis sobre duas séries ou qualquer combinação de
DataFrame/Series ou DataFrame/DataFrame. Aqui está o comportamento em cada caso:

• duas séries: calcula a estatística do emparelhamento.

• DataFrame/Series: calcula as estatísticas para cada coluna do DataFrame com a Series passada, assim
retornando um DataFrame.

• DataFrame/DataFrame: por padrão calcula a estatística para correspondência de nomes de colunas, retornando um
DataFrame. Se o argumento da palavra-chave pairwise=True for passado, então calcula a estatística para cada par de
colunas, retornando um DataFrame com um MultiIndex cujos valores são as datas em questão (veja a próxima seção).

Por exemplo:

Em [60]: df =
....: pd.DataFrame( np.random.randn(10, 4),
....: index=pd.date_range("2020-01-01", períodos=10), colunas=["A", "B
....: ", "C", "D"],
....: )
....:

Em [61]: df = df.cumsum()

Em [62]: df2 = df[:4]

Em [63]: df2.rolling(window=2).corr(df2["B"])
Fora[63]:
A B C D
2020-01-01 NaN NaN NaN NaN
2020-01-02 -1,0 1,0 -1,0 1,0
2020-01-03 1,0 1,0 1,0 -1,0
2020-01-04 -1,0 1,0 1,0 -1,0

Calculando covariâncias e correlações de pares contínuos

Na análise de dados financeiros e em outras áreas, é comum calcular matrizes de covariância e correlação para uma coleção de
séries temporais. Freqüentemente, também se está interessado em matrizes de covariância e correlação de janela móvel. Isso
pode ser feito passando o argumento da palavra-chave pairwise, que no caso de entradas do DataFrame produzirá um DataFrame
MultiIndexado cujo índice são as datas em questão. No caso de um único argumento DataFrame, o argumento pairwise pode até
ser omitido:

Nota: Os valores omissos são ignorados e cada entrada é calculada usando as observações completas aos pares. Consulte a
seção de covariância para obter advertências associadas a este método de cálculo de matrizes de covariância e correlação.

Em [64]: covs = ( df[["B",


....: "C",
....:
....: "D"]] .rolling(window=4) .cov(df[["A", "B", "C"]] , par a par=Verdadeiro)
....: )
....:

(continua na próxima página)

834 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [65]: covs
Fora[65]:
B C D
01/01/2020 NaN NaN NaN
B NaN NaN NaN
C NaN NaN NaN
2020-01-02 NaN NaN NaN
B NaN NaN NaN
... ... ... ...
2020-01-09 B 0,342006 0,230190 0,052849
C 0,230190 1,575251 0,082901
2020-01-10 UM -0,333945 0,006871 -0,655514
B 0,649711 0,430860 0,469271
C 0,430860 0,829721 0,055300

[30 linhas x 3 colunas]

2.19.3 Janela ponderada

O argumento win_type em .rolling gera janelas ponderadas que são comumente usadas em filtragem e espectro
estimativa. win_type deve ser uma string que corresponda a uma função de janela scipy.signal. O Scipy deve ser instalado em
para usar essas janelas, e argumentos suplementares que os métodos de janela do Scipy usam devem ser especificados em
a função de agregação.

Em [66]: s = pd.Series(intervalo(10))

Em [67]: s.rolling(window=5).mean()
Fora[67]:
0 NaN
NaN
1 NaN
2 3 NaN

4 2,0
5 3,0
6 4,0
7 5,0
8 6,0
9 7,0
tipo d: float64

Em [68]: s.rolling(window=5, win_type="triang").mean()


Fora[68]:
0 NaN
1 NaN
2 NaN
3 NaN
4 2,0
5 3,0
6 4,0
7 5,0
8 6,0
(continua na próxima página)

2.19. Operações de janelas 835


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


9 7,0
tipo d: float64

# Argumentos complementares do Scipy passados na função de agregação


Em [69]: s.rolling(window=5, win_type="gaussian").mean(std=0.1)
Fora[69]:
0 NaN
1 NaN
2 NaN
3 NaN
4 2,0
5 3,0
6 4,0
7 5,0
8 6,0
9 7,0
tipo d: float64

Para todas as funções de agregação suportadas, consulte Funções de janela ponderadas.

2.19.4 Janela de expansão

Uma janela em expansão produz o valor de uma estatística de agregação com todos os dados disponíveis até aquele momento.
Como esses cálculos são um caso especial de estatísticas contínuas, eles são implementados em pandas de forma que o seguinte
duas chamadas são equivalentes:

Em [70]: df = pd.DataFrame(intervalo(5))

Em [71]: df.rolling(window=len(df), min_periods=1).mean()


Fora[71]:
0
0 0,0
1 0,5
2 1,0
3 1,5
4 2,0

Em [72]: df.expanding(min_periods=1).mean()
Fora[72]:
0
0 0,0
1 0,5
2 1,0
3 1,5
4 2,0

Para todas as funções de agregação suportadas, consulte Funções de janela de expansão.

836 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.19.5 Janela ponderada exponencialmente

Uma janela ponderada exponencialmente é semelhante a uma janela em expansão, mas com cada ponto anterior sendo exponencialmente
ponderado em relação ao ponto atual.

Em geral, uma média móvel ponderada é calculada como

= ÿÿ =0 -
,
ÿÿ =0

onde está a entrada, é o resultado e são os pesos.

Para todas as funções de agregação suportadas, consulte Funções de janela ponderadas exponencialmente.

As funções EW suportam duas variantes de pesos exponenciais. O padrão, Adjust=True, usa os pesos =
(1 ÿ ) que dá

2
= + (1 ÿ ) ÿ1 + (1 ÿ ) ÿ2 +… + (1 ÿ ) 0
2
1 + (1 ÿ ) + (1 ÿ ) + ... + (1 ÿ )

Quando Adjust=False é especificado, as médias móveis são calculadas como

=
0 0

= (1 ÿ ) ÿ1 + ,

o que equivale a usar pesos

se <
(1ÿÿ)) se = .
= {ÿ (1

' =1ÿ
Nota: Essas equações às vezes são escritas em termos de , por exemplo

= '
ÿ1 + (1 ÿ
'
) .

A diferença entre as duas variantes acima surge porque estamos lidando com séries que possuem história finita.
Considere uma série de história infinita, com Adjust=True:
2
= + (1 ÿ ) ÿ1 + (1 ÿ ) ÿ2 + ...
2 + ...
1 + (1 ÿ ) + (1 ÿ )

Observando que o denominador é uma série geométrica com termo inicial igual a 1 e proporção de 1 - temos
2
= + (1 ÿ ) ÿ1 + (1 ÿ ) ÿ2 + ...
1
1ÿ(1ÿ )
2
= [ + (1 ÿ ) ÿ1 + (1 ÿ ) ÿ2 + ...]
2
= + [(1 ÿ ) ÿ1 + (1 ÿ ) ÿ2 + ...] =

+ (1 ÿ )[ ÿ1 + (1 ÿ ) ÿ2 + ...] = + (1 ÿ ) ÿ1

que é a mesma expressão que Adjust=False acima e, portanto, mostra a equivalência das duas variantes para
série infinita. Quando Adjust=False, temos que =
0 0 e = + (1ÿ) ÿ1. Portanto, há uma suposição
não é 0um valor comum, mas sim um momento exponencialmente ponderado da série infinita até aquele ponto.

2.19. Operações de janelas 837


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

É preciso ter 0 < ÿ 1 e, embora seja possível passar diretamente, muitas vezes é mais fácil pensar no vão, no centro de massa (com)
ou na meia-vida de um momento EW:

ÿ para vão ÿ 1
2
= para centro de massa ÿ 0
ÿÿ
+1 , 1 1+ ,
registro

ÿÿ 1 ÿ exp
0,5 ÿ
, para meia-vida ÿ > 0

Deve-se especificar precisamente amplitude , centro de massa, meia-vida e alfa para as funções EW:

• Span corresponde ao que é comumente chamado de “média móvel EW de N dias”.

• O centro de massa tem uma interpretação mais física e pode ser pensado em termos de extensão: = ( ÿ 1)/2.

• A meia-vida é o período de tempo para o peso exponencial ser reduzido à metade.

• Alpha especifica o fator de suavização diretamente.

Novo na versão 1.1.0.

Você também pode especificar a meia-vida em termos de uma unidade conversível timedelta para especificar a quantidade de tempo que leva
para uma observação cair para metade do seu valor ao especificar também uma sequência de tempos.

Em [73]: df = pd.DataFrame({"B": [0, 1, 2, np.nan, 4]})

Em [74]: df
Fora[74]:
B
0 0,0
1 1,0
2 2,0
3NaN
4 4,0

Em [75]: tempos = ["2020-01-01", "2020-01-03", "2020-01-10", "2020-01-15", "2020-01-17"]

Em [76]: df.ewm(halflife="4 dias", times=pd.DatetimeIndex(times)).mean()


Fora[76]:

B 0 0,000000 1
0,585786 2
1,523889 3
1,523889 4
3,233686

A fórmula a seguir é usada para calcular a média ponderada exponencialmente com um vetor de entrada de tempos:
-

0,5
= ÿÿ =0
-
- ,
ÿÿ =0 0,5

ExponentialMovingWindow também possui um argumento ignore_na, que determina como os valores nulos intermediários afetam o
cálculo dos pesos. Quando ignore_na=False (o padrão), os pesos são calculados com base em posições absolutas, de modo que
valores nulos intermediários afetem o resultado. Quando ignore_na=True, os pesos são calculados ignorando valores nulos
intermediários. Por exemplo, assumindo Adjust=True, se ignore_na=False, a média ponderada de 3, NaN, 5 seria calculada como

(1 ÿ ) (1 2 · 3 + 1 · 5
.
2 +1
ÿ)

838 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Considerando que se ignore_na=True, a média ponderada seria calculada como

(1 ÿ ) · 3 + 1 · 5 (1
.
ÿ)+1

As funções var(), std() e cov() possuem um argumento de polarização, especificando se o resultado deve conter estatísticas
tendenciosas ou imparciais. Por exemplo, se bias=True, ewmvar(x) é calculado como ewmvar(x) = ewma(x**2) - ewma(x)**2; enquanto
que se polarização=Falso (o padrão), as estatísticas de variância tendenciosa são dimensionadas por fatores de redução de polarização

(ÿÿÿ =0 )ÿ2 .
2
(ÿÿÿ =0 )ÿ2 ÿ ÿÿ =0

(Para = 1, isso se reduz ao fator /( ÿ1) usual, com = +1.) Consulte Variância ponderada da amostra na Wikipedia para obter
mais detalhes.

2.20 Funcionalidade de série temporal/data

pandas contém amplos recursos e recursos para trabalhar com dados de série temporal para todos os domínios. Usando os
dtypes NumPy datetime64 e timedelta64, o pandas consolidou um grande número de recursos de outras bibliotecas Python,
como scikits.timeseries, bem como criou uma enorme quantidade de novas funcionalidades para manipular dados de séries
temporais.

Por exemplo, pandas suporta:

Analisando informações de série temporal de várias fontes e formatos

Em [1]: importar data e hora

Em [2]: dti = pd.to_datetime(


...: ["01/01/2018", np.datetime64("2018-01-01"), datetime.datetime(2018, 1, 1)]
... :)
...:

Em [3]: dti
Saída[3]: DatetimeIndex(['2018-01-01', '2018-01-01', '2018-01-01'], dtype='datetime64[ns]', ÿÿ freq=None)

Gere sequências de datas e intervalos de tempo de frequência fixa

Em [4]: dti = pd.date_range("2018-01-01", períodos=3, freq="H")

Em [5]: dti
Fora[5]:
DatetimeIndex(['2018-01-01 00:00:00', '2018-01-01 01:00:00', '2018-01-01
02:00:00'], dtype='datetime64[ns]
', frequência='H')

Manipulação e conversão de data e hora com informações de fuso horário

Em [6]: dti = dti.tz_localize("UTC")

Em [7]: dti
Fora[7]:
(continua na próxima página)

2.20. Funcionalidade de série temporal/data 839


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

DatetimeIndex(['2018-01-01 00:00:00+00:00', '2018-01-01 01:00:00+00:00', '2018-01-01 02:00:00+00 :00'],


dtype='datetime64[ns, UTC]', freq='H')

Em [8]: dti.tz_convert("EUA/Pacífico")
Saída [8]:
DatetimeIndex (['2017-12-31 16:00:00-08:00', '2017-12-31 17:00:00-08:00', '2017-12-31 18: 00:00-08:00'],
dtype='datetime64[ns, EUA/Pacífico]',
freq='H')

Reamostrar ou converter uma série temporal para uma frequência específica

Em [9]: idx = pd.date_range("2018-01-01", períodos=5, freq="H")

Em [10]: ts = pd.Series(range(len(idx)), index=idx)

Em [11]: ts
Saída[11]:
01-01-2018 00:00:00 0
01/01/2018 01:00:00 1
01/01/2018 02:00:00 2
01/01/2018 03:00:00 3
01/01/2018 04:00:00 4
Freq: H, tipo d: int64

Em [12]: ts.resample("2H").mean()
Fora[12]:
01/01/2018 00:00:00 0,5
01-01-2018 02:00:00 2.5 01-01-2018
04:00:00 4.0 Freq: 2H, tipo d: float64

Executando aritmética de data e hora com incrementos de tempo absolutos ou relativos

Em [13]: sexta-feira = pd.Timestamp("2018-01-05")

Em [14]: sexta-feira.day_name()
Saída[14]: 'Sexta-feira'

# Adicionar 1 dia
em [15]: sábado = sexta + pd.Timedelta("1 dia")

Em [16]: sábado.day_name()
Saída[16]: 'Sábado'

# Adicione 1 dia útil (sexta-feira -> segunda-feira)


Em [17]: segunda = sexta + pd.offsets.BDay()

Em [18]: monday.day_name()
Saída[18]: 'Segunda-feira'

O pandas fornece um conjunto de ferramentas relativamente compacto e independente para executar as tarefas acima e muito mais.

840 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.20.1 Visão Geral

pandas captura 4 conceitos gerais relacionados ao tempo:

1. Data e hora: uma data e hora específicas com suporte de fuso horário. Semelhante a datetime.datetime do padrão
biblioteca.

2. Deltas de tempo: uma duração de tempo absoluta. Semelhante a datetime.timedelta da biblioteca padrão.

3. Intervalos de tempo: Um período de tempo definido por um ponto no tempo e sua frequência associada.

4. Deslocamentos de data: Uma duração relativa que respeita a aritmética do calendário. Semelhante a dateutil.relativedelta.
relativodelta do pacote dateutil.

Conceito Escalar Classe de matriz tipo de dados pandas Método de Criação Primária
Aula
Data Carimbo de data/hora DatetimeIndex datetime64[ns] ou até_datahora ou intervalo_de_datas
vezes datetime64[ns, tz]
Tempo Timedelta TimedeltaIndextimedelta64[ns] to_timedelta ou
deltas timedelta_range
Tempo Período PeríodoÍndice período[freq] Período ou intervalo_período
vãos
Data de folga- DataOffset Nenhum Nenhum DataOffset
conjuntos

Para dados de série temporal, é convencional representar o componente temporal no índice de uma Série ou DataFrame para que
manipulações podem ser realizadas em relação ao elemento de tempo.

Em [19]: pd.Series(range(3), index=pd.date_range("2000", freq="D", períodos=3))


Fora[19]:
01/01/2000 0
02/01/2000 1
03/01/2000 2
Freq: D, tipo d: int64

No entanto, Series e DataFrame também podem suportar diretamente o componente de tempo como os próprios dados.

Em [20]: pd.Series(pd.date_range("2000", freq="D", períodos=3))


Fora[20]:
0 01/01/2000
102-01-2000
2000-01-03
tipo d: datahora64[ns]

Series e DataFrame estenderam o suporte e a funcionalidade de tipos de dados para datetime, timedelta e Period
dados quando passados para esses construtores. Os dados DateOffset, entretanto, serão armazenados como dados de objeto.

Em [21]: pd.Series(pd.period_range("1/1/2011", freq="M", períodos=3))


Fora[21]:
0 2011-01
1 2011-02
2 2011-03
dtipo: período[M]

Em [22]: pd.Series([pd.DateOffset(1), pd.DateOffset(2)])


(continua na próxima página)

2.20. Funcionalidade de série temporal/data 841


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


Fora[22]:
0 <DataOffset>
1 <2 * Compensações de Data>

dtype: objeto

Em [23]: pd.Series(pd.date_range("1/1/2011", freq="M", períodos=3))


Fora[23]:
0 31/01/2011
12011-02-28
2 31/03/2011
tipo d: datahora64[ns]

Por último, pandas representa datas nulas, deltas de tempo e intervalos de tempo como NaT, o que é útil para representar valores semelhantes a
datas nulas ou ausentes e se comporta de maneira semelhante a np.nan para dados flutuantes.

Em [24]: pd.Timestamp(pd.NaT)
Fora[24]: NaT

Em [25]: pd.Timedelta(pd.NaT)
Fora[25]: NaT

Em [26]: pd.Period(pd.NaT)
Fora[26]: NaT

# A igualdade atua como np.nan faria In


[27]: pd.NaT == pd.NaT Out[27]:
False

2.20.2 Carimbos de data e hora versus intervalos de tempo

Os dados com carimbo de data e hora são o tipo mais básico de dados de série temporal que associam valores a pontos no tempo. Para
objetos pandas, significa usar os pontos no tempo.

Em [28]: pd.Timestamp(datetime.datetime(2012, 5, 1))


Saída[28]: Carimbo de data/hora('2012-05-01 00:00:00')

Em [29]: pd.Timestamp("01/05/2012")
Saída[29]: Carimbo de data/hora('2012-05-01 00:00:00')

Em [30]: pd.Timestamp(2012, 5, 1)
Saída[30]: Carimbo de data/hora('2012-05-01 00:00:00')

No entanto, em muitos casos, é mais natural associar coisas como variáveis de mudança a um intervalo de tempo. O intervalo representado
por Período pode ser especificado explicitamente ou inferido a partir do formato de string de data e hora.

Por exemplo:

Em [31]: pd.Period("2011-01")
Fora[31]: Período('2011-01', 'M')

Em [32]: pd.Period("2012-05", freq="D")


Fora[32]: Período('2012-05-01', 'D')

842 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Timestamp e Period podem servir como índice. Listas de carimbo de data/hora e período são automaticamente coagidas
para DatetimeIndex e PeriodIndex respectivamente.

Em [33]: datas =
....: [ pd.Timestamp("2012-05-01"),
....: pd.Timestamp("2012-05-02"),
....: pd.Timestamp("2012-05-03"),
....: ]
....:

Em [34]: ts = pd.Series(np.random.randn(3), datas)

Em [35]: tipo(ts.index)
Saída[35]: pandas.core.indexes.datetimes.DatetimeIndex

In [36]: ts.index Out[36]:


DatetimeIndex(['2012-05-01', '2012-05-02', '2012-05-03'], dtype='datetime64[ns] ÿÿ ', frequência=Nenhum)

Em [37]: ts
Saída[37]:
01/05/2012 0,469112
02/05/2012 -0,282863
03-05-2012 -1.509059
tipo d: float64

Em [38]: períodos = [pd.Period("2012-01"), pd.Period("2012-02"), pd.Period("2012-03")]

Em [39]: ts = pd.Series(np.random.randn(3), períodos)

Em [40]: tipo(ts.index)
Fora[40]: pandas.core.indexes.period.PeriodIndex

In [41]: ts.index Out[41]:


PeriodIndex(['2012-01', '2012-02', '2012-03'], dtype='período[M]')

Entrada [42]: ts
Saída [42]:
2012-01 -1,135632 2012-02
1,212112 2012-03 -0,173215
Freq: M, dtype: float64

pandas permite capturar ambas as representações e converter entre elas. Nos bastidores, o pandas representa carimbos de data/
hora usando instâncias de Timestamp e sequências de carimbos de data/hora usando instâncias de DatetimeIndex. Para
intervalos de tempo regulares, o pandas usa objetos Period para valores escalares e PeriodIndex para sequências de intervalos.
Melhor suporte para intervalos irregulares com pontos iniciais e finais arbitrários estará disponível em versões futuras.

2.20. Funcionalidade de série temporal/data 843


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.20.3 Convertendo para carimbos de data/hora

Para converter uma série ou objeto semelhante a uma lista de objetos semelhantes a datas, por exemplo, strings, épocas ou uma
mistura, você pode usar a função to_datetime. Quando passado por uma Série, retorna uma Série (com o mesmo índice), enquanto
uma lista é convertida em um DatetimeIndex:

Em [43]: pd.to_datetime(pd.Series([" 31 de julho de 2009", "2010-01-10", Nenhum]))


Fora[43]:
0 31/07/2009
10/01/2010
2 NaT
tipo d: datahora64[ns]

Em [44]: pd.to_datetime(["2005/11/23", "2010.12.31"])


Saída[44]: DatetimeIndex(['2005-11-23', '2010-12-31'], dtype='datetime64[ns]', freq=None)

Se você usar datas que começam com o dia primeiro (ou seja, no estilo europeu), você pode passar a bandeira dayfirst:

Em [45]: pd.to_datetime(["04-01-2012 10:00"], dayfirst=True)


Saída[45]: DatetimeIndex(['2012-01-04 10:00:00'], dtype='datetime64[ns]', freq=Nenhum)

Em [46]: pd.to_datetime(["14-01-2012", "01-14-2012"], dayfirst=True)


Saída[46]: DatetimeIndex(['2012-01-14', '2012-01-14'], dtype='datetime64[ns]', freq=None)

Aviso: você vê no exemplo acima que dayfirst não é rigoroso. Se uma data não puder ser analisada com o primeiro dia, ela
será analisada como se dayfirst fosse False e, no caso de análise de strings de datas delimitadas (por exemplo, 31-12-2012),
um aviso também será gerado.

Se você passar uma única string para to_datetime, ela retornará um único carimbo de data/hora. Timestamp também pode aceitar
entrada de string, mas não aceita opções de análise de string como dayfirst ou format, então use to_datetime se forem necessários.

Em [47]: pd.to_datetime("2010/11/12")
Saída[47]: Carimbo de data/hora('2010-11-12 00:00:00')

Em [48]: pd.Timestamp("2010/11/12")
Saída[48]: Carimbo de data/hora('2010-11-12 00:00:00')

Você também pode usar o construtor DatetimeIndex diretamente:

Em [49]: pd.DatetimeIndex(["2018-01-01", "2018-01-03", "2018-01-05"])


Out[49]: DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'], dtype='datetime64[ns] ÿÿ', freq=None)

A string 'infer' pode ser passada para definir a frequência do índice como a frequência inferida na criação:

Em [50]: pd.DatetimeIndex(["2018-01-01", "2018-01-03", "2018-01-05"], freq="infer")


Saída[50]: DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'], dtype='datetime64[ns] ÿÿ', freq='2D')

844 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Fornecendo um argumento de formato

Além da sequência de data e hora necessária, um argumento de formato pode ser passado para garantir uma análise específica.
Isso também poderia acelerar consideravelmente a conversão.

Em [51]: pd.to_datetime("2010/11/12", format="%Y/%m/%d")


Saída[51]: Carimbo de data/hora('2010-11-12 00:00:00')

Em [52]: pd.to_datetime("12-11-2010 00:00", format="%d-%m-%Y %H:%M")


Saída[52]: Carimbo de data/hora('2010-11-12 00:00:00')

Para obter mais informações sobre as opções disponíveis ao especificar a opção de formato, consulte a documentação de data e hora do
Python.

Montando data e hora de várias colunas do DataFrame

Você também pode passar um DataFrame de colunas inteiras ou de string para montar em uma série de carimbos de data/hora.

Em [53]: df = pd.DataFrame( {"ano":


....: [2015, 2016], "mês": [2, 3], "dia": [4, 5], "hora": [2, 3 ]}
....: )
....:

Em [54]: pd.to_datetime(df)
Saída [54]:
0 04/02/2015 02:00:00 1 05/03/2016
03:00:00 dtype: datetime64[ns]

Você pode passar apenas as colunas que precisa montar.

Em [55]: pd.to_datetime(df[["ano", "mês", "dia"]])


Fora[55]: 0
04/02/2015
1 05/03/2016
tipo d: datahora64[ns]

pd.to_datetime procura designações padrão do componente datetime nos nomes das colunas, incluindo:

• obrigatório: ano, mês, dia

• opcional: hora, minuto, segundo, milissegundo, microssegundo, nanossegundo

Dados inválidos

O comportamento padrão, erros='raise', é aumentar quando não for analisável:

Em [2]: pd.to_datetime(['2009/07/31', 'asd'], erros='raise')


ValueError: formato de string desconhecido

Passe erros='ignore' para retornar a entrada original quando não for analisável:

Em [56]: pd.to_datetime(["2009/07/31", "asd"], erros = "ignorar")


Fora[56]: Índice(['2009/07/31', 'asd'], dtype='objeto')

2.20. Funcionalidade de série temporal/data 845


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Passe errors='coerce' para converter dados não analisáveis em NaT (não um horário):

Em [57]: pd.to_datetime(["2009/07/31", "asd"], erros = "coercer")


Saída[57]: DatetimeIndex(['2009-07-31', 'NaT'], dtype='datetime64[ns]', freq=None)

Carimbos de data e hora da época

pandas suporta a conversão de tempos de época inteiros ou flutuantes para Timestamp e DatetimeIndex. A unidade padrão é
nanossegundos, pois é assim que os objetos Timestamp são armazenados internamente. No entanto, as épocas são frequentemente
armazenadas em outra unidade que pode ser especificada. Eles são calculados a partir do ponto inicial especificado pelo parâmetro origin.

Em [58]: pd.to_datetime(
....: [1349720105, 1349806505, 1349892905, 1349979305, 1350065705], unidade = "s"
....: )
....:
Fora[58]:
DatetimeIndex(['2012-10-08 18:15:05', '2012-10-09 18:15:05', '2012-10-10 18:15:05',
'2012-10-11 18: 15:05', '12/10/2012 18:15:05'],

dtype='datetime64[ns]',freq=Nenhum)

Em [59]: pd.to_datetime(
....: [1349720105100, 1349720105200 , 1349720105300, 1349720105400, 1349720105500], unidade = "ms",
....:
....: )
....:
Saída [59]:
DatetimeIndex (['2012-10-08 18:15:05.100000', '2012-10-08 18:15:05.200000', '2012-10-08
18:15:05.300000', '2012- 08/10 18:15:05.400000', '08/10/2012 18:15:05.500000'],
dtype='datetime64[ns]', freq=Nenhum)

Nota: O parâmetro unit não usa as mesmas strings que o parâmetro format discutido acima). As unidades disponíveis estão
listadas na documentação de pandas.to_datetime().

Alterado na versão 1.0.0.


Construir um Timestamp ou DatetimeIndex com um carimbo de data e hora de época com o argumento tz especificado gerará um ValueError.
Se você tiver épocas no horário de parede em outro fuso horário, poderá ler as épocas como carimbos de data e hora ingênuos do fuso horário
e, em seguida, localizá-las para o fuso horário apropriado:

Em [60]: pd.Timestamp(1262347200000000000).tz_localize("EUA/Pacífico")
Saída[60]: Timestamp('2010-01-01 12:00:00-0800', tz='EUA/Pacífico')

Em [61]: pd.DatetimeIndex([1262347200000000000]).tz_localize("EUA/Pacífico")
Out[61]: DatetimeIndex(['2010-01-01 12:00:00-08:00'], dtype='datetime64[ns, US/Pacific]', ÿÿ freq=None)

Nota: Os tempos das épocas serão arredondados para o nanossegundo mais próximo.

846 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Aviso: A conversão de tempos de época flutuante pode levar a resultados imprecisos e inesperados. Os carros flutuantes do Python têm
precisão de cerca de 15 dígitos em decimal. O arredondamento durante a conversão de float para carimbo de data/hora de alta precisão é inevitável.
A única maneira de obter precisão exata é usar tipos de largura fixa (por exemplo, um int64).

Em [62]: pd.to_datetime([1490195805.433, 1490195805.433502912], unidade = "s")


Saída[62]: DatetimeIndex(['2017-03-22 15:16:45.433000088', '2017-03-22 15:16:45. ÿÿ433502913'],
dtype='datetime64[ns]', freq= Nenhum)

Em [63]: pd.to_datetime(1490195805433502912, unit="ns")


Saída[63]: carimbo de data/hora ('2017-03-22 15:16:45.433502912')

Veja também:

Usando o parâmetro origin

De carimbos de data/hora a época

Para inverter a operação acima, ou seja, para converter de um Timestamp para uma época 'unix':

Em [64]: carimbos = pd.date_range("2012-10-08 18:15:05", períodos=4, freq="D")

Em [65]: selos
Fora[65]:
DatetimeIndex(['2012-10-08 18:15:05', '2012-10-09 18:15:05', '2012-10-10 18:15:05',
'2012-10-11 18: 15:05'], dtype='datetime64[ns]', freq='D')

Subtraímos a época (meia-noite de 1º de janeiro de 1970 UTC) e depois dividimos o piso pela “unidade” (1 segundo).

Em [66]: (selos - pd.Timestamp("1970-01-01")) // pd.Timedelta("1s")


Saída[66]: Int64Index([1349720105, 1349806505, 1349892905, 1349979305], dtype='int64')

Usando o parâmetro origem

Usando o parâmetro origin, pode-se especificar um ponto de partida alternativo para a criação de um DatetimeIndex. Por exemplo,
para usar 1960-01-01 como data de início:

Em [67]: pd.to_datetime([1, 2, 3], unit="D", origin=pd.Timestamp("1960-01-01"))


Out[67]: DatetimeIndex(['1960-01-02', '1960-01-03', '1960-01-04'], dtype='datetime64[ns] ÿÿ', freq=Nenhum)

O padrão é definido em origin='unix', cujo padrão é 1970-01-01 00:00:00. Comumente chamada de 'época unix' ou hora POSIX.

Em [68]: pd.to_datetime([1, 2, 3], unidade="D")


Out[68]: DatetimeIndex(['1970-01-02', '1970-01-03', '1970-01-04'], dtype='datetime64[ns] ÿÿ', freq=Nenhum)

2.20. Funcionalidade de série temporal/data 847


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.20.4 Gerando intervalos de carimbos de data/hora

Para gerar um índice com carimbos de data e hora, você pode usar o construtor DatetimeIndex ou Index e passar uma lista de
objetos de data e hora:

Em [69]: datas =
....: [ datetime.datetime(2012, 5, 1),
....: datetime.datetime(2012, 5, 2),
....: datetime.datetime(2012, 5, 3),
....: ]
....:

# Observe as informações de frequência em


[70]: index = pd.DatetimeIndex(dates)

Em [71]: índice
Out[71]: DatetimeIndex(['2012-05-01', '2012-05-02', '2012-05-03'], dtype='datetime64[ns] ÿÿ', freq=None)

# Convertido automaticamente para DatetimeIndex In


[72]: index = pd.Index(dates)

Em [73]: índice
Out[73]: DatetimeIndex(['2012-05-01', '2012-05-02', '2012-05-03'], dtype='datetime64[ns] ÿÿ', freq=None)

Na prática, isso se torna muito complicado porque muitas vezes precisamos de um índice muito longo com um grande número de carimbos de data/hora.
Se precisarmos de carimbos de data/hora em uma frequência regular, podemos usar as funções date_range() e bdate_range()
para criar um DatetimeIndex. A frequência padrão para intervalo_data é um dia corrido , enquanto o padrão para intervalo_data
é um dia útil:

Em [74]: início = datetime.datetime(2011, 1, 1)

Em [75]: fim = datetime.datetime(2012, 1, 1)

Em [76]: índice = pd.date_range(início, fim)

Em [77]: índice
Fora[77]:
DatetimeIndex(['2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06' ,
'2011-01-07', '2011-01-08', '2011-01-09', '2011-01-10',

...
'2011-12-23', '2011-12-24', '2011-12-25', '2011-12-26', '2011-12-27',
'2011-12-28', '2011 -12-29', '2011-12-30', '2011-12-31', '2012-01-01'],
dtype='datetime64[ns]',
comprimento=366, freq='D')

Em [78]: índice = pd.bdate_range(início, fim)

Em [79]: índice
Fora[79]:
DatetimeIndex(['2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06', '2011-01-07', '2011-01-10' ,
'11/01/2011', '12/01/2011',
(continua na próxima página)

848 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

'13/01/2011', '14/01/2011',
...
'2011-12-19', '2011-12-20', '2011-12-21', '2011-12-22', '2011-12-23',
'2011-12-26', '2011 -12-27', '2011-12-28', '2011-12-29', '2011-12-30'],
dtype='datetime64[ns]',
comprimento=260, freq='B')

Funções de conveniência como date_range e bdate_range podem utilizar uma variedade de aliases de frequência:

Em [80]: pd.date_range(início, períodos=1000, freq="M")


Saída
[80]: DatetimeIndex (['2011-01-31', '2011-02-28', '2011-03-31', '2011-04-30', '2011-05-31',
'2011 -06-30', '2011-07-31', '2011-08-31', '2011-09-30', '2011-10-31',

...
'2093-07-31', '2093-08-31', '2093-09-30', '2093-10-31', '2093-11-30',
'2093-12-31', '2094 -01-31', '2094-02-28', '2094-03-31', '2094-04-30'],

dtype='datetime64[ns]', comprimento=1000, freq='M')

Em [81]: pd.bdate_range(início, períodos=250, freq="BQS")


Saída
[81]: DatetimeIndex (['2011-01-03', '2011-04-01', '2011-07-01', '2011-10-03', '2012-01-02',
'2012 -04-02', '2012-07-02', '2012-10-01', '2013-01-01', '2013-04-01',

...
'2071-01-01', '2071-04-01', '2071-07-01', '2071-10-01', '2072-01-01',
'2072-04-01', '2072 -07-01', '2072-10-03', '2073-01-02', '2073-04-03'],

dtype='datetime64[ns]', comprimento=250, freq='BQS-JAN')

date_range e bdate_range facilitam a geração de um intervalo de datas usando várias combinações de parâmetros como
início, fim, períodos e frequência. As datas de início e término são estritamente inclusivas, portanto não serão geradas
datas fora das especificadas:

Em [82]: pd.date_range(início, fim, freq="BM")


Saída
[82]: DatetimeIndex (['2011-01-31', '2011-02-28', '2011-03-31', '2011-04-29', '2011-05-31',
'2011 -06-30', '2011-07-29', '2011-08-31', '2011-09-30', '2011-10-31',
'2011-11-30', '2011-12 -30'],
dtype='datetime64[ns]',freq='BM')

Em [83]: pd.date_range(início, fim, freq="W")


Saída
[83]: DatetimeIndex (['2011-01-02', '2011-01-09', '2011-01-16', '2011-01-23', '2011-01-30',
'2011 -02-06', '2011-02-13', '2011-02-20', '2011-02-27', '2011-03-06',
'2011-03-13', '2011-03 -20', '2011-03-27', '2011-04-03', '2011-04-10',
'2011-04-17', '2011-04-24', '2011-05-01 ', '2011-05-08', '2011-05-15',
'2011-05-22', '2011-05-29', '2011-06-05', '2011-06-12', '19/06/2011',
'26/06/2011', '03/07/2011', '10/07/2011', '17/07/2011', '24/07/2011', '2011
-07-31', '07-08-2011',

(continua na próxima página)

2.20. Funcionalidade de série temporal/data 849


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

'14/08/2011', '21/08/2011', '28/08/2011', '04/09/2011', '11/09/2011',


'18/09/2011', '2011 -09-25', '2011-10-02', '2011-10-09', '2011-10-16',
'2011-10-23', '2011-10-30', '2011-11 -06', '2011-11-13', '2011-11-20',
'2011-11-27', '2011-12-04', '2011-12-11', '2011-12-18 ', '2011-12-25',
'2012-01-01'],

dtype='datetime64[ns]', freq='W-SUN')

Em [84]: pd.bdate_range(end=end, períodos=20)


Saída [84]:
DatetimeIndex (['2011-12-05', '2011-12-06', '2011-12-07', '2011-12-08', '2011-12-09', '2011
-12-12', '2011-12-13', '2011-12-14', '2011-12-15', '2011-12-16', '2011-12-19',
'2011-12 -20', '2011-12-21', '2011-12-22', '2011-12-23', '2011-12-26',
'2011-12-27', '2011-12-28 ', '2011-12-29', '2011-12-30'],

dtype='datetime64[ns]',freq='B')

Em [85]: pd.bdate_range(início=início, períodos=20)


Saída [85]:
DatetimeIndex (['2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06', '2011-01-07', '2011
-01-10', '2011-01-11', '2011-01-12', '2011-01-13', '2011-01-14', '2011-01-17',
'2011-01 -18', '2011-01-19', '2011-01-20', '2011-01-21', '2011-01-24',
'2011-01-25', '2011-01-26 ', '2011-01-27', '2011-01-28'],

dtype='datetime64[ns]',freq='B')

A especificação de início, fim e períodos gerará um intervalo de datas com espaçamento uniforme do início ao fim, inclusive,
com períodos e números de elementos no DatetimeIndex resultante:

Em [86]: pd.date_range("2018-01-01", "2018-01-05", períodos=5)


Saída [86]:
DatetimeIndex (['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',
'2018-01-05'],
dtype='datetime64[ns]', freq=Nenhum)

Em [87]: pd.date_range("2018-01-01", "2018-01-05", períodos = 10)


Saída [87]:
DatetimeIndex (['2018-01-01 00:00:00', '2018-01-01 10:40:00', '2018-01-01
21:20:00', '2018- 01-02 08:00:00', '2018-01-02 18:40:00',
'2018-01-03 05:20:00', '2018-01-03 16:00:00', ' 04/01/2018
02:40:00', '04/01/2018 13:20:00', '05/01/2018 00:00:00'],

dtype='datetime64[ns]',freq=Nenhum)

850 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Faixas de frequência personalizadas

bdate_range também pode gerar um intervalo de datas de frequência personalizadas usando os parâmetros weekmask e feriados.
Esses parâmetros só serão usados se uma sequência de frequência personalizada for passada.

Em [88]: máscara da semana = "Seg Qua Sex"

Em [89]: feriados = [datetime.datetime(2011, 1, 5), datetime.datetime(2011, 3, 14)]

Em [90]: pd.bdate_range(início, fim, freq="C", máscara semanal=máscara semanal, feriados=feriados)


Saída [90]:
DatetimeIndex (['2011-01-03', '2011-01-07', '2011-01-10', '2011-01-12', '2011-01-14', '2011 -01-17',
'2011-01-19', '2011-01-21', '2011-01-24', '2011-01-26',

...
'2011-12-09', '2011-12-12', '2011-12-14', '2011-12-16', '2011-12-19', '2011-12-21',
'2011 -12-23', '2011-12-26', '2011-12-28', '2011-12-30'], dtype='datetime64[ns]',
comprimento=154, freq='C')

Em [91]: pd.bdate_range(início, fim, freq="CBMS", máscara semanal=máscara semanal)


Saída [91]:
DatetimeIndex (['2011-01-03', '2011-02-02', '2011-03-02', '2011-04-01', '2011-05-02', '2011 -06-01',
'2011-07-01', '2011-08-01', '2011-09-02', '2011-10-03', '2011-11-02', '2011-12 -02'],

dtype='datetime64[ns]', freq='CBMS')

Veja também:

Dias úteis personalizados

2.20.5 Limitações de carimbo de data/hora

Como o pandas representa carimbos de data/hora em resolução de nanossegundos, o intervalo de tempo que pode ser representado usando um número
inteiro de 64 bits é limitado a aproximadamente 584 anos:

In [92]: pd.Timestamp.min Out[92]:


Timestamp('1677-09-21 00:12:43.145224193')

Em [93]: pd.Timestamp.max Out[93]:


Timestamp('2262-04-11 23:47:16.854775807')

Veja também:

Representando períodos fora dos limites

2.20. Funcionalidade de série temporal/data 851


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.20.6 Indexação

Um dos principais usos do DatetimeIndex é como índice para objetos pandas. A classe DatetimeIndex contém muitas otimizações relacionadas
a séries temporais:

• Uma grande variedade de datas para vários deslocamentos são pré-calculadas e armazenadas em cache para tornar a geração
intervalos de datas subsequentes muito rápido (basta pegar uma fatia).

• Mudança rápida usando o método shift em objetos pandas.

• A união de objetos DatetimeIndex sobrepostos com a mesma frequência é muito rápida (importante para dados rápidos
alinhamento).

• Acesso rápido aos campos de data através de propriedades como ano, mês, etc.

• Funções de regularização como snap e lógica muito rápida.

Os objetos DatetimeIndex têm todas as funcionalidades básicas dos objetos Index regulares e uma miscelânea de métodos avançados
específicos de séries temporais para fácil processamento de frequência.

Veja também:

Métodos de reindexação

Nota: Embora o pandas não force você a ter um índice de data classificado, alguns desses métodos podem ter um comportamento inesperado
ou incorreto se as datas não estiverem classificadas.

DatetimeIndex pode ser usado como um índice normal e oferece todas as suas funcionalidades inteligentes, como seleção, fatiamento, etc.

Em [94]: rng = pd.date_range(início, fim, freq="BM")

Em [95]: ts = pd.Series(np.random.randn(len(rng)), index=rng)

In [96]: ts.index Out[96]:

DatetimeIndex(['2011-01-31', '2011-02-28', '2011-03-31', '2011-04-29', '2011 -05-31', '2011-06-30', '2011-07-29',


'2011-08-31', '2011-09-30', '2011-10-31', '2011-11 -30', '30/12/2011'],

dtype='datetime64[ns]',freq='BM')

Em [97]: ts[:5].index Out[97]:

DatetimeIndex(['2011-01-31', '2011-02-28', '2011-03-31', '2011-04-29 ',


'31/05/2011'],
dtype='datetime64[ns]', freq='BM')

Em [98]: ts[::2].index Out[98]:

DatetimeIndex(['2011-01-31', '2011-03-31', '2011-05-31', '2011-07- 29', '30/09/2011', '30/11/2011'],


dtype='datetime64[ns]', freq='2BM')

852 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Indexação parcial de strings

Datas e strings analisadas para carimbos de data/hora podem ser passadas como parâmetros de indexação:

Em [99]: ts["31/01/2011"]
Fora[99]: 0,11920871129693428

Em [100]: ts[datetime.datetime(2011, 12, 25):]


Fora[100]:
30/12/2011 0,56702
Freq: BM, tipo d: float64

Em [101]: ts["31/10/2011":"31/12/2011"]
Fora[101]:
31/10/2011 0,271860
30/11/2011 -0,424972
30/12/2011 0,567020
Freq: BM, tipo d: float64

Para facilitar o acesso a séries temporais mais longas, você também pode passar o ano ou o ano e o mês como strings:

Em [102]: ts["2011"]
Fora[102]:
31/01/2011 0,119209
28/02/2011 -1.044236
31/03/2011 -0,861849
29/04/2011 -2.104569
31/05/2011 -0,494929
30/06/2011 1.071804
29/07/2011 0,721555
31/08/2011 -0,706771
30/09/2011 -1,039575
31/10/2011 0,271860
30/11/2011 -0,424972
30/12/2011 0,567020
Freq: BM, tipo d: float64

Em [103]: ts["2011-6"]
Fora[103]:
30/06/2011 1.071804
Freq: BM, tipo d: float64

Este tipo de fatiamento também funcionará em um DataFrame com DatetimeIndex. Como a seleção parcial de strings é uma
forma de fatiamento de rótulo, os pontos finais serão incluídos. Isso incluiria horários correspondentes em uma data incluída:

Aviso: a indexação de linhas do DataFrame com uma única string com getitem (por exemplo, frame[dtstring]) está obsoleta
começando com pandas 1.2.0 (dada a ambigüidade se está indexando as linhas ou selecionando uma coluna) e será
removido em uma versão futura. O equivalente com .loc (por exemplo, frame.loc[dtstring]) ainda é suportado.

Em [104]: dft = pd.DataFrame(


.....: np.random.randn(100000, 1),
.....: colunas=["A"],
(continua na próxima página)

2.20. Funcionalidade de série temporal/data 853


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

.....: index=pd.date_range("20130101", períodos=100000, freq="T"),


..... :)
.....:

Em [105]: dft
Fora[105]:
A
01/01/2013 00:00:00 0,276232
01-01-2013 00:01:00 -1.087401
01-01-2013 00:02:00 -0,673690
01/01/2013 00:03:00 0,113648 01/01/2013
00:04:00 -1,478427
... ...
2013-03-11 10:35:00 -0.747967 2013-03-11
10:36:00 -0.034523 2013-03-11 10:37:00
-0.201754 2013-03-11 10:38:00 -1.509067
20134 03-11 10:39:00 -1.693043

[100.000 linhas x 1 coluna]

Em [106]: dft.loc["2013"]
Fora[106]:
A
01/01/2013 00:00:00 0,276232
01-01-2013 00:01:00 -1.087401
01-01-2013 00:02:00 -0,673690
01/01/2013 00:03:00 0,113648
01-01-2013 00:04:00 -1.478427
... ...
11/03/2013 10:35:00 -0,747967
11/03/2013 10:36:00 -0,034523
11/03/2013 10:37:00 -0,201754
11/03/2013 10:38:00 -1,509067 11/03/2013
10:39:00 -1,693043

[100.000 linhas x 1 coluna]

Isso começa na primeira vez no mês e inclui a última data e hora do mês:

Em [107]: dft["2013-1":"2013-2"]
Fora[107]:
A
01/01/2013 00:00:00 0,276232
01-01-2013 00:01:00 -1.087401
01-01-2013 00:02:00 -0,673690
01/01/2013 00:03:00 0,113648
01-01-2013 00:04:00 -1.478427
... ...
28/02/2013 23:55:00 0,850929
28/02/2013 23:56:00 0,976712
28/02/2013 23:57:00 -2.693884
(continua na próxima página)

854 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

28/02/2013 23:58:00 -1,575535


28/02/2013 23:59:00 -1.573517

[84.960 linhas x 1 coluna]

Isso especifica um horário de parada que inclui todos os horários do último dia:

Em [108]: dft["2013-1":"2013-2-28"]
Fora[108]:
A
2013-01-01 00:00:00 0,276232 2013-01-01
00:01:00 -1,087401 2013-01-01 00:02:00
-0,673690 2013-01-01 00:03:00 0,113648
2013- 01- 01 00:04:00 -1,478427

... ...
2013-02-28 23:55:00 0,850929 2013-02-28
23:56:00 0,976712 2013-02-28 23:57:00
-2,693884 2013-02-28 23:58:00 -1,575535
2013- 02- 28 23:59:00 -1,573517

[84.960 linhas x 1 coluna]

Isso especifica um horário de parada exato (e não é igual ao acima):

Em [109]: dft["2013-1":"2013-2-28 00:00:00"]


Fora[109]:
A
01/01/2013 00:00:00 0,276232
01-01-2013 00:01:00 -1.087401
01-01-2013 00:02:00 -0,673690
01/01/2013 00:03:00 0,113648
01-01-2013 00:04:00 -1.478427
... ...
2013-02-27 23:56:00 1,197749 2013-02-27
23:57:00 0,720521 2013-02-27 23:58:00
-0,072718 2013-02-27 23:59:00 -0,681192
2013- 02- 28 00:00:00 -0,557501

[83521 linhas x 1 coluna]

Paramos no endpoint incluído, pois ele faz parte do índice:

Em [110]: dft["2013-1-15":"2013-1-15 12:30:00"]


Fora[110]:
A
15/01/2013 00:00:00 -0,984810
15/01/2013 00:01:00 0,941451
15/01/2013 00:02:00 1.559365
15/01/2013 00:03:00 1.034374
15/01/2013 00:04:00 -1.480656
(continua na próxima página)

2.20. Funcionalidade de série temporal/data 855


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

... ...
15/01/2013 12:26:00 0,371454
15/01/2013 12:27:00 -0,930806
15/01/2013 12:28:00 -0,069177
15/01/2013 12:29:00 0,066510
15/01/2013 12:30:00 -0,003945

[751 linhas x 1 coluna]

A indexação parcial de strings DatetimeIndex também funciona em um DataFrame com um MultiIndex:

Em [111]: dft2 = pd.DataFrame(


.....: np.random.randn(20, 1),
.....: colunas=["A"],
.....: índice=pd.MultiIndex.from_product(
.....: [pd.date_range("20130101", períodos=10, freq="12H"), ["a", "b"]]
.....: ),
..... :)
.....:

Em [112]: dft2
Fora[112]:
A
01/01/2013 00:00:00 a -0,298694
b0,823553
01/01/2013 12:00:00 a 0,943285
b-1,479399
02/01/2013 00:00:00 a -1.643342
... ...
04/01/2013 12:00:00 b 0,069036 05/01/2013
00:00:00 a 0,122297 b 1,422060 05/01/2013
12:00:00 a
0,370079 b 1,016331

[20 linhas x 1 coluna]

Em [113]: dft2.loc["05/01/2013"]
Fora[113]:
A
05/01/2013 00:00:00 a 0,122297
b 1,422060
05-01-2013 12:00:00 a 0,370079
b 1,016331

Em [114]: idx = pd.IndexSlice

Em [115]: dft2 = dft2.swaplevel(0, 1).sort_index()

Em [116]: dft2.loc[idx[:, "2013-01-05"], :]


Fora[116]:
A
(continua na próxima página)

856 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

a 05/01/2013 00:00:00 0,122297


05/01/2013 12:00:00 0,370079
b 05-01-2013 00:00:00 1.422060
05-01-2013 12:00:00 1.016331

Novo na versão 0.25.0.

O fatiamento com indexação de string também respeita o deslocamento UTC.

Em [117]: df = pd.DataFrame([0], index=pd.DatetimeIndex(["2019-01-01"], tz="US/Pacific"))

Em [118]: df
Fora[118]:

0 01-01-2019 00:00:00-08:00 0

Em [119]: df["2019-01-01 12:00:00+04:00":"2019-01-01 13:00:00+04:00"]


Fora[119]:
0
01-01-2019 00:00:00-08:00 0

Fatia vs. correspondência exata

A mesma string usada como parâmetro de indexação pode ser tratada como uma fatia ou como uma correspondência exata, dependendo
da resolução do índice. Se a string for menos precisa que o índice, ela será tratada como uma fatia, caso contrário, como uma
correspondência exata.

Considere um objeto Series com um índice de resolução de minutos:

Em [120]: série_minuto = pd.Series(


.....: [1, 2, 3],
.....: pd.DatetimeIndex( ["31/12/2011
.....: 23:59:00", "01/01/2012 00:00:00", "01/01/2012 00:02:00 "]
.....: ),
..... :)
.....:

In [121]: series_minuto.index.resolution Out[121]: 'minuto'

Uma string de carimbo de data/hora com menos precisão que um minuto fornece um objeto Series.

Em [122]: série_minuto["2011-12-31 23"]


Saída[122]:
31/12/2011 23:59:00 1
tipo d: int64

Uma string de carimbo de data/hora com resolução de minutos (ou mais precisa) fornece um escalar, ou seja, não é convertido em uma fatia.

Em [123]: minuto_série["31/12/2011 23:59"]


Fora[123]: 1

(continua na próxima página)

2.20. Funcionalidade de série temporal/data 857


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [124]: minuto_série["2011-12-31 23:59:00"]


Fora[124]: 1

Se a resolução do índice for a segunda, o carimbo de data/hora com precisão de minuto fornecerá uma série.

Em [125]: series_second = pd.Series(


.....: [1, 2, 3],
.....:
.....: pd.DatetimeIndex( ["31/12/2011 23:59:59", "01/01/2012 00:00:00", "01/01/2012 00:00:01 "]
.....: ),
..... :)
.....:

In [126]: series_second.index.resolution Out[126]:


'second'

Em [127]: series_second["31/12/2011 23:59"]


Saída [127]:
31/12/2011 23:59:59 1
dtype: int64

Se a string do carimbo de data/hora for tratada como uma fatia, ela também poderá ser usada para indexar DataFrame com .loc[].

Em [128]: dft_minuto = pd.DataFrame(


.....: {"a": [1, 2, 3], "b": [4, 5, 6]}, índice=série_minuto.index
..... :)
.....:

Em [129]: dft_minuto.loc["31/12/2011 23"]


Fora[129]:
ab
31/12/2011 23:59:00 1 4

Aviso: No entanto, se a string for tratada como uma correspondência exata, a seleção em [] do DataFrame será
em colunas e não em linhas, consulte Noções básicas de indexação. Por exemplo, dft_minuto['2011-12-31 23:59']
gerará KeyError, pois '2012-12-31 23:59' tem a mesma resolução do índice e não há coluna com esse nome:

Para sempre ter uma seleção inequívoca, seja a linha tratada como uma fatia ou como uma seleção única, use .loc.

Em [130]: dft_minuto.loc["31/12/2011 23:59"]


Fora[130]:
a 1
b 4
Nome: 31/12/2011 23:59:00, dtype: int64

Observe também que a resolução DatetimeIndex não pode ser menos precisa que dia.

Em [131]: series_monthly = pd.Series(


.....: [1, 2, 3], pd.DatetimeIndex(["2011-12", "2012-01", "2012-02"])
..... :)
.....:
(continua na próxima página)

858 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

In [132]: series_monthly.index.resolution Out[132]: 'dia'

Em [133]: series_monthly["2011-12"] # retorna Série


Fora[133]:
01-12-2011 1
tipo d: int64

Indexação exata

Conforme discutido na seção anterior, a indexação de um DatetimeIndex com uma string parcial depende da “precisão”
do período, ou seja, quão específico é o intervalo em relação à resolução do índice. Por outro lado, a indexação com
objetos Timestamp ou datetime é exata, porque os objetos têm significado exato. Eles também seguem a semântica de
incluir ambos os terminais.

Esses objetos Timestamp e datetime têm horas, minutos e segundos exatos, mesmo que não tenham sido
especificados explicitamente (são 0).

Em [134]: dft[datetime.datetime(2013, 1, 1): datetime.datetime(2013, 2, 28)]


Fora[134]:
A
01/01/2013 00:00:00 0,276232
01-01-2013 00:01:00 -1.087401
01-01-2013 00:02:00 -0,673690
01/01/2013 00:03:00 0,113648
01-01-2013 00:04:00 -1.478427
... ...
2013-02-27 23:56:00 1,197749 2013-02-27
23:57:00 0,720521 2013-02-27 23:58:00
-0,072718 2013-02-27 23:59:00 -0,681192
2013- 02- 28 00:00:00 -0,557501

[83521 linhas x 1 coluna]

Sem padrões.

Em [135]:
.....: dft[ datetime.datetime(2013, 1, 1, 10, 12, 0): datetime.datetime( 2013, 2, 28, 10, 12, 0
.....:
.....: )
.....: ]
.....:
Fora[135]:
A
01/01/2013 10:12:00 0,565375
01/01/2013 10:13:00 0,068184
01/01/2013 10:14:00 0,788871
01/01/2013 10:15:00 -0,280343 01/01/2013
10:16:00 0,931536
... ...
(continua na próxima página)

2.20. Funcionalidade de série temporal/data 859


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


28/02/2013 10:08:00 0,148098
28/02/2013 10:09:00 -0,388138
28/02/2013 10:10:00 0,139348
28/02/2013 10:11:00 0,085288
28/02/2013 10:12:00 0,950146

[83521 linhas x 1 coluna]

Truncamento e indexação sofisticada

É fornecida uma função de conveniência truncate() que é semelhante ao fatiamento. Observe que truncar assume um valor 0 para qualquer
componente de data não especificado em um DatetimeIndex em contraste com o fatiamento que retorna quaisquer datas parcialmente correspondentes:

Em [136]: rng2 = pd.date_range("2011-01-01", "2012-01-01", freq="W")

Em [137]: ts2 = pd.Series(np.random.randn(len(rng2)), index=rng2)

Em [138]: ts2.truncate(before="2011-11", after="2011-12")


Saída [138]:
06/11/2011 0,437823 13/11/2011
-0,293083 20/11/2011 -0,059881
27/11/2011 1,252450 Freq: W-
SUN, dtype: float64

Em [139]: ts2["2011-11":"2011-12"]
Saída[139]:
06/11/2011 0,437823
13/11/2011 -0,293083
20/11/2011 -0,059881
27/11/2011 1,252450
04/12/2011 0,046611
11/12/2011 0,059478
18/12/2011 -0,286539
25/12/2011 0,841669
Freq: W-SUN, tipo d: float64

Mesmo uma indexação sofisticada e complicada que quebra a regularidade de frequência do DatetimeIndex resultará em um
DatetimeIndex, embora a frequência seja perdida:

Em [140]: ts2[[0, 2, 6]].index Out[140]:


DatetimeIndex(['2011-01-02', '2011-01-16', '2011-02-13'], dtype='datetime64[ns] ÿÿ', freq=Nenhum)

860 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.20.7 Componentes de hora/data

Existem várias propriedades de hora/data que podem ser acessadas a partir do Timestamp ou de uma coleção de carimbos de data/hora, como um
Índice de data e hora.

Propriedade Descrição
ano O ano da data e hora
mês O mês da data e hora
dia Os dias da data e hora
hora A hora da data e hora
minuto Os minutos da data e hora
segundo Os segundos da data e hora
data em Os microssegundos da data e hora
microssegundos Os nanossegundos da data e hora
em nanossegundos Retorna datetime.date (não contém informações de fuso horário)
tempo Retorna datetime.time (não contém informações de fuso horário)
horário Retorna datetime.time como hora local com informações de fuso horário
dia do ano O dia normal do ano
dia_do_ano O dia normal do ano
semana do O ordinal da semana do ano
ano O ordinal da semana do ano
semana dia O número do dia da semana com segunda=0, domingo=6
da semana O número do dia da semana com segunda=0, domingo=6
O número do dia da semana com segunda=0, domingo=6
Trimestre da data: janeiro-março = 1, abril-junho = 2, etc.
dia_da_semana O número de dias no mês da data e hora
dia da semana Indicação lógica se for primeiro dia do mês (definido por frequência)
trimestre Indicação lógica se for último dia do mês (definido por frequência)
dias_no_mês Indicação lógica se for primeiro dia do trimestre (definido por frequência)
é_mês_início Indicação lógica se for último dia do trimestre (definido por frequência)
é_mês_fim Indicação lógica se for primeiro dia do ano (definido por frequência)
é_quarto_início Indicação lógica se for último dia do ano (definido por frequência)
é_quarto_fim é_ano_inícioIndicação
é_ano_fimlógica
é_anosebissexto
a data pertence a um ano bissexto

Além disso, se você tiver uma série com valores semelhantes a data e hora, poderá acessar essas propriedades por meio do acessador .dt,
conforme detalhado na seção sobre acessadores .dt.

Novo na versão 1.1.0.

Você pode obter os componentes de ano, semana e dia do ano ISO da norma ISO 8601:

Em [141]: idx = pd.date_range(start="2019-12-29", freq="D", períodos=4)

Em [142]: idx.isocalendar()
Fora[142]:
ano dia da semana
2019-12-29 2019 7 52

30/12/2019 2020 1 1

31/12/2019 2020 2 1

2020-01-01 2020 3 1

Em [143]: idx.to_series().dt.isocalendar()
Fora[143]:
(continua na próxima página)

2.20. Funcionalidade de série temporal/data 861


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

ano dia da semana


2019-12-29 2019 7 52
30/12/2019 2020 1 1
31-12-2019 2020 1 2
2020-01-01 2020 1 3

2.20.8 Objetos DateOffset

Nos exemplos anteriores, sequências de frequência (por exemplo, 'D') foram usadas para especificar uma frequência que definia:

• como as datas e horas em DatetimeIndex foram espaçadas ao usar date_range()

• a frequência de um Período ou PeriodIndex

Essas sequências de frequência são mapeadas para um objeto DateOffset e suas subclasses. Um DateOffset é semelhante a um Timedelta que
representa uma duração de tempo, mas segue regras específicas de duração do calendário. Por exemplo, um dia Timedelta sempre
incrementará os horários em 24 horas, enquanto um dia DateOffset aumentará os horários para o mesmo horário no dia seguinte
se um dia representa 23, 24 ou 25 horas devido ao horário de verão. No entanto, todas as subclasses DateOffset que são
uma hora ou menos (Hora, Minuto, Segundo, Mili, Micro, Nano) comportam-se como Timedelta e respeitam o tempo absoluto.

O DateOffset básico atua de forma semelhante a dateutil.relativedelta (documentação relativadelta) que muda uma data
tempo pela duração do calendário correspondente especificada. O operador aritmético (+) pode ser usado para realizar a mudança.

# Este dia específico contém uma transição para o horário de verão


Em [144]: ts = pd.Timestamp("2016-10-30 00:00:00", tz="Europa/Helsínquia")

# Respeita o tempo absoluto


Em [145]: ts + pd.Timedelta(dias=1)
Saída[145]: Timestamp('2016-10-30 23:00:00+0200', tz='Europa/Helsínquia')

# Respeita o horário do calendário


Em [146]: ts + pd.DateOffset(dias=1)
Saída[146]: Timestamp('2016-10-31 00:00:00+0200', tz='Europa/Helsínquia')

Em [147]: sexta-feira = pd.Timestamp("2018-01-05")

Em [148]: sexta-feira.nome_dia()
Saiu[148]: 'Sexta-feira'

# Adicione 2 dias úteis (sexta-feira -> terça-feira)


Em [149]: dois_dias_comerciais = 2 * pd.offsets.BDay()

Em [150]: sexta-feira + dois dias úteis


Saída[150]: carimbo de data/hora('2018-01-09 00:00:00')

Em [151]: (sexta-feira + dois_dias_comerciais).day_name()


Saída[151]: 'Terça-feira'

A maioria dos DateOffsets possui strings de frequências associadas, ou aliases de deslocamento, que podem ser passados para argumentos de palavras-chave
freq. As compensações de data disponíveis e as sequências de frequência associadas podem ser encontradas abaixo:

862 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Compensação de data Frequência Descrição


Corda
DataOffset Nenhum Classe de compensação genérica, padrão para 24 horas absolutas
Aniversário ou 'B' dia útil (dia útil)
Dia de negócios
Dia CD ou 'C' dia útil personalizado
CustomBusinessDay
Semana 'C' uma semana, opcionalmente ancorado em um dia da semana
WeekOfMonth 'WOM' o x-ésimo dia da y-ésima semana de cada mês
LastWeekOfMonth'LWOM' o x-ésimo dia da última semana de cada mês
Fim do mês 'M' fim do mês calendário
Início do mês 'EM' início do mês civil
BMonthEnd ou 'BM' fim do mês comercial
Fim do mês comercial
BMonthBegin 'BMS' início do mês comercial
ou
BusinessMonthBegin
CBMêsFim 'CBM' final do mês comercial personalizado
ou
CustomBusinessMonthEnd
CBMonthBegin 'CBMS' início do mês comercial personalizado
ou
CustomBusinessMonthBegin
SemiMonthEnd 'SM' 15 (ou outro dia_do_mês) e final do mês civil
SemiMonthBegin'SMS' 15 (ou outro dia_do_mês) e início do mês civil
Fim do trimestre Fim do trimestre calendário 'Q'
Início do trimestre do calendário QuarterBegin 'QS'
BQuarterEnd 'Final do trimestre de negócios BQ
BQuarterBegin 'BQS' trimestre de negócios começa
FY5253Quarter 'REQ' varejo (também conhecido como 52-53 semanas) trimestre
Fim de ano 'A' final do ano civil
Início do ano Início do ano civil 'AS' ou 'BYS'
BYearEnd Fim do ano comercial 'BA'
BYearBegin Início do ano comercial 'BAS'
EF5253 'RÉ' varejo (também conhecido como 52-53 semanas) ano

Páscoa Nenhum Feriado da Páscoa


Horário comercial 'BH' hora de negócios
CustomBusinessHour 'CBH' horário comercial personalizado

Dia 'D' um dia absoluto


Hora 'H' uma hora
Minuto 'T' ou 'min' um minuto
Segundo 'S' um segundo
Mili 'L' ou 'ms' um milissegundo
Micro 'U' ou 'nós' um microssegundo
Nano 'N' um nanossegundo

DateOffsets também possuem métodos rollforward() e rollback() para avançar ou retroceder uma data
respectivamente, para uma data de compensação válida relativa à compensação. Por exemplo, as compensações comerciais rolarão datas que chegarão ao
fins de semana (sábado e domingo) para segunda-feira, uma vez que as compensações comerciais operam durante a semana.

Em [152]: ts = pd.Timestamp("2018-01-06 00:00:00")

(continua na próxima página)

2.20. Funcionalidade de série temporal/data 863


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [153]: ts.day_name()
Fora[153]: 'Sábado'

# As datas de compensação válidas do BusinessHour são de segunda a sexta-feira. In


[154]: offset = pd.offsets.BusinessHour(start="09:00")

# Traga a data para a data de compensação mais próxima (segunda-feira)


Em [155]: offset.rollforward(ts)
Saída[155]: Carimbo de data/hora('2018-01-08 09:00:00')

# A data é trazida primeiro para a data de deslocamento mais próxima e depois a hora é adicionada
Em [156]: ts + deslocamento
Saída[156]: Carimbo de data/hora('2018-01-08 10:00:00')

Essas operações preservam informações de tempo (hora, minuto, etc.) por padrão. Para redefinir o horário para meia-noite, use
normalize() antes ou depois de aplicar a operação (dependendo se você deseja que as informações de horário sejam incluídas na operação).

Em [157]: ts = pd.Timestamp("01/01/2014 09:00")

Em [158]: dia = pd.offsets.Day()

Em [159]: dia + ts
Saída[159]: Carimbo de data/hora('2014-01-02 09:00:00')

Em [160]: (dia + ts).normalize()


Saída[160]: Carimbo de data/hora('2014-01-02 00:00:00')

Em [161]: ts = pd.Timestamp("01/01/2014 22:00")

Em [162]: hora = pd.offsets.Hour()

Em [163]: hora + ts
Saída[163]: Carimbo de data/hora('2014-01-01 23:00:00')

Em [164]: (hora + ts).normalize()


Saída[164]: Carimbo de data/hora('2014-01-01 00:00:00')

Em [165]: (hora + pd.Timestamp("01/01/2014 23:30")).normalize()


Saída[165]: Carimbo de data/hora('2014-01-02 00:00:00')

Deslocamentos paramétricos

Alguns dos deslocamentos podem ser “parametrizados” quando criados para resultar em comportamentos diferentes. Por exemplo, o
deslocamento semanal para gerar dados semanais aceita um parâmetro de dia da semana que resulta nas datas geradas sempre em
um determinado dia da semana:

Em [166]: d = datetime.datetime(2008, 8, 18, 9, 0)

Entrada [167]:
d Saída [167]: datetime.datetime(2008, 8, 18, 9, 0)

(continua na próxima página)

864 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [168]: d + pd.offsets.Week()
Saída[168]: Carimbo de data/hora('2008-08-25 09:00:00')

Em [169]: d + pd.offsets.Week(dia da semana=4)


Saída[169]: Carimbo de data/hora('2008-08-22 09:00:00')

Em [170]: (d + pd.offsets.Week(weekday=4)).weekday()
Fora[170]: 4

Em [171]: d - pd.offsets.Week()
Saída[171]: Carimbo de data/hora('2008-08-11 09:00:00')

A opção normalizar será eficaz para adição e subtração.

Em [172]: d + pd.offsets.Week(normalize=True)
Saída[172]: Carimbo de data/hora('2008-08-25 00:00:00')

Em [173]: d - pd.offsets.Week(normalize=True)
Saída[173]: Carimbo de data/hora('2008-08-11 00:00:00')

Outro exemplo é parametrizar YearEnd com o mês final específico:

Em [174]: d + pd.offsets.YearEnd()
Saída[174]: Carimbo de data/hora('2008-12-31 09:00:00')

Em [175]: d + pd.offsets.YearEnd(mês=6)
Saída[175]: Carimbo de data/hora('2009-06-30 09:00:00')

Usando deslocamentos com Series / DatetimeIndex

Os deslocamentos podem ser usados com Series ou DatetimeIndex para aplicar o deslocamento a cada elemento.

Em [176]: rng = pd.date_range("2012-01-01", "2012-01-03")

Em [177]: s = pd.Series(rng)

Em [178]: anel
Out[178]: DatetimeIndex(['2012-01-01', '2012-01-02', '2012-01-03'], dtype='datetime64[ns] ÿÿ', freq='D')

Em [179]: rng + pd.DateOffset(meses=2)


Out[179]: DatetimeIndex(['2012-03-01', '2012-03-02', '2012-03-03'], dtype='datetime64[ns] ÿÿ', freq=None)

Em [180]: s + pd.DateOffset(meses=2)
Fora[180]:
0 01/03/2012
12012-03-02
2012-03-03
tipo d: datahora64[ns]

(continua na próxima página)

2.20. Funcionalidade de série temporal/data 865


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [181]: s - pd.DateOffset(meses=2)
Fora[181]:
0 01-11-2011
12011-11-02
2 03/11/2011
tipo d: datahora64[ns]

Se a classe de deslocamento for mapeada diretamente para um Timedelta (Dia, Hora, Minuto, Segundo, Micro, Mili, Nano), ela poderá ser usada
exatamente como um Timedelta - consulte a seção Timedelta para obter mais exemplos.

Em [182]: s - pd.offsets.Day(2)
Fora[182]:
0 30/12/2011
131-12-2011
2012-01-01
tipo d: datahora64[ns]

Em [183]: td = s - pd.Series(pd.date_range("2011-12-29", "2011-12-31"))

Em [184]: td
Saída[184]:
0 3 dias 1 3
dias 2 3 dias
dtype:
timedelta64[ns]

Em [185]: td + pd.offsets.Minute(15)
Saída[185]:
0 3 dias 00:15:00 3 dias
1 00:15:00 3 dias
2 00:15:00 dtype:
timedelta64[ns]

Observe que alguns deslocamentos (como BQuarterEnd) não possuem uma implementação vetorizada. Eles ainda podem ser usados, mas
podem calcular significativamente mais lentamente e mostrarão um PerformanceWarning

Em [186]: rng + pd.offsets.BQuarterEnd()


Out[186]: DatetimeIndex(['2012-03-30', '2012-03-30', '2012-03-30'], dtype='datetime64[ns] ÿÿ', freq=None)

Dias úteis personalizados

A classe CDay ou CustomBusinessDay fornece uma classe paramétrica BusinessDay que pode ser usada para criar calendários
de dias úteis personalizados que levam em conta feriados locais e convenções locais de fim de semana.

Como exemplo interessante, vejamos o Egito, onde se observa um fim de semana de sexta a sábado.

Em [187]: weekmask_egypt = "Dom Seg Ter Qua Qui"

# Eles também comemoram o Dia Internacional dos Trabalhadores, então


vamos # acrescentar isso por alguns anos
Em [188]: feriados = [
(continua na próxima página)

866 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

.....: "01/05/2012",
.....: datahora.datehora(2013, 5, 1),
.....: np.datetime64("01/05/2014"),
.....: ]
.....:

Em [189]: bday_egypt = pd.offsets.CustomBusinessDay(


.....: feriados = feriados,
.....: máscara semanal = máscara semanal_egypt,
..... :)
.....:

Em [190]: dt = datetime.datetime(2013, 4, 30)

Em [191]: dt + 2 * aniversário_egito
Saída[191]: Carimbo de data/hora('2013-05-05 00:00:00')

Vamos mapear os nomes dos dias da semana:

Em [192]: dts = pd.date_range(dt, períodos=5, freq=bday_egypt)

Em [193]: pd.Series(dts.weekday, dts).map(pd.Series("Seg Ter Qua Qui Sex Sáb Dom".


ÿÿdividir()))
Fora[193]:
30/04/2013 ter
02/05/2013 qui
05/05/2013 Sol
06/05/2013 seg
07/05/2013 ter
Freq: C, dtype: objeto

Os calendários de feriados podem ser usados para fornecer a lista de feriados. Consulte a seção do calendário de feriados para obter mais informações.

Em [194]: de pandas.tseries.holiday import USFederalHolidayCalendar

Em [195]: bday_us = pd.offsets.CustomBusinessDay(calendar=USFederalHolidayCalendar())

# Sexta-feira antes do Dia MLK


Em [196]: dt = datetime.datetime(2014, 1, 17)

# Terça-feira após o MLK Day (segunda-feira é ignorada porque é feriado)


Em [197]: dt + aniversário_us
Saída[197]: Carimbo de data/hora('2014-01-21 00:00:00')

As compensações mensais que respeitam um determinado calendário de feriados podem ser definidas da forma habitual.

Em [198]: bmth_us = pd.offsets.


ÿÿCustomBusinessMonthBegin(calendar=USFederalHolidayCalendar())

# Pular ano novo


Em [199]: dt = datetime.datetime(2013, 12, 17)

Em [200]: dt + bmth_us
(continua na próxima página)

2.20. Funcionalidade de série temporal/data 867


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Saída[200]: carimbo de data/hora('2014-01-02 00:00:00')

# Defina o índice de data com deslocamento personalizado


em [201]: pd.date_range(start="20100101", end="20120101", freq=bmth_us)
Saída[201]:
DatetimeIndex(['2010-01-04', '2010-02-01', '2010-03-01', '2010-04-01', '2010-05-03', '2010 -06-01',
'2010-07-01', '2010-08-02', '2010-09-01', '2010-10-01', '2010-11-01', '2010-12 -01',
'2011-01-03', '2011-02-01', '2011-03-01', '2011-04-01', '2011-05-02', '2011-06-01 ',
'2011-07-01', '2011-08-01', '2011-09-01', '2011-10-03', '2011-11-01', '2011-12-01'] ,

dtype='datetime64[ns]', freq='CBMS')

Observação: a sequência de frequência 'C' é usada para indicar que um CustomBusinessDay DateOffset é usado. É importante
observar que, como CustomBusinessDay é um tipo parametrizado, as instâncias de CustomBusinessDay podem ser diferentes e isso
não é detectável na sequência de frequência 'C'. O usuário, portanto, precisa garantir que a sequência de frequência 'C' seja usada
consistentemente na aplicação do usuário.

Hora de negócios

A classe BusinessHour fornece uma representação do horário comercial no BusinessDay, permitindo utilizar horários de início e término
específicos.

Por padrão, o BusinessHour usa das 9h às 17h como horário comercial. Adicionar BusinessHour aumentará o Timestamp por frequência
horária. Se o carimbo de data/hora de destino estiver fora do horário comercial, vá para o próximo horário comercial e aumente-o.
Caso o resultado ultrapasse o término do horário comercial, as horas restantes serão somadas ao próximo dia útil.

Em [202]: bh = pd.offsets.BusinessHour()

Em [203]: bh
Saída[203]: <Horário Comercial: BH=09h00-17h00>

# 01/08/2014 é sexta-feira em
[204]: pd.Timestamp("01/08/2014 10:00").weekday()
Fora[204]: 4

In [205]: pd.Timestamp("2014-08-01 10:00") + bh Out[205]:


Timestamp('2014-08-01 11:00:00')

# O exemplo abaixo é igual a: pd.Timestamp('2014-08-01 09:00') + bh In [206]: pd.Timestamp("2014-08-01


08:00") + bh Out[206 ]: Carimbo de data e hora ('2014-08-01 10:00:00')

# Se o resultado estiver no horário de término, passa para o próximo dia útil In [207]:
pd.Timestamp("2014-08-01 16:00") + bh Out[207]: Timestamp('2014-08-
04 09:00:00')

# Os restantes são adicionados ao dia seguinte In [208]:


pd.Timestamp("2014-08-01 16:30") + bh Out[208]: Timestamp('2014-08-04
09:30:00')
(continua na próxima página)

868 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

# Adicionando 2 horários comerciais


em [209]: pd.Timestamp("2014-08-01 10:00") + pd.offsets.BusinessHour(2)
Saída[209]: Carimbo de data/hora('2014-08-01 12:00:00')

# Subtraindo 3 horas úteis em [210]:


pd.Timestamp("2014-08-01 10:00") + pd.offsets.BusinessHour(-3)
Saída[210]: Carimbo de data/hora('2014-07-31 15:00:00')

Você também pode especificar o horário de início e término por palavras-chave. O argumento deve ser uma str com uma representação
hora:minuto ou uma instância datetime.time. Especificar segundos, microssegundos e nanossegundos como horário comercial resulta
em ValueError.

Em [211]: bh = pd.offsets.BusinessHour(start="11:00", end=datetime.time(20, 0))

Em [212]: bh
Saída[212]: <Horário Comercial: BH=11h00-20h00>

In [213]: pd.Timestamp("2014-08-01 13:00") + bh Out[213]:


Timestamp('2014-08-01 14:00:00')

In [214]: pd.Timestamp("2014-08-01 09:00") + bh Out[214]:


Timestamp('2014-08-01 12:00:00')

In [215]: pd.Timestamp("2014-08-01 18:00") + bh Out[215]:


Timestamp('2014-08-01 19:00:00')

Passar o horário de início depois do final representa meia-noite no horário comercial. Nesse caso, o horário comercial ultrapassa a meia-
noite e se sobrepõe ao dia seguinte. O horário comercial válido é diferenciado pelo fato de ter começado em um BusinessDay válido.

Em [216]: bh = pd.offsets.BusinessHour(start="17:00", end="09:00")

Em [217]: bh
Saída[217]: <Horário Comercial: BH=17h00-09h00>

In [218]: pd.Timestamp("2014-08-01 17:00") + bh Out[218]:


Timestamp('2014-08-01 18:00:00')

In [219]: pd.Timestamp("2014-08-01 23:00") + bh Out[219]:


Timestamp('2014-08-02 00:00:00')

# Embora 02/08/2014 seja sábado, # é válido


porque começa em 01/08 (sexta-feira).
In [220]: pd.Timestamp("2014-08-02 04:00") + bh Out[220]:
Timestamp('2014-08-02 05:00:00')

# Embora 04/08/2014 seja segunda-feira, #


está fora do horário comercial porque começa de 03/08 (domingo).
In [221]: pd.Timestamp("2014-08-04 04:00") + bh Out[221]:
Timestamp('2014-08-04 18:00:00')

Aplicar BusinessHour.rollforward e rollback para resultados fora do horário comercial no início do próximo horário comercial ou
no final do dia anterior. Diferente de outras compensações, BusinessHour.rollforward pode gerar resultados diferentes de

2.20. Funcionalidade de série temporal/data 869


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

aplicar por definição.

Isso ocorre porque o término do horário comercial de um dia é igual ao início do horário comercial do dia seguinte. Por exemplo, no horário
comercial padrão (9h00 - 17h00), não há intervalo (0 minutos) entre 01/08/2014 às 17h e 04/08/2014 às 09h.

# Isso ajusta um carimbo de data / hora para o limite do horário comercial em


[222]: pd.offsets.BusinessHour().rollback(pd.Timestamp("2014-08-02 15:00"))
Saída[222]: Carimbo de data/hora('2014-08-01 17:00:00')

Em [223]: pd.offsets.BusinessHour().rollforward(pd.Timestamp("2014-08-02 15:00"))


Saída[223]: Carimbo de data/hora('2014-08-04 09:00:00')

# É o mesmo que BusinessHour() + pd.Timestamp('2014-08-01 17:00').


# E é o mesmo que BusinessHour() + pd.Timestamp('2014-08-04 09:00')
Em [224]: pd.offsets.BusinessHour() + pd.Timestamp("02/08/2014 15:00")
Saída[224]: Carimbo de data/hora('2014-08-04 10:00:00')

# Resultados do BusinessDay (para referência)


Em [225]: pd.offsets.BusinessHour().rollforward(pd.Timestamp("2014/08/02"))
Saída[225]: Carimbo de data/hora('2014-08-04 09:00:00')

# É o mesmo que BusinessDay() + pd.Timestamp('2014-08-01')


# O resultado é o mesmo que rollworward porque BusinessDay nunca se sobrepõe.
Em [226]: pd.offsets.BusinessHour() + pd.Timestamp("2014-08-02")
Saída[226]: Carimbo de data/hora('2014-08-04 10:00:00')

BusinessHour considera sábado e domingo feriados. Para usar feriados arbitrários, você pode usar o
deslocamento CustomBusinessHour, conforme explicado na subseção a seguir.

Horário comercial personalizado

O CustomBusinessHour é uma mistura de BusinessHour e CustomBusinessDay que permite especificar feriados arbitrários. CustomBusinessHour
funciona da mesma forma que BusinessHour, exceto que ignora feriados personalizados especificados.

Em [227]: de pandas.tseries.holiday import USFederalHolidayCalendar

Em [228]: bhour_us = pd.offsets.CustomBusinessHour(calendar=USFederalHolidayCalendar())

# Sexta-feira antes do MLK Day In


[229]: dt = datetime.datetime(2014, 1, 17, 15)

Em [230]: dt + bhour_us
Saída[230]: Carimbo de data/hora('2014-01-17 16:00:00')

# Terça-feira após o MLK Day (segunda-feira é ignorada porque é feriado)


Em [231]: dt + bhour_us * 2
Saída[231]: Carimbo de data/hora('2014-01-21 09:00:00')

Você pode usar argumentos de palavra-chave suportados por BusinessHour e CustomBusinessDay.

Em [232]: bhour_mon = pd.offsets.CustomBusinessHour(start="10:00", weekmask="Ter Qua Quiÿ ÿÿSex")

(continua na próxima página)

870 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)


# Segunda-feira é ignorada porque é feriado, o horário comercial começa a partir das 10h
Em [233]: dt + bhour_mon * 2
Saída[233]: Carimbo de data/hora('2014-01-21 10:00:00')

Aliases de deslocamento

Vários apelidos de string são fornecidos para frequências úteis de séries temporais comuns. Iremos nos referir a esses aliases como deslocamento
apelido.

Alias Descrição
B frequência do dia útil
C frequência personalizada do dia útil
D frequência do dia de calendário
C frequência semanal
M frequência de final de mês
SM frequência final semestral (15º e final do mês)
BM frequência de final do mês comercial
CBM frequência de final do mês comercial personalizada
EM frequência de início do mês
SMS frequência de início semestral (1º e 15º)
BMS frequência de início do mês comercial
CBMS frequência de início do mês comercial personalizada
P frequência de final de trimestre
churrasco frequência de final do trimestre comercial
QS frequência de início do trimestre
BQS frequência de início do trimestre comercial
UMA, S frequência de final de ano
BEBÊ frequência de final de ano comercial
COMO, SIM frequência de início do ano
Frequência de início do ano comercial BAS, BYS
frequência do horário comercial
H
Frequência horária de BH
T, min frequência minuciosa
S segunda frequência
eu, senhora milissegundos
Você, nós microssegundos
N nanossegundos

Observação:

Ao usar os aliases de deslocamento acima, deve-se observar que funções como date_range(),
bdate_range(), retornará apenas timestamps que estejam no intervalo definido por start_date e
data final. Se start_date não corresponder à frequência, os timestamps retornados começarão
no próximo carimbo de data/hora válido, o mesmo para data_final, os carimbos de data/hora retornados irão parar no carimbo de data/hora válido anterior
carimbo de data/hora.

Por exemplo, para o deslocamento MS, se start_date não for o primeiro do mês, os carimbos de data/hora retornados começarão com
primeiro dia do mês seguinte. Se end_date não for o primeiro dia de um mês, o último carimbo de data/hora retornado será o primeiro
dia do mês correspondente.

2.20. Funcionalidade de série temporal/data 871


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [234]: datas_lst_1 = pd.date_range("2020-01-06", "2020-04-03", freq="MS")

Em [235]: datas_lst_1
Out[235]: DatetimeIndex(['2020-02-01', '2020-03-01', '2020-04-01'], dtype='datetime64[ns] ÿÿ', freq='MS')

Em [236]: datas_lst_2 = pd.date_range("2020-01-01", "2020-04-01", freq="MS")

Em [237]: datas_lst_2
Saída[237]: DatetimeIndex(['2020-01-01', '2020-02-01', '2020-03-01', '2020-04-01'], dtype= ÿÿ'datetime64[ns] ',
frequência='MS')

Podemos ver no exemplo acima date_range() e bdate_range() retornará apenas os carimbos de data e hora válidos entre
start_date e end_date. Se esses carimbos de data e hora não forem válidos para a frequência especificada, ele passará para o
próximo valor de data_inicial (respectivamente anterior para data_final)

Combinando apelidos

Como vimos anteriormente, o alias e a instância offset são fungíveis na maioria das funções:

Em [238]: pd.date_range(início, períodos=5, freq="B")


Saída [238]:
DatetimeIndex (['2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06',
'2011-01-07'],
dtype='datetime64[ns]', freq='B')

Em [239]: pd.date_range(início, períodos=5, freq=pd.offsets.BDay())


Saída [239]:
DatetimeIndex (['2011-01-03', '2011-01-04', '2011-01-05', '2011-01-06',
'2011-01-07'],
dtype='datetime64[ns]', freq='B')

Você pode combinar compensações diárias e intradiárias:

Em [240]: pd.date_range(início, períodos=10, freq="2h20min")


Saída [240]:
DatetimeIndex (['2011-01-01 00:00:00', '2011-01-01 02:20:00', '2011-01-01
04:40:00', '2011- 01-01 07:00:00', '2011-01-01 09:20:00',
'2011-01-01 11:40:00', '2011-01-01 14:00:00', ' 01-01-2011
16:20:00', '01-01-2011 18:40:00', '01-01-2011 21:00:00'],
dtype='datetime64[ns]', freq= '140T')

Em [241]: pd.date_range(início, períodos=10, freq="1D10U")


Saída [241]:
DatetimeIndex ([ '2011-01-01 00:00:00', '2011-01-02 00:00:00.000010', '2011-01-03 00:00:00.000020',
'2011- 01-04 00:00:00.000030', '2011-01-05 00:00:00.000040', '2011-01-06
00:00:00.000050', '2011-01-07 00:00:00.000060', ' 08-01-2011 00:00:00.000070',
'09-01-2011 00:00:00.000080', '10-01-2011 00:00:00.000090'],

dtype='datetime64[ns]', freq='86400000010U')

872 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Deslocamentos ancorados

Para algumas frequências você pode especificar um sufixo de ancoragem:

Alias Descrição
W-SUN W- frequência semanal (domingos). O mesmo que 'W'
MON frequência semanal (segundas-feiras)
Frequência semanal W-TUE (terças-feiras)

Frequência semanal W-WED (quartas-feiras) Frequência


W-THU semanal (quintas-feiras)
W-FRI frequência semanal (sextas-feiras) frequência
W-SAT semanal (sábados) frequência trimestral,
(B)Q(S)- o ano termina em dezembro. O mesmo que 'Q'
DEZEMBRO

(B)Q(S)- frequência trimestral, o ano termina em janeiro


JANEIRO

(B)Q(S)- frequência trimestral, o ano termina em fevereiro


FEVEREIRO

(B)Q(S)- frequência trimestral, o ano termina em março


MAR

(B)Q(S)- frequência trimestral, o ano termina em abril


ABRIL

(B)Q(S)- frequência trimestral, o ano termina em maio


PODERIA

(B)Q(S)- frequência trimestral, o ano termina em junho


JUNHO

(B)Q(S)- frequência trimestral, o ano termina em julho


JULHO

(B)Q(S)- frequência trimestral, o ano termina em agosto


AGOSTO

(B)Q(S)- frequência trimestral, o ano termina em setembro


SET

(B)Q(S)- frequência trimestral, o ano termina em outubro


OUTUBRO

(B)Q(S)- frequência trimestral, o ano termina em novembro


novembro

(B)A(S)- frequência anual, ancorada no final de dezembro. O mesmo que 'A'


DEZEMBRO

(B)A(S)- frequência anual, ancorada no final de janeiro


JANEIRO

(B)A(S)- frequência anual, ancorada no final de fevereiro


FEVEREIRO

(B)A(S)- frequência anual, ancorada no final de março


MAR

(B)A(S)- frequência anual, ancorada no final de abril


ABRIL

(B)A(S)- frequência anual, ancorada no final de maio


PODERIA

(B)A(S)- frequência anual, ancorada no final de junho


JUNHO

(B)A(S)- frequência anual, ancorada no final de julho


JULHO

continua na próxima página

2.20. Funcionalidade de série temporal/data 873


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Tabela 3 – continuação da página anterior


Alias Descrição
(B)A(S)- frequência anual, ancorada no final de agosto
AGOSTO

(B)A(S)- frequência anual, ancorada no final de setembro


SET
(B)A(S)- frequência anual, ancorada no final de outubro
OUTUBRO

(B)A(S)- frequência anual, ancorada no final de novembro


novembro

Eles podem ser usados como argumentos para date_range, bdate_range, construtores para DatetimeIndex, bem como várias outras funções
relacionadas a séries temporais em pandas.

Semântica de deslocamento ancorado

Para as compensações ancoradas no início ou no final de uma frequência específica (MonthEnd, MonthBegin, WeekEnd, etc.), as regras a
seguir se aplicam ao avanço e retrocesso.

Quando n não for 0, se a data fornecida não estiver em um ponto de ancoragem, ela se moverá para o próximo ponto de ancoragem (anterior)
e moverá |n|-1 passos adicionais para frente ou para trás.

Em [242]: pd.Timestamp("2014-01-02") + pd.offsets.MonthBegin(n=1)


Saída[242]: Carimbo de data/hora('2014-02-01 00:00:00')

Em [243]: pd.Timestamp("2014-01-02") + pd.offsets.MonthEnd(n=1)


Saída[243]: Carimbo de data/hora('2014-01-31 00:00:00')

Em [244]: pd.Timestamp("2014-01-02") - pd.offsets.MonthBegin(n=1)


Saída[244]: Carimbo de data/hora('2014-01-01 00:00:00')

Em [245]: pd.Timestamp("2014-01-02") - pd.offsets.MonthEnd(n=1)


Saída[245]: Carimbo de data/hora('2013-12-31 00:00:00')

Em [246]: pd.Timestamp("2014-01-02") + pd.offsets.MonthBegin(n=4)


Saída[246]: Carimbo de data/hora('2014-05-01 00:00:00')

Em [247]: pd.Timestamp("2014-01-02") - pd.offsets.MonthBegin(n=4)


Saída[247]: Carimbo de data/hora('2013-10-01 00:00:00')

Se a data fornecida estiver em um ponto de ancoragem, ela será movida |n| aponta para frente ou para trás.

Em [248]: pd.Timestamp("2014-01-01") + pd.offsets.MonthBegin(n=1)


Saída[248]: Carimbo de data/hora('2014-02-01 00:00:00')

Em [249]: pd.Timestamp("2014-01-31") + pd.offsets.MonthEnd(n=1)


Saída[249]: Carimbo de data/hora('2014-02-28 00:00:00')

Em [250]: pd.Timestamp("2014-01-01") - pd.offsets.MonthBegin(n=1)


Saída[250]: Carimbo de data/hora('2013-12-01 00:00:00')

Em [251]: pd.Timestamp("2014-01-31") - pd.offsets.MonthEnd(n=1)


Saída[251]: Carimbo de data/hora('2013-12-31 00:00:00')
(continua na próxima página)

874 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

Em [252]: pd.Timestamp("2014-01-01") + pd.offsets.MonthBegin(n=4)


Saída[252]: Carimbo de data/hora('2014-05-01 00:00:00')

Em [253]: pd.Timestamp("2014-01-31") - pd.offsets.MonthBegin(n=4)


Saída[253]: Carimbo de data/hora('2013-10-01 00:00:00')

Para o caso em que n=0, a data não é movida se estiver em um ponto de ancoragem, caso contrário, ela é transferida para a próxima âncora
apontar.

Em [254]: pd.Timestamp("2014-01-02") + pd.offsets.MonthBegin(n=0)


Saída[254]: Carimbo de data/hora('2014-02-01 00:00:00')

Em [255]: pd.Timestamp("2014-01-02") + pd.offsets.MonthEnd(n=0)


Saída[255]: Carimbo de data/hora('2014-01-31 00:00:00')

Em [256]: pd.Timestamp("2014-01-01") + pd.offsets.MonthBegin(n=0)


Saída[256]: Carimbo de data/hora('2014-01-01 00:00:00')

Em [257]: pd.Timestamp("2014-01-31") + pd.offsets.MonthEnd(n=0)


Saída[257]: Carimbo de data/hora('2014-01-31 00:00:00')

Feriados/calendários de feriados

Feriados e calendários fornecem uma maneira simples de definir regras de feriados a serem usadas com CustomBusinessDay ou em outros
análise que requer um conjunto predefinido de feriados. A classe AbstractHolidayCalendar fornece todos os recursos necessários
métodos para retornar uma lista de feriados e apenas regras precisam ser definidas em uma classe específica de calendário de
feriados. Além disso, os atributos de classe start_date e end_date determinam em qual intervalo de datas os feriados são gerados. Esses
deve ser substituído na classe AbstractHolidayCalendar para que o intervalo seja aplicado a todas as subclasses do calendário.
USFederalHolidayCalendar é o único calendário que existe e serve principalmente como exemplo para o desenvolvimento de outros
calendários.

Para feriados que ocorrem em datas fixas (por exemplo, Memorial Day dos EUA ou 4 de julho), uma regra de observância determina quando
feriado é observado se cair em um fim de semana ou em algum outro dia não observado. As regras de observância definidas são:

Regra Descrição
next_workday muda de sábado para sexta e de domingo para segunda
sol- passar o domingo para a segunda-feira seguinte
dia_a_segunda
next_monday_or_tuesday mover sábado para segunda e domingo/segunda para terça
previous_sexta-feira move sábado e domingo para sexta-feira anterior”
next_monday move sábado e domingo para segunda-feira seguinte

Um exemplo de como são definidos feriados e calendários de feriados:

Em [258]: de pandas.tseries.holiday import (


.....: Feriado,
.....: MemorialDay dos EUA,
.....: ResumoFériasCalendário,
.....: dia_trabalho mais próximo,
.....: MO,
(continua na próxima página)

2.20. Funcionalidade de série temporal/data 875


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

..... :)
.....:

Em [259]: classe ExemploCalendar(AbstractHolidayCalendar):


.....: regras = [
.....: MemorialDay dos EUA,
.....: Feriado(" 4 de julho", mês=7, dia=4, observância=dia_trabalho mais próximo),
.....: Feriado(
.....: "Dia de Colombo",
.....: mês = 10,
.....: dia=1,
.....: deslocamento = pd.DateOffset (dia da semana = MO (2)),
.....: ),
.....: ]
.....:

Em [260]: cal = ExemploCalendário()

Em [261]: cal.holidays(datetime.datetime(2012, 1, 1), datetime.datetime(2012, 12, 31))


Saída[261]: DatetimeIndex(['2012-05-28', '2012-07-04', '2012-10-08'], dtype='datetime64[ns]
ÿÿ', freq=Nenhum)

dica weekday=MO(2) é igual a 2 * Week(weekday=2)


Usando este calendário, a criação de um índice ou a aritmética de deslocamento ignora fins de semana e feriados (ou seja, Memorial Day/julho
4º). Por exemplo, a seguir define um deslocamento de dia útil personalizado usando o exemploCalendar. Como qualquer outro deslocamento,
ele pode ser usado para criar um DatetimeIndex ou adicionado a objetos datetime ou Timestamp.

Em [262]: pd.date_range(
.....: start="01/07/2012", end="10/07/2012", freq=pd.offsets.CDay(calendar=cal)
.....: .to_pydatetime()
.....:
Fora[262]:
matriz([datahora.datahora(2012, 7, 2, 0, 0),
datahora.datehora(2012, 7, 3, 0, 0),
datetime.datetime(2012, 7, 5, 0, 0),
datahora.datehora(2012, 7, 6, 0, 0),
datahora.datehora(2012, 7, 9, 0, 0),
datetime.datetime(2012, 7, 10, 0, 0)], dtype=objeto)

Em [263]: deslocamento = pd.offsets.CustomBusinessDay(calendar=cal)

Em [264]: datetime.datetime(2012, 5, 25) + deslocamento


Saída[264]: Carimbo de data/hora('2012-05-29 00:00:00')

Em [265]: datetime.datetime(2012, 7, 3) + deslocamento


Saída[265]: Carimbo de data/hora('2012-07-05 00:00:00')

Em [266]: datetime.datetime(2012, 7, 3) + 2 * deslocamento


Saída[266]: Carimbo de data/hora('2012-07-06 00:00:00')

Em [267]: datetime.datetime(2012, 7, 6) + deslocamento


Saída[267]: Carimbo de data/hora('2012-07-09 00:00:00')

876 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Os intervalos são definidos pelos atributos de classe start_date e end_date de AbstractHolidayCalendar. Os padrões são
mostrados abaixo.

Em [268]: AbstractHolidayCalendar.start_date Out[268]:


Timestamp('1970-01-01 00:00:00')

Em [269]: AbstractHolidayCalendar.end_date Out[269]:


Timestamp('2200-12-31 00:00:00')

Essas datas podem ser substituídas definindo os atributos como datetime/Timestamp/string.

Em [270]: AbstractHolidayCalendar.start_date = datetime.datetime(2012, 1, 1)

Em [271]: AbstractHolidayCalendar.end_date = datetime.datetime(2012, 12, 31)

Em [272]: cal.feriados()
Out[272]: DatetimeIndex(['2012-05-28', '2012-07-04', '2012-10-08'], dtype='datetime64[ns] ÿÿ', freq=None)

Cada classe de calendário é acessível por nome usando a função get_calendar que retorna uma instância da classe holiday.
Qualquer classe de calendário importada estará automaticamente disponível por esta função. Além disso, HolidayCalendarFactory
fornece uma interface fácil para criar calendários que são combinações de calendários ou calendários com regras adicionais.

Em [273]: de pandas.tseries.holiday import get_calendar, HolidayCalendarFactory,ÿ ÿÿUSLaborDay

Em [274]: cal = get_calendar("ExampleCalendar")

In [275]: cal.rules Out[275]:


[Feriado:
Memorial Day (mês=5, dia=31, deslocamento=<DateOffset: weekday=MO(-1)>), Feriado: 4 de julho (mês=7 ,
dia=4, observância=<função dia_trabalho mais próximo emÿ ÿÿ0x7f0eded1cdc0>), Feriado: Dia de Colombo
(mês=10, dia=1,
deslocamento=<DateOffset: dia da semana=MO(+2)>)]

Em [276]: new_cal = HolidayCalendarFactory("NewExampleCalendar", cal, USLaborDay)

In [277]: new_cal.rules Out[277]:


[Feriado:
Dia do Trabalho (mês=9, dia=1, deslocamento=<DateOffset: weekday=MO(+1)>), Feriado: Memorial Day
(mês=5 , dia=31, deslocamento=<DateOffset: weekday=MO(-1)>), Feriado: 4 de julho (mês=7, dia=4,
observância=<função dia_trabalho mais próximo emÿ ÿÿ0x7f0eded1cdc0>), Feriado: Dia de Colombo
(mês=10, dia=1,
deslocamento=<DateOffset: dia da semana=MO(+2)>)]

2.20. Funcionalidade de série temporal/data 877


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

2.20.9 Métodos de instância relacionados a séries temporais

Mudança / atraso

Pode-se querer deslocar ou atrasar os valores em uma série temporal para frente e para trás no tempo. O método para isso é shift(),
que está disponível em todos os objetos pandas.

Em [278]: ts = pd.Series(range(len(rng)), index=rng)

Em [279]: ts = ts[:5]

Em [280]: ts.shift(1)
Fora[280]:
01/01/2012 NaN
02/01/2012 0,0
03/01/2012 1,0
Freq: D, tipo d: float64

O método shift aceita um argumento freq que pode aceitar uma classe DateOffset ou outro objeto do tipo timedelta
ou também um alias de deslocamento.

Quando freq é especificado, o método shift altera todas as datas no índice em vez de alterar o alinhamento do
dados e o índice:

Em [281]: ts.shift(5, freq="D")


Fora[281]:
06/01/2012 0
07/01/2012 1
08/01/2012 2
Freq: D, tipo d: int64

Em [282]: ts.shift(5, freq=pd.offsets.BDay())


Fora[282]:
06/01/2012 0
09/01/2012 1
10/01/2012 2
tipo d: int64

Em [283]: ts.shift(5, freq="BM")


Fora[283]:
31/05/2012 0
31/05/2012 1
31/05/2012 2
dtype: int64

Observe que quando freq é especificado, a entrada inicial não é mais NaN porque os dados não estão sendo realinhados.

878 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Conversão de frequência

A principal função para alterar frequências é o método asfreq() . Para um DatetimeIndex, isso é basicamente apenas
um wrapper fino, mas conveniente em torno de reindex() que gera um intervalo de datas e chama reindex.

Em [284]: dr = pd.date_range("1/1/2010", períodos=3, freq=3 * pd.offsets.BDay())

Em [285]: ts = pd.Series(np.random.randn(3), index=dr)

Em [286]: ts
Fora[286]:
01/01/2010 1.494522
06-01-2010 -0,778425
11/01/2010 -0,253355
Freq: 3B, tipo d: float64

Em [287]: ts.asfreq(pd.offsets.BDay())
Fora[287]:
01-01-2010 1.494522
04-01-2010 NaN
05-01-2010 NaN
06-01-2010 -0,778425
07/01/2010 NaN
08/01/2010 NaN
11/01/2010 -0,253355
Freq: B, tipo d: float64

asfreq fornece uma conveniência adicional para que você possa especificar um método de interpolação para quaisquer lacunas que possam aparecer após
a conversão de frequência.

Em [288]: ts.asfreq(pd.offsets.BDay(), método="pad")


Fora[288]:
01/01/2010 1.494522
04-01-2010 1.494522
05/01/2010 1.494522
06-01-2010 -0,778425
07-01-2010 -0,778425
08/01/2010 -0,778425
11/01/2010 -0,253355
Freq: B, tipo d: float64

2.20. Funcionalidade de série temporal/data 879


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Preenchendo para frente / para trás

Relacionado a asfreq e reindex está fillna(), que está documentado na seção de dados ausentes.

Convertendo para datas Python

DatetimeIndex pode ser convertido em uma matriz de objetos datetime.datetime nativos do Python usando o método to_pydatetime.

2.20.10 Reamostragem

O pandas possui uma funcionalidade simples, poderosa e eficiente para realizar operações de reamostragem durante a conversão de
frequência (por exemplo, converter dados secundários em dados de 5 minutos). Isso é extremamente comum, mas não se limita a,
aplicações financeiras.

resample() é um groupby baseado em tempo, seguido por um método de redução em cada um de seus grupos. Veja alguns exemplos de livros
de receitas para algumas estratégias avançadas.

O método resample() pode ser usado diretamente dos objetos DataFrameGroupBy, consulte a documentação groupby.

Fundamentos

Em [289]: rng = pd.date_range("1/1/2012", períodos=100, freq="S")

Em [290]: ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)

Em [291]: ts.resample("5Min").sum()
Saída [291]:
01/01/2012 25103 Freq: 5T,
dtype: int64

A função de reamostragem é muito flexível e permite especificar muitos parâmetros diferentes para controlar a conversão de frequência
e a operação de reamostragem.

Qualquer função disponível via despacho está disponível como um método do objeto retornado, incluindo soma, média, padrão, sem,
máximo, mínimo, mediana, primeiro, último, ohlc:

Em [292]: ts.resample("5Min").mean()
Fora[292]:
01/01/2012 251.03
Freq: 5T, tipo d: float64

Em [293]: ts.resample("5Min").ohlc()
Fora[293]:
abrir alto baixo fechar 205
01/01/2012 308 460 9

Em [294]: ts.resample("5Min").max()
Saída [294]:
01/01/2012 460 Freq: 5T,
dtype: int64

Para redução da resolução, fechado pode ser definido como 'esquerda' ou 'direita' para especificar qual final do intervalo é fechado:

880 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Em [295]: ts.resample("5Min", fechado="direita").mean()


Fora[295]:
31/12/2011 23:55:00 308.000000
01/01/2012 00:00:00 250.454545
Freq: 5T, tipo d: float64

Em [296]: ts.resample("5Min", fechado="esquerda").mean()


Fora[296]:
01/01/2012 251,03
Freq: 5T, tipo d: float64

Parâmetros como rótulo são usados para manipular os rótulos resultantes. label especifica se o resultado é rotulado com
o início ou o fim do intervalo.

Em [297]: ts.resample("5Min").mean() # por padrão label='left'


Fora[297]:
01/01/2012 251.03
Freq: 5T, tipo d: float64

Em [298]: ts.resample("5Min", label="left").mean()


Fora[298]:
01/01/2012 251.03
Freq: 5T, tipo d: float64

Aviso: Os valores padrão para rótulo e fechado são 'esquerdo' para todos os deslocamentos de frequência, exceto 'M', 'A', 'Q',
'BM', 'BA', 'BQ' e 'W', todos com o padrão 'certo'.

Isso pode levar involuntariamente a uma previsão futura, em que o valor de um momento posterior é retrocedido para um momento anterior, pois
no exemplo a seguir com a frequência BusinessDay :

Em [299]: s = pd.date_range("2000-01-01", "2000-01-05").to_series()

Em [300]: s.iloc[2] = pd.NaT

Em [301]: s.dt.day_name()
Fora[301]:
01/01/2000 Sábado
02/01/2000 Domingo
03/01/2000 NaN
04-01-2000 Terça-feira
05/01/2000 Quarta-feira
Freq: D, dtype: objeto

# padrão: label='esquerda', fechado='esquerda'


Em [302]: s.resample("B").last().dt.day_name()
Fora[302]:
31/12/1999 Domingo
03/01/2000 NaN
04-01-2000 Terça-feira
05/01/2000 Quarta-feira
Freq: B, dtype: objeto

Observe como o valor do domingo foi reduzido para a sexta-feira anterior. Para obter o comportamento onde o valor para

2.20. Funcionalidade de série temporal/data 881


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Domingo é transferido para segunda-feira, use em vez disso

Em [303]: s.resample("B", label="right", fechado="right").last().dt.day_name()


Fora[303]:
03/01/2000 Domingo
04-01-2000 Terça-feira
05/01/2000 Quarta-feira
Freq: B, dtype: objeto

O parâmetro axis pode ser definido como 0 ou 1 e permite reamostrar o eixo especificado para um DataFrame.

kind pode ser definido como 'timestamp' ou 'period' para converter o índice resultante de/para representações de timestamp e intervalo de
tempo. Por padrão, a reamostragem mantém a representação de entrada.

a convenção pode ser definida como 'início' ou 'fim' ao reamostrar os dados do período (detalhe abaixo). Ele especifica quão baixa frequência
períodos são convertidos em períodos de frequência mais alta.

Aumento da resolução

Para upsampling, você pode especificar uma forma de upsample e o parâmetro limite para interpolar sobre as lacunas que são
criada:

# de segundo a cada 250 milissegundos


Em [304]: ts[:2].resample("250L").asfreq()
Fora[304]:
01-01-2012 00:00:00.000 308,0
01-01-2012 00:00:00.250 NaN
01-01-2012 00:00:00.500 NaN
01-01-2012 00:00:00.750 NaN
01/01/2012 00:00:01.000 204,0
Freq: 250L, tipo d: float64

Em [305]: ts[:2].resample("250L").ffill()
Fora[305]:
01/01/2012 00:00:00.000 308
01-01-2012 00:00:00.250 308
01-01-2012 00:00:00.500 308
01-01-2012 00:00:00.750 308
01/01/2012 00:00:01.000 Freq: 204
250L, dtype: int64

Em [306]: ts[:2].resample("250L").ffill(limit=2)
Fora[306]:
01-01-2012 00:00:00.000 308,0
01-01-2012 00:00:00.250 308,0
01-01-2012 00:00:00.500 308,0
01-012012 00:00:00.750 NaN
01-01-2012 00:00:01.000 Freq: 204,0
250L, tipo d: float64

882 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Reamostragem esparsa

Séries temporais esparsas são aquelas em que você tem muito menos pontos em relação à quantidade de tempo que deseja
redimensionamento. Aumentar a resolução ingenuamente de uma série esparsa pode potencialmente gerar muitos valores intermediários. Quando você não
Se você quiser usar um método para preencher esses valores, por exemplo, fill_method é None, então os valores intermediários serão preenchidos com NaN.

Como a reamostragem é um agrupamento baseado no tempo, a seguir está um método para reamostrar com eficiência apenas os grupos que não são
tudo NaN.

Em [307]: rng = pd.date_range("2014-1-1", períodos=100, freq="D") + pd.Timedelta("1s")

Em [308]: ts = pd.Series(range(100), index=rng)

Se quisermos reamostrar toda a gama da série:

Em [309]: ts.resample("3T").sum()
Fora[309]:
01-01-2014 00:00:00 0
01-01-2014 00:03:00 0
01-01-2014 00:06:00 0
01-01-2014 00:09:00 0
01-01-2014 00:12:00 0
..
09/04/2014 23:48:00 0
09/04/2014 23:51:00 0
09/04/2014 23:54:00 0
09/04/2014 23:57:00 0
10/04/2014 00:00:00 99
Freq: 3T, Comprimento: 47521, tipo d: int64

Em vez disso, podemos reamostrar apenas os grupos onde temos pontos da seguinte forma:

Em [310]: de functools importa parcial

Em [311]: de pandas.tseries.frequencies importar para_offset

Em [312]: def round(t, freq):


.....: freq = to_offset(freq)
.....: retornar pd.Timestamp((t.value // freq.delta.value) * freq.delta.value)
.....:

Em [313]: ts.groupby(partial(round, freq="3T")).sum()


Fora[313]:
01-01-2014 0
02/01/2014 1
03/01/2014 2
04/01/2014 3
05/01/2014 4
..
06/04/2014 95
07/04/2014 96
08/04/2014 97
09/04/2014 98
10/04/2014 99
Comprimento: 100, tipo d: int64

2.20. Funcionalidade de série temporal/data 883


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

Agregação

Semelhante à API de agregação, à API groupby e à API de janela, um Reamostrador pode ser reamostrado seletivamente.

Reamostrando um DataFrame, o padrão será atuar em todas as colunas com a mesma função.

Em [314]: df = pd.DataFrame(
.....: np.random.randn(1000, 3),
.....: índice=pd.date_range("01/01/2012", freq="S", períodos=1000),
.....: colunas=["A", "B", "C"],
..... :)
.....:

Em [315]: r = df.resample("3T")

Em [316]: r.mean()
Fora[316]:
A B C
01-01-2012 00:00:00 -0,033823 -0,121514 -0,081447
01-01-2012 00:03:00 0,056909 0,146731 -0,024320
01-01-2012 00:06:00 -0,058837 0,047046 -0,052021
01/01/2012 00:09:00 0,063123 -0,026158 -0,066533
01-01-2012 00:12:00 0,186340 -0,003144 0,074752
01-01-2012 00:15:00 -0,085954 -0,016287 -0,050046

Podemos selecionar uma coluna ou colunas específicas usando getitem padrão.

Em [317]: r["A"].mean()
Fora[317]:
01-01-2012 00:00:00 -0,033823
01/01/2012 00:03:00 0,056909
01-01-2012 00:06:00 -0,058837
01-01-2012 00:09:00 0,063123
01-01-2012 00:12:00 0,186340
01-01-2012 00:15:00 -0,085954
Freq: 3T, Nome: A, tipo d: float64

Em [318]: r[["A", "B"]].mean()


Fora[318]:
A B
01/01/2012 00:00:00 -0,033823 -0,121514
01/01/2012 00:03:00 0,056909 0,146731
01/01/2012 00:06:00 -0,058837 0,047046
01/01/2012 00:09:00 0,063123 -0,026158
01-01-2012 00:12:00 0,186340 -0,003144
01/01/2012 00:15:00 -0,085954 -0,016287

Você pode passar uma lista ou ditado de funções para agregar, gerando um DataFrame:

Em [319]: r["A"].agg([np.sum, np.mean, np.std])


Fora[319]:
soma significar padrão

01/01/2012 00:00:00 -6,088060 -0,033823 1,043263


01/01/2012 00:03:00 10,243678 0,056909 1,058534
(continua na próxima página)

884 Capítulo 2. Guia do Usuário


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

01/01/2012 00:06:00 -10,590584 -0,058837 0,949264


01/01/2012 00:09:00 11,362228 0,063123 1,028096
01-01-2012 00:12:00 33,541257 0,186340 0,884586
01/01/2012 00:15:00 -8,595393 -0,085954 1,035476

Em um DataFrame reamostrado, você pode passar uma lista de funções para aplicar a cada coluna, o que produz um valor agregado
resultado com um índice hierárquico:

Em [320]: r.agg([np.sum, np.mean])


Fora[320]:
A B C
soma significar soma significar soma significar

01/01/2012 00:00:00 -6,088060 -0,033823 -21,872530 -0,121514 -14,660515 -0,081447


01/01/2012 00:03:00 10,243678 0,056909 26,411633 0,146731 -4,377642 -0,024320
01-01-2012 00:06:00 -10,590584 -0,058837 8,468289 0,047046 -9,363825 -0,052021
01-01-2012 00:09:00 11,362228 0,063123 -4,708526 -0,026158 -11,975895 -0,066533
01-01-2012 00:12:00 33,541257 0,186340 -0,565895 -0,003144 13,455299 0,074752
01/01/2012 00:15:00 -8,595393 -0,085954 -1,628689 -0,016287 -5,004580 -0,050046

Ao passar um dict para agregar você pode aplicar uma agregação diferente às colunas de um DataFrame:

Em [321]: r.agg({"A": np.sum, "B": lambda x: np.std(x, ddof=1)})


Fora[321]:
AB
01/01/2012 00:00:00 -6,088060 1,001294
01/01/2012 00:03:00 10,243678 1,074597
01/01/2012 00:06:00 -10,590584 0,987309
01/01/2012 00:09:00 11,362228 0,944953
01/01/2012 00:12:00 33,541257 1,095025
01/01/2012 00:15:00 -8,595393 1,035312

Os nomes das funções também podem ser strings. Para que uma string seja válida ela deve ser implementada no objeto reamostrado:

Em [322]: r.agg({"A": "soma", "B": "std"})


Fora[322]:
A B
01/01/2012 00:00:00 -6,088060 1,001294
01/01/2012 00:03:00 10,243678 1,074597
01/01/2012 00:06:00 -10,590584 0,987309
01/01/2012 00:09:00 11,362228 0,944953
01/01/2012 00:12:00 33,541257 1,095025
01/01/2012 00:15:00 -8,595393 1,035312

Além disso, você também pode especificar diversas funções de agregação para cada coluna separadamente.

Em [323]: r.agg({"A": ["soma", "padrão"], "B": ["média", "padrão"]})


Fora[323]:
A B
soma padrão significar padrão

01/01/2012 00:00:00 -6,088060 1,043263 -0,121514 1,001294


01/01/2012 00:03:00 10,243678 1,058534 0,146731 1,074597
01/01/2012 00:06:00 -10,590584 0,949264 0,047046 0,987309
01/01/2012 00:09:00 11,362228 1,028096 -0,026158 0,944953
(continua na próxima página)

2.20. Funcionalidade de série temporal/data 885


Machine Translated by Google

pandas: poderoso kit de ferramentas de análise de dados Python, versão 1.4.4

(continuação da página anterior)

01-01-2012 00:12:00 33,541257 0,884586 -0,003144 1,095025


01/01/2012 00:15:00 -8,595393 1,035476 -0,016287 1,035312

Se um DataFrame não tiver um índice datetimelike, mas em vez disso você quiser fazer uma nova amostragem com base na coluna datetimelike no
quadro, ele poderá ser passado para a palavra-chave on.

Em [324]: df = pd.DataFrame( {"data":


.....: pd.date_range("2015-01-01", freq="W", períodos=5), "a": np.
ÿÿlaranja(5)},
.....: índice=pd.MultiIndex.from_arrays(
.....: [[1, 2, 3, 4, 5], pd.date_range("2015-01-01", freq="W", períodos=5)], nomes=["v", "d"],
.....:
.....: ),
..... :)
.....:

Em [325]: df
Fora[325]:
namorar um
vd
1 04/01/2015 04/01/2015 0
2 11/01/2015 11/01/2015 1
3 18/01/2015 18/01/2015 2
4 25/01/2015 25/01/2015 3
5 01/02/2015 01/02/2015 4

Em [326]: df.resample("M", on="data").sum()


Fora[326]:
a
data
31/01/2015 6
28/02/2015 4

Da mesma forma, se você quiser fazer uma nova amostragem por um nível semelhante a data e hora do MultiIndex, seu nome ou localização poderá ser
passado para a palavra-chave level.

Em [327]: df.resample("M", level="d").sum()


Fora[327]:
a
d
31/01/2015 6
28/02/2015 4

886 Capítulo 2. Guia do Usuário

Você também pode gostar