quarta-feira, 12 de agosto de 2020

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

Imagem de Steve Buissinne por Pixabay

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Usando o método append do pandas

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

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

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

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

Ignorando índices

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

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

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

Concatenando séries com dataframes

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

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

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

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

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

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

Concatenando com um grupo de keys

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

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

Podemos fazer a mesma coisa com um dicionário.

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

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

0 comentários:

Postar um comentário