J'ai vu beaucoup de questions concernant les tableaux croisés dynamiques. Même s'ils ne savent pas qu'ils posent des questions sur les tableaux croisés dynamiques, ils le sont généralement. Il est pratiquement impossible d'écrire une question canonique et une réponse englobant tous les aspects du pivotement ....
... Mais je vais essayer.
Le problème avec les questions et réponses existantes est que souvent la question est centrée sur une nuance que le PO a du mal à généraliser afin d’utiliser un certain nombre des bonnes réponses existantes. Cependant, aucune des réponses ne tente de donner une explication complète (car c’est une tâche ardue)
Regardez quelques exemples de mon recherche google
pd.DataFrame.pivot
Ainsi, chaque fois que quelqu'un recherche pivot
, il obtient des résultats sporadiques qui ne vont probablement pas répondre à leur question spécifique.
Vous remarquerez peut-être que j'ai clairement nommé mes colonnes et les valeurs de colonne correspondantes pour qu'elles correspondent à la manière dont je vais faire pivoter les réponses ci-dessous. Faites attention afin de vous familiariser avec les noms des colonnes et les résultats recherchés.
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
Pourquoi ai-je ValueError: Index contains duplicate entries, cannot reshape
Comment faire pivoter df
pour que les valeurs col
soient des colonnes, row
, les valeurs d'indice et la moyenne de val0
, sont les valeurs?
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
Comment pivoter df
de sorte que les valeurs col
soient des colonnes, row
, les valeurs d'index, la moyenne de val0
sont les valeurs et les valeurs manquantes sont 0
?
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
Puis-je obtenir autre chose que mean
, comme peut-être 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
Puis-je faire plus qu'une agrégation à la fois?
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
Puis-je agréger plusieurs colonnes de valeurs?
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
Peut-on subdiviser en plusieurs colonnes?
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
Ou
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
Puis-je agréger la fréquence à laquelle la colonne et les lignes apparaissent ensemble, ou "tabulation croisée"?
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
Comment convertir un DataFrame de long en large en faisant pivoter SEULEMENT deux colonnes? Donné,
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'attendu devrait ressembler à quelque chose comme
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
Comment puis-je aplatir l'index multiple en index unique après pivot
De
1 2
1 1 2
a 2 1 1
b 2 1 0
c 1 0 0
À
1|1 2|1 2|2
a 2 1 1
b 2 1 0
c 1 0 0
Nous commençons par répondre à la première question:
Pourquoi ai-je _
ValueError: Index contains duplicate entries, cannot reshape
_
Cela se produit parce que pandas tente de réindexer un objet columns
ou index
avec des entrées en double. Il existe différentes méthodes à utiliser pouvant effectuer un pivot. Certaines d’entre elles ne conviennent pas aux duplicata des clés sur lesquelles il est demandé de pivoter. Par exemple. Considérons _pd.DataFrame.pivot
_. Je sais qu'il existe des entrées en double partageant les valeurs row
et col
:
_df.duplicated(['row', 'col']).any()
True
_
Alors, quand je pivot
utiliser
_df.pivot(index='row', columns='col', values='val0')
_
Je reçois l'erreur mentionnée ci-dessus. En fait, j'obtiens la même erreur lorsque j'essaie d'exécuter la même tâche avec:
_df.set_index(['row', 'col'])['val0'].unstack()
_
Voici une liste des idiomes que nous pouvons utiliser pour faire pivoter
pd.DataFrame.groupby
+ pd.DataFrame.unstack
unstack
les niveaux que vous souhaitez voir figurer dans l'index de la colonne.pd.DataFrame.pivot_table
groupby
avec une API plus intuitive. Pour beaucoup de gens, c'est l'approche privilégiée. Et est l'approche prévue par les développeurs.pd.DataFrame.set_index
+ pd.DataFrame.unstack
groupby
, nous spécifions toutes les colonnes qui seront éventuellement des niveaux de ligne ou de colonne et nous les définissons comme étant l'index. Nous avons ensuite unstack
les niveaux que nous voulons dans les colonnes. Si les niveaux d'index ou de colonne restants ne sont pas uniques, cette méthode échouera.pd.DataFrame.pivot
set_index
_ en ce sens qu'il partage la limitation de clé en double. L'API est également très limité. Seules les valeurs scalaires pour index
, columns
, values
sont prises en compte.pivot_table
_ en ce sens que nous sélectionnons des lignes, des colonnes et des valeurs sur lesquelles faire pivoter. Cependant, nous ne pouvons pas agréger et si les lignes ou les colonnes ne sont pas uniques, cette méthode échouera.pd.crosstab
pivot_table
_ et dans sa forme la plus pure est le moyen le plus intuitif d’exécuter plusieurs tâches.pd.factorize
+ np.bincount
pd.get_dummies
+ pd.DataFrame.dot
Ce que je vais faire pour chaque réponse et question suivante est d'y répondre en utilisant _pd.DataFrame.pivot_table
_. Ensuite, je proposerai des alternatives pour effectuer la même tâche.
Comment pivoter
df
de sorte que les valeurscol
soient des colonnes,row
, les valeurs sont l'index, la moyenne de _val0
_ sont les valeurs et les valeurs manquantes sont _0
_?
_pd.DataFrame.pivot_table
_
fill_value
_ n'est pas défini par défaut. J'ai tendance à le définir correctement. Dans ce cas, je le règle sur _0
_. Remarquez que j'ai sauté la question 2 car c'est la même chose que cette réponse sans le _fill_value
__aggfunc='mean'
_ est la valeur par défaut et je n'ai pas eu à le définir. Je l'ai inclus pour être explicite.
_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)
_
Puis-je obtenir autre chose que
mean
, comme peut-êtresum
?
_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)
_
Puis-je faire plus qu'une agrégation à la fois?
Notez que pour _pivot_table
_ et _cross_tab
_, je devais passer la liste des callables. Par contre, _groupby.agg
_ peut prendre des chaînes pour un nombre limité de fonctions spéciales. _groupby.agg
_ aurait également pris les mêmes callables que nous avons passés aux autres, mais il est souvent plus efficace de tirer parti des noms de fonction de chaîne car il est possible de gagner en efficacité.
_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')
_
Puis-je agréger plusieurs colonnes de valeurs?
_pd.DataFrame.pivot_table
_ nous passons _values=['val0', 'val1']
_ mais nous aurions pu laisser cela complètement
_df.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)
_
Peut-on subdiviser en plusieurs colonnes?
_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)
_
Peut-on subdiviser en plusieurs colonnes?
_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
_ car le jeu de clés est unique pour les lignes et les colonnes
_df.set_index(
['key', 'row', 'item', 'col']
)['val0'].unstack(['item', 'col']).fillna(0).sort_index(1)
_
Puis-je agréger la fréquence à laquelle la colonne et les lignes apparaissent ensemble, ou "tabulation croisée"?
_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.cross_tab
_
_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
_
Comment convertir un DataFrame de long en large en faisant pivoter SEULEMENT deux colonnes?
La première étape consiste à attribuer un numéro à chaque ligne. Ce numéro correspond à l'index de ligne de cette valeur dans le résultat pivoté. Ceci est fait en utilisant 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
_
Comment puis-je aplatir l'index multiple en index unique après
pivot
Si columns
tapez object
avec la chaîne join
_df.columns = df.columns.map('|'.join)
_
sinon format
_df.columns = df.columns.map('{0[0]}|{0[1]}'.format)
_