Come ruotare un dataframe?
- Cos'è pivot?
- Come faccio a ruotare?
- È questo un perno?
- Dal formato lungo al grande formato?
Ho visto molte domande che pongono sulle tabelle pivot. Anche se non sanno che stanno chiedendo informazioni sulle tabelle pivot, di solito lo sono. È praticamente impossibile scrivere una domanda e una risposta canoniche che comprenda tutti gli aspetti del pivot ...
... Ma ci proverò.
Il problema con le domande e le risposte esistenti è che spesso la domanda è focalizzata su una sfumatura che il PO ha difficoltà a generalizzare per utilizzare un certo numero di buone risposte esistenti. Tuttavia, nessuna delle risposte cerca di fornire una spiegazione esauriente (perché è un compito arduo)
Guarda alcuni esempi dalla mia ricerca su Google
- Buona domanda e risposta. Ma la risposta risponde solo alla domanda specifica con poche spiegazioni.
- In questa domanda, l'OP si occupa dell'output del pivot. Vale a dire come appaiono le colonne. OP voleva che assomigliasse a R. Questo non è molto utile per gli utenti di panda.
- Un'altra domanda decente, ma la risposta si concentra su un metodo, vale a dire
pd.DataFrame.pivot
Quindi, ogni volta che qualcuno cerca pivot
, ottiene risultati sporadici che probabilmente non risponderanno alla loro domanda specifica.
Impostare
Potresti notare che ho chiamato in modo evidente le mie colonne e i valori delle colonne pertinenti in modo che corrispondano a come farò perno nelle risposte seguenti.
import numpy as np
import pandas as pd
from numpy.core.defchararray import add
np.random.seed([3,1415])
n = 20
cols = np.array(['key', 'row', 'item', 'col'])
arr1 = (np.random.randint(5, size=(n, 4)) // [2, 1, 2, 1]).astype(str)
df = pd.DataFrame(
add(cols, arr1), columns=cols
).join(
pd.DataFrame(np.random.rand(n, 2).round(2)).add_prefix('val')
)
print(df)
key row item col val0 val1
0 key0 row3 item1 col3 0.81 0.04
1 key1 row2 item1 col2 0.44 0.07
2 key1 row0 item1 col0 0.77 0.01
3 key0 row4 item0 col2 0.15 0.59
4 key1 row0 item2 col1 0.81 0.64
5 key1 row2 item2 col4 0.13 0.88
6 key2 row4 item1 col3 0.88 0.39
7 key1 row4 item1 col1 0.10 0.07
8 key1 row0 item2 col4 0.65 0.02
9 key1 row2 item0 col2 0.35 0.61
10 key2 row0 item2 col1 0.40 0.85
11 key2 row4 item1 col2 0.64 0.25
12 key0 row2 item2 col3 0.50 0.44
13 key0 row4 item1 col4 0.24 0.46
14 key1 row3 item2 col3 0.28 0.11
15 key0 row3 item1 col1 0.31 0.23
16 key0 row0 item2 col3 0.86 0.01
17 key0 row4 item0 col3 0.64 0.21
18 key2 row2 item2 col0 0.13 0.45
19 key0 row2 item0 col4 0.37 0.70
Domande)
Perché ottengo
ValueError: Index contains duplicate entries, cannot reshape
Come faccio a ruotare in modo
df
tale che icol
valori siano colonne, irow
valori siano l'indice e la mediaval0
siano i valori?col col0 col1 col2 col3 col4 row row0 0.77 0.605 NaN 0.860 0.65 row2 0.13 NaN 0.395 0.500 0.25 row3 NaN 0.310 NaN 0.545 NaN row4 NaN 0.100 0.395 0.760 0.24
Come faccio a ruotare in modo
df
tale che icol
valori siano colonne, irow
valori siano l'indice, la media deival0
valori e i valori mancanti siano0
?col col0 col1 col2 col3 col4 row row0 0.77 0.605 0.000 0.860 0.65 row2 0.13 0.000 0.395 0.500 0.25 row3 0.00 0.310 0.000 0.545 0.00 row4 0.00 0.100 0.395 0.760 0.24
Posso ottenere qualcosa di diverso
mean
, come forsesum
?col col0 col1 col2 col3 col4 row row0 0.77 1.21 0.00 0.86 0.65 row2 0.13 0.00 0.79 0.50 0.50 row3 0.00 0.31 0.00 1.09 0.00 row4 0.00 0.10 0.79 1.52 0.24
Posso fare più di un'aggregazione alla volta?
sum mean col col0 col1 col2 col3 col4 col0 col1 col2 col3 col4 row row0 0.77 1.21 0.00 0.86 0.65 0.77 0.605 0.000 0.860 0.65 row2 0.13 0.00 0.79 0.50 0.50 0.13 0.000 0.395 0.500 0.25 row3 0.00 0.31 0.00 1.09 0.00 0.00 0.310 0.000 0.545 0.00 row4 0.00 0.10 0.79 1.52 0.24 0.00 0.100 0.395 0.760 0.24
Posso aggregare su più colonne di valori?
val0 val1 col col0 col1 col2 col3 col4 col0 col1 col2 col3 col4 row row0 0.77 0.605 0.000 0.860 0.65 0.01 0.745 0.00 0.010 0.02 row2 0.13 0.000 0.395 0.500 0.25 0.45 0.000 0.34 0.440 0.79 row3 0.00 0.310 0.000 0.545 0.00 0.00 0.230 0.00 0.075 0.00 row4 0.00 0.100 0.395 0.760 0.24 0.00 0.070 0.42 0.300 0.46
Può suddividere per più colonne?
item item0 item1 item2 col col2 col3 col4 col0 col1 col2 col3 col4 col0 col1 col3 col4 row row0 0.00 0.00 0.00 0.77 0.00 0.00 0.00 0.00 0.00 0.605 0.86 0.65 row2 0.35 0.00 0.37 0.00 0.00 0.44 0.00 0.00 0.13 0.000 0.50 0.13 row3 0.00 0.00 0.00 0.00 0.31 0.00 0.81 0.00 0.00 0.000 0.28 0.00 row4 0.15 0.64 0.00 0.00 0.10 0.64 0.88 0.24 0.00 0.000 0.00 0.00
O
item item0 item1 item2 col col2 col3 col4 col0 col1 col2 col3 col4 col0 col1 col3 col4 key row key0 row0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.86 0.00 row2 0.00 0.00 0.37 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.50 0.00 row3 0.00 0.00 0.00 0.00 0.31 0.00 0.81 0.00 0.00 0.00 0.00 0.00 row4 0.15 0.64 0.00 0.00 0.00 0.00 0.00 0.24 0.00 0.00 0.00 0.00 key1 row0 0.00 0.00 0.00 0.77 0.00 0.00 0.00 0.00 0.00 0.81 0.00 0.65 row2 0.35 0.00 0.00 0.00 0.00 0.44 0.00 0.00 0.00 0.00 0.00 0.13 row3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.28 0.00 row4 0.00 0.00 0.00 0.00 0.10 0.00 0.00 0.00 0.00 0.00 0.00 0.00 key2 row0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.40 0.00 0.00 row2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.13 0.00 0.00 0.00 row4 0.00 0.00 0.00 0.00 0.00 0.64 0.88 0.00 0.00 0.00 0.00 0.00
Posso aggregare la frequenza con cui la colonna e le righe ricorrono insieme, ovvero "tabulazione incrociata"?
col col0 col1 col2 col3 col4 row row0 1 2 0 1 1 row2 1 0 2 1 2 row3 0 1 0 2 0 row4 0 1 2 2 1
Come posso convertire un DataFrame da lungo a largo ruotando SOLO su due colonne? Dato,
np.random.seed([3, 1415]) df2 = pd.DataFrame({'A': list('aaaabbbc'), 'B': np.random.choice(15, 8)}) df2 A B 0 a 0 1 a 11 2 a 2 3 a 11 4 b 10 5 b 10 6 b 14 7 c 7
L'atteso dovrebbe assomigliare a qualcosa
a b c 0 0.0 10.0 7.0 1 11.0 10.0 NaN 2 2.0 14.0 NaN 3 11.0 NaN NaN
Come appiattisco l'indice multiplo in un indice singolo dopo
pivot
A partire dal
1 2 1 1 2 a 2 1 1 b 2 1 0 c 1 0 0
Per
1|1 2|1 2|2 a 2 1 1 b 2 1 0 c 1 0 0
Risposte
Iniziamo rispondendo alla prima domanda:
Domanda 1
Perché ottengo
ValueError: Index contains duplicate entries, cannot reshape
Ciò si verifica perché i panda stanno tentando di reindicizzare un oggetto columns
o index
con voci duplicate. Esistono diversi metodi da utilizzare che possono eseguire un pivot. Alcuni di essi non sono adatti a quando sono presenti duplicati delle chiavi su cui viene chiesto di ruotare. Per esempio. Considera pd.DataFrame.pivot
. So che ci sono voci duplicate che condividono i valori row
e col
:
df.duplicated(['row', 'col']).any()
True
Quindi quando pivot
uso
df.pivot(index='row', columns='col', values='val0')
Ottengo l'errore di cui sopra. In effetti, ottengo lo stesso errore quando provo a eseguire la stessa attività con:
df.set_index(['row', 'col'])['val0'].unstack()
Ecco un elenco di modi di dire che possiamo usare per fare perno
pd.DataFrame.groupby
+pd.DataFrame.unstack
- Buon approccio generale per eseguire praticamente qualsiasi tipo di perno
- Specificare tutte le colonne che costituiranno i livelli di riga pivot e i livelli di colonna in un gruppo da. Puoi seguirlo selezionando le colonne rimanenti che desideri aggregare e le funzioni che desideri eseguire l'aggregazione. Infine,
unstack
i livelli che vuoi essere nell'indice della colonna.
pd.DataFrame.pivot_table
- Una versione glorificata di
groupby
con API più intuitive. Per molte persone, questo è l'approccio preferito. Ed è l'approccio previsto dagli sviluppatori. - Specificare il livello di riga, i livelli di colonna, i valori da aggregare e le funzioni per eseguire le aggregazioni.
- Una versione glorificata di
pd.DataFrame.set_index
+pd.DataFrame.unstack
- Comodo e intuitivo per alcuni (me compreso). Impossibile gestire chiavi raggruppate duplicate.
- Simile al
groupby
paradigma, specifichiamo tutte le colonne che alla fine saranno livelli di riga o di colonna e le impostiamo come indice. Abbiamo quindiunstack
i livelli che vogliamo nelle colonne. Se i livelli di indice rimanenti oi livelli di colonna non sono univoci, questo metodo avrà esito negativo.
pd.DataFrame.pivot
- Molto simile a
set_index
in quanto condivide la limitazione della chiave duplicata. Anche l'API è molto limitata. Si richiede solo valori scalari perindex
,columns
,values
. - Simile al
pivot_table
metodo in quanto selezioniamo righe, colonne e valori su cui ruotare. Tuttavia, non possiamo aggregare e se le righe o le colonne non sono univoche, questo metodo fallirà.
- Molto simile a
pd.crosstab
- Questa una versione specializzata
pivot_table
e nella sua forma più pura è il modo più intuitivo per eseguire diverse attività.
- Questa una versione specializzata
pd.factorize
+np.bincount
- Questa è una tecnica molto avanzata che è molto oscura ma è molto veloce. Non può essere utilizzato in tutte le circostanze, ma quando può essere utilizzato e ti senti a tuo agio nell'usarlo, raccoglierai i frutti delle prestazioni.
pd.get_dummies
+pd.DataFrame.dot
- Lo uso per eseguire abilmente la tabulazione incrociata.
Esempi
Quello che farò per ogni risposta e domanda successiva è rispondere usando pd.DataFrame.pivot_table
. Quindi fornirò alternative per eseguire la stessa operazione.
Domanda 3
Come faccio a ruotare in modo
df
tale che icol
valori siano colonne, irow
valori siano l'indice, la media deival0
valori e i valori mancanti siano0
?
pd.DataFrame.pivot_table
fill_value
non è impostato di default. Tendo a impostarlo in modo appropriato. In questo caso l'ho impostato su0
. Si noti che ho saltato la domanda 2 poiché è la stessa di questa risposta senza l'estensionefill_value
aggfunc='mean'
è l'impostazione predefinita e non ho dovuto impostarla. L'ho incluso per essere esplicito.df.pivot_table( values='val0', index='row', columns='col', fill_value=0, aggfunc='mean') col col0 col1 col2 col3 col4 row row0 0.77 0.605 0.000 0.860 0.65 row2 0.13 0.000 0.395 0.500 0.25 row3 0.00 0.310 0.000 0.545 0.00 row4 0.00 0.100 0.395 0.760 0.24
pd.DataFrame.groupby
df.groupby(['row', 'col'])['val0'].mean().unstack(fill_value=0)
pd.crosstab
pd.crosstab( index=df['row'], columns=df['col'], values=df['val0'], aggfunc='mean').fillna(0)
Domanda 4
Posso ottenere qualcosa di diverso
mean
, come forsesum
?
pd.DataFrame.pivot_table
df.pivot_table( values='val0', index='row', columns='col', fill_value=0, aggfunc='sum') col col0 col1 col2 col3 col4 row row0 0.77 1.21 0.00 0.86 0.65 row2 0.13 0.00 0.79 0.50 0.50 row3 0.00 0.31 0.00 1.09 0.00 row4 0.00 0.10 0.79 1.52 0.24
pd.DataFrame.groupby
df.groupby(['row', 'col'])['val0'].sum().unstack(fill_value=0)
pd.crosstab
pd.crosstab( index=df['row'], columns=df['col'], values=df['val0'], aggfunc='sum').fillna(0)
Domanda 5
Posso fare più di un'aggregazione alla volta?
Si noti che per pivot_table
e crosstab
avevo bisogno di passare l'elenco di invocabili. D'altra parte, groupby.agg
è in grado di accettare stringhe per un numero limitato di funzioni speciali. groupby.agg
avrebbe anche preso gli stessi invocabili che abbiamo passato agli altri, ma spesso è più efficiente sfruttare i nomi delle funzioni stringa poiché ci sono efficienze da ottenere.
pd.DataFrame.pivot_table
df.pivot_table( values='val0', index='row', columns='col', fill_value=0, aggfunc=[np.size, np.mean]) size mean col col0 col1 col2 col3 col4 col0 col1 col2 col3 col4 row row0 1 2 0 1 1 0.77 0.605 0.000 0.860 0.65 row2 1 0 2 1 2 0.13 0.000 0.395 0.500 0.25 row3 0 1 0 2 0 0.00 0.310 0.000 0.545 0.00 row4 0 1 2 2 1 0.00 0.100 0.395 0.760 0.24
pd.DataFrame.groupby
df.groupby(['row', 'col'])['val0'].agg(['size', 'mean']).unstack(fill_value=0)
pd.crosstab
pd.crosstab( index=df['row'], columns=df['col'], values=df['val0'], aggfunc=[np.size, np.mean]).fillna(0, downcast='infer')
Domanda 6
Posso aggregare su più colonne di valori?
pd.DataFrame.pivot_table
passiamovalues=['val0', 'val1']
ma avremmo potuto lasciarlo completamente fuoridf.pivot_table( values=['val0', 'val1'], index='row', columns='col', fill_value=0, aggfunc='mean') val0 val1 col col0 col1 col2 col3 col4 col0 col1 col2 col3 col4 row row0 0.77 0.605 0.000 0.860 0.65 0.01 0.745 0.00 0.010 0.02 row2 0.13 0.000 0.395 0.500 0.25 0.45 0.000 0.34 0.440 0.79 row3 0.00 0.310 0.000 0.545 0.00 0.00 0.230 0.00 0.075 0.00 row4 0.00 0.100 0.395 0.760 0.24 0.00 0.070 0.42 0.300 0.46
pd.DataFrame.groupby
df.groupby(['row', 'col'])['val0', 'val1'].mean().unstack(fill_value=0)
Domanda 7
Può suddividere per più colonne?
pd.DataFrame.pivot_table
df.pivot_table( values='val0', index='row', columns=['item', 'col'], fill_value=0, aggfunc='mean') item item0 item1 item2 col col2 col3 col4 col0 col1 col2 col3 col4 col0 col1 col3 col4 row row0 0.00 0.00 0.00 0.77 0.00 0.00 0.00 0.00 0.00 0.605 0.86 0.65 row2 0.35 0.00 0.37 0.00 0.00 0.44 0.00 0.00 0.13 0.000 0.50 0.13 row3 0.00 0.00 0.00 0.00 0.31 0.00 0.81 0.00 0.00 0.000 0.28 0.00 row4 0.15 0.64 0.00 0.00 0.10 0.64 0.88 0.24 0.00 0.000 0.00 0.00
pd.DataFrame.groupby
df.groupby( ['row', 'item', 'col'] )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)
Domanda 8
Può suddividere per più colonne?
pd.DataFrame.pivot_table
df.pivot_table( values='val0', index=['key', 'row'], columns=['item', 'col'], fill_value=0, aggfunc='mean') item item0 item1 item2 col col2 col3 col4 col0 col1 col2 col3 col4 col0 col1 col3 col4 key row key0 row0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.86 0.00 row2 0.00 0.00 0.37 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.50 0.00 row3 0.00 0.00 0.00 0.00 0.31 0.00 0.81 0.00 0.00 0.00 0.00 0.00 row4 0.15 0.64 0.00 0.00 0.00 0.00 0.00 0.24 0.00 0.00 0.00 0.00 key1 row0 0.00 0.00 0.00 0.77 0.00 0.00 0.00 0.00 0.00 0.81 0.00 0.65 row2 0.35 0.00 0.00 0.00 0.00 0.44 0.00 0.00 0.00 0.00 0.00 0.13 row3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.28 0.00 row4 0.00 0.00 0.00 0.00 0.10 0.00 0.00 0.00 0.00 0.00 0.00 0.00 key2 row0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.40 0.00 0.00 row2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.13 0.00 0.00 0.00 row4 0.00 0.00 0.00 0.00 0.00 0.64 0.88 0.00 0.00 0.00 0.00 0.00
pd.DataFrame.groupby
df.groupby( ['key', 'row', 'item', 'col'] )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)
pd.DataFrame.set_index
perché il set di chiavi è unico sia per le righe che per le colonnedf.set_index( ['key', 'row', 'item', 'col'] )['val0'].unstack(['item', 'col']).fillna(0).sort_index(1)
Domanda 9
Posso aggregare la frequenza con cui la colonna e le righe ricorrono insieme, ovvero "tabulazione incrociata"?
pd.DataFrame.pivot_table
df.pivot_table(index='row', columns='col', fill_value=0, aggfunc='size') col col0 col1 col2 col3 col4 row row0 1 2 0 1 1 row2 1 0 2 1 2 row3 0 1 0 2 0 row4 0 1 2 2 1
pd.DataFrame.groupby
df.groupby(['row', 'col'])['val0'].size().unstack(fill_value=0)
pd.crosstab
pd.crosstab(df['row'], df['col'])
pd.factorize
+np.bincount
# get integer factorization `i` and unique values `r` # for column `'row'` i, r = pd.factorize(df['row'].values) # get integer factorization `j` and unique values `c` # for column `'col'` j, c = pd.factorize(df['col'].values) # `n` will be the number of rows # `m` will be the number of columns n, m = r.size, c.size # `i * m + j` is a clever way of counting the # factorization bins assuming a flat array of length # `n * m`. Which is why we subsequently reshape as `(n, m)` b = np.bincount(i * m + j, minlength=n * m).reshape(n, m) # BTW, whenever I read this, I think 'Bean, Rice, and Cheese' pd.DataFrame(b, r, c) col3 col2 col0 col1 col4 row3 2 0 0 1 0 row2 1 2 1 0 2 row0 1 0 1 2 1 row4 2 2 0 1 1
pd.get_dummies
pd.get_dummies(df['row']).T.dot(pd.get_dummies(df['col'])) col0 col1 col2 col3 col4 row0 1 2 0 1 1 row2 1 0 2 1 2 row3 0 1 0 2 0 row4 0 1 2 2 1
Domanda 10
Come posso convertire un DataFrame da lungo a largo ruotando SOLO su due colonne?
Il primo passaggio è assegnare un numero a ciascuna riga: questo numero sarà l'indice di riga di quel valore nel risultato pivot. Questo viene fatto usando GroupBy.cumcount
:
df2.insert(0, 'count', df.groupby('A').cumcount())
df2
count A B
0 0 a 0
1 1 a 11
2 2 a 2
3 3 a 11
4 0 b 10
5 1 b 10
6 2 b 14
7 0 c 7
Il secondo passaggio consiste nell'usare la colonna appena creata come indice da chiamare DataFrame.pivot
.
df2.pivot(*df)
# df.pivot(index='count', columns='A', values='B')
A a b c
count
0 0.0 10.0 7.0
1 11.0 10.0 NaN
2 2.0 14.0 NaN
3 11.0 NaN NaN
Domanda 11
Come appiattisco l'indice multiplo in un indice singolo dopo
pivot
Se columns
digita object
con stringajoin
df.columns = df.columns.map('|'.join)
altro format
df.columns = df.columns.map('{0[0]}|{0[1]}'.format)
Per estendere la risposta di @ piRSquared un'altra versione della domanda 10
Domanda 10.1
DataFrame:
d = data = {'A': {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 3, 6: 5},
'B': {0: 'a', 1: 'b', 2: 'c', 3: 'a', 4: 'b', 5: 'a', 6: 'c'}}
df = pd.DataFrame(d)
A B
0 1 a
1 1 b
2 1 c
3 2 a
4 2 b
5 3 a
6 5 c
Produzione:
0 1 2
A
1 a b c
2 a b None
3 a None None
5 c None None
Utilizzando df.groupby
epd.Series.tolist
t = df.groupby('A')['B'].apply(list)
out = pd.DataFrame(t.tolist(),index=t.index)
out
0 1 2
A
1 a b c
2 a b None
3 a None None
5 c None None
O un'alternativa molto migliore utilizzando pd.pivot_table
condf.squeeze.
t = df.pivot_table(index='A',values='B',aggfunc=list).squeeze()
out = pd.DataFrame(t.tolist(),index=t.index)