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 reshapeCome faccio a ruotare in modo
dftale che icolvalori siano colonne, irowvalori siano l'indice e la mediaval0siano 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.24Come faccio a ruotare in modo
dftale che icolvalori siano colonne, irowvalori siano l'indice, la media deival0valori 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.24Posso 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.24Posso 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.24Posso 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.46Può 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.00O
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.00Posso 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 1Come 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 7L'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 NaNCome appiattisco l'indice multiplo in un indice singolo dopo
pivotA partire dal
1 2 1 1 2 a 2 1 1 b 2 1 0 c 1 0 0Per
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 columnso indexcon 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 rowe col:
df.duplicated(['row', 'col']).any()
True
Quindi quando pivotuso
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,
unstacki livelli che vuoi essere nell'indice della colonna.
pd.DataFrame.pivot_table- Una versione glorificata di
groupbycon 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
groupbyparadigma, specifichiamo tutte le colonne che alla fine saranno livelli di riga o di colonna e le impostiamo come indice. Abbiamo quindiunstacki 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_indexin quanto condivide la limitazione della chiave duplicata. Anche l'API è molto limitata. Si richiede solo valori scalari perindex,columns,values. - Simile al
pivot_tablemetodo 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_tablee 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
dftale che icolvalori siano colonne, irowvalori siano l'indice, la media deival0valori e i valori mancanti siano0?
pd.DataFrame.pivot_tablefill_valuenon è 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_valueaggfunc='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.groupbydf.groupby(['row', 'col'])['val0'].mean().unstack(fill_value=0)pd.crosstabpd.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_tabledf.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.24pd.DataFrame.groupbydf.groupby(['row', 'col'])['val0'].sum().unstack(fill_value=0)pd.crosstabpd.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_tablee crosstabavevo 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.aggavrebbe 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_tabledf.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.24pd.DataFrame.groupbydf.groupby(['row', 'col'])['val0'].agg(['size', 'mean']).unstack(fill_value=0)pd.crosstabpd.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_tablepassiamovalues=['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.46pd.DataFrame.groupbydf.groupby(['row', 'col'])['val0', 'val1'].mean().unstack(fill_value=0)
Domanda 7
Può suddividere per più colonne?
pd.DataFrame.pivot_tabledf.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.00pd.DataFrame.groupbydf.groupby( ['row', 'item', 'col'] )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)
Domanda 8
Può suddividere per più colonne?
pd.DataFrame.pivot_tabledf.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.00pd.DataFrame.groupbydf.groupby( ['key', 'row', 'item', 'col'] )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)pd.DataFrame.set_indexperché 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_tabledf.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 1pd.DataFrame.groupbydf.groupby(['row', 'col'])['val0'].size().unstack(fill_value=0)pd.crosstabpd.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 1pd.get_dummiespd.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 columnsdigita objectcon 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.groupbyepd.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_tablecondf.squeeze.
t = df.pivot_table(index='A',values='B',aggfunc=list).squeeze()
out = pd.DataFrame(t.tolist(),index=t.index)