Jak obrócić ramkę danych?
- Co to jest Pivot?
- Jak się obracać?
- Czy to jest osie?
- Od długiego do szerokiego formatu?
Widziałem wiele pytań dotyczących tabel przestawnych. Nawet jeśli nie wiedzą, że pytają o tabele przestawne, zwykle tak jest. Praktycznie niemożliwe jest napisanie kanonicznego pytania i odpowiedzi, które obejmowałyby wszystkie aspekty obracania ...
... Ale spróbuję.
Problem z istniejącymi pytaniami i odpowiedziami polega na tym, że często pytanie koncentruje się na niuansie, który PO ma problem z uogólnieniem w celu wykorzystania wielu istniejących dobrych odpowiedzi. Jednak żadna z odpowiedzi nie jest próbą wyczerpującego wyjaśnienia (ponieważ jest to trudne zadanie)
Spójrz na kilka przykładów z mojej wyszukiwarki Google
- Dobre pytanie i odpowiedź. Ale odpowiedź odpowiada tylko na konkretne pytanie bez wyjaśnienia.
- W tym pytaniu PO dotyczy wyników pivotu. Mianowicie, jak wyglądają kolumny. OP chciał, żeby wyglądał jak R. Nie jest to zbyt pomocne dla użytkowników pand.
- Kolejne przyzwoite pytanie, ale odpowiedź skupia się na jednej metodzie, a mianowicie
pd.DataFrame.pivot
pivot
Kiedy więc ktoś wyszukuje , otrzymuje sporadyczne wyniki, które prawdopodobnie nie odpowiedzą na jego konkretne pytanie.
Ustawiać
Możesz zauważyć, że wyraźnie nazwałam swoje kolumny i odpowiednie wartości kolumn, aby odpowiadały temu, jak zamierzam przestawić się w odpowiedziach poniżej.
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
Pytania)
Dlaczego dostaję
ValueError: Index contains duplicate entries, cannot reshape
Jak przestawić
df
tak, abycol
wartości były kolumnami,row
wartościami indeksami, a średniąval0
wartościami?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
Jak przestawić
df
tak, abycol
wartości były kolumnami,row
wartościami były indeks, średnieval0
wartości i brakujące wartości0
?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
Czy mogę dostać coś innego niż
mean
możesum
?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
Czy mogę zrobić więcej niż jedną agregację naraz?
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
Czy mogę agregować w wielu kolumnach wartości?
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
Czy można podzielić przez wiele kolumn?
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
Lub
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
Czy mogę zagregować częstotliwość, z jaką kolumna i wiersze występują razem, czyli „krzyżowe zestawianie”?
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
Jak przekonwertować ramkę DataFrame z długiej na szeroką, obracając TYLKO dwie kolumny? Dany,
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
Oczekiwany powinien wyglądać mniej więcej tak
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
Jak spłaszczyć wiele indeksów do jednego indeksu po
pivot
Z
1 2 1 1 2 a 2 1 1 b 2 1 0 c 1 0 0
Do
1|1 2|1 2|2 a 2 1 1 b 2 1 0 c 1 0 0
Odpowiedzi
Rozpoczynamy od odpowiedzi na pierwsze pytanie:
Pytanie 1
Dlaczego dostaję
ValueError: Index contains duplicate entries, cannot reshape
Dzieje się tak, ponieważ pandy próbują ponownie zindeksować obiekt columns
lub index
ze zduplikowanymi wpisami. Istnieją różne metody, których można użyć, aby wykonać zwrot. Niektóre z nich nie nadają się dobrze, gdy istnieją duplikaty kluczy, w których ma się obracać. Na przykład. Rozważ pd.DataFrame.pivot
. Wiem, że istnieją zduplikowane wpisy, które mają wspólne wartości row
i col
:
df.duplicated(['row', 'col']).any()
True
Więc kiedy pivot
używam
df.pivot(index='row', columns='col', values='val0')
Pojawia się błąd wspomniany powyżej. W rzeczywistości pojawia się ten sam błąd, gdy próbuję wykonać to samo zadanie z:
df.set_index(['row', 'col'])['val0'].unstack()
Oto lista idiomów, których możemy użyć do zmiany
pd.DataFrame.groupby
+pd.DataFrame.unstack
- Dobre ogólne podejście do wykonywania prawie każdego rodzaju obrotu
- Należy określić wszystkie kolumny, które będą stanowić przestawione poziomy wierszy i poziomy kolumn w jednej grupie według. Postępujesz zgodnie z tym, wybierając pozostałe kolumny, które chcesz agregować, i funkcje, które chcesz wykonać agregację. Wreszcie
unstack
poziomy, które chcesz znaleźć w indeksie kolumny.
pd.DataFrame.pivot_table
- Ulepszona wersja
groupby
z bardziej intuicyjnym interfejsem API. Dla wielu osób jest to preferowane podejście. I jest to zamierzone podejście twórców. - Określ poziom wiersza, poziomy kolumn, wartości do agregacji i funkcje do wykonywania agregacji.
- Ulepszona wersja
pd.DataFrame.set_index
+pd.DataFrame.unstack
- Wygodny i intuicyjny dla niektórych (łącznie ze mną). Nie można obsłużyć zduplikowanych kluczy zgrupowanych.
- Podobnie jak w przypadku
groupby
paradygmatu, określamy wszystkie kolumny, które ostatecznie będą miały poziom wierszy lub kolumn, i ustawiamy je jako indeks. Następnieunstack
mamy poziomy, które chcemy w kolumnach. Jeśli pozostałe poziomy indeksu lub poziomy kolumn nie są unikatowe, ta metoda zakończy się niepowodzeniem.
pd.DataFrame.pivot
- Bardzo podobny do
set_index
tego, że ma wspólne ograniczenie dotyczące duplikatów klucza. API jest również bardzo ograniczone. To trwa tylko wartości skalarne dlaindex
,columns
,values
. - Podobnie jak w przypadku
pivot_table
metody, w której wybieramy wiersze, kolumny i wartości, na których ma się obracać. Nie możemy jednak agregować i jeśli wiersze lub kolumny nie są unikalne, ta metoda zakończy się niepowodzeniem.
- Bardzo podobny do
pd.crosstab
- To wyspecjalizowana wersja
pivot_table
i w najczystszej formie jest najbardziej intuicyjnym sposobem wykonywania kilku zadań.
- To wyspecjalizowana wersja
pd.factorize
+np.bincount
- Jest to bardzo zaawansowana technika, bardzo mało znana, ale bardzo szybka. Nie można go używać w każdych okolicznościach, ale jeśli będzie można go używać i będzie Ci wygodnie z niego korzystać, otrzymasz nagrody za wydajność.
pd.get_dummies
+pd.DataFrame.dot
- Używam tego do sprytnych zestawień krzyżowych.
Przykłady
Dla każdej kolejnej odpowiedzi i pytania zamierzam odpowiedzieć za pomocą pd.DataFrame.pivot_table
. Następnie przedstawię alternatywy do wykonania tego samego zadania.
pytanie 3
Jak przestawić
df
tak, abycol
wartości były kolumnami,row
wartościami były indeks, średnieval0
wartości i brakujące wartości0
?
pd.DataFrame.pivot_table
fill_value
nie jest ustawiony domyślnie. Zwykle ustawiam to odpowiednio. W tym przypadku ustawiłem na0
. Zauważ, że pominąłem pytanie 2, ponieważ jest takie samo jak ta odpowiedź bezfill_value
aggfunc='mean'
jest ustawieniem domyślnym i nie musiałem go ustawiać. Załączam to, aby było jasne.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)
Pytanie 4
Czy mogę dostać coś innego niż
mean
możesum
?
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)
Pytanie 5
Czy mogę zrobić więcej niż jedną agregację naraz?
Zauważ, że dla pivot_table
i crosstab
musiałem przekazać listę wywołań. Z drugiej strony groupby.agg
może przyjmować ciągi znaków dla ograniczonej liczby funkcji specjalnych. groupby.agg
wziąłby również te same wywołania, które przekazaliśmy innym, ale często bardziej efektywne jest wykorzystanie nazw funkcji łańcuchowych, ponieważ istnieją wydajności do uzyskania.
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')
Pytanie 6
Czy mogę agregować w wielu kolumnach wartości?
pd.DataFrame.pivot_table
zdajemy,values=['val0', 'val1']
ale mogliśmy to całkowicie pominąć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)
Pytanie 7
Czy można podzielić przez wiele kolumn?
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)
Pytanie 8
Czy można podzielić przez wiele kolumn?
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
ponieważ zestaw kluczy jest unikalny dla wierszy i kolumndf.set_index( ['key', 'row', 'item', 'col'] )['val0'].unstack(['item', 'col']).fillna(0).sort_index(1)
Pytanie 9
Czy mogę zagregować częstotliwość, z jaką kolumna i wiersze występują razem, czyli „krzyżowe zestawianie”?
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
Pytanie 10
Jak przekonwertować ramkę DataFrame z długiej na szeroką, obracając TYLKO dwie kolumny?
Pierwszym krokiem jest przypisanie liczby do każdego wiersza - ta liczba będzie indeksem wiersza o tej wartości w przestawionym wyniku. Odbywa się to za pomocą 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
Drugim krokiem jest użycie nowo utworzonej kolumny jako indeksu do wywołania 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
Pytanie 11
Jak spłaszczyć wiele indeksów do jednego indeksu po
pivot
Jeśli columns
wpisz object
ciągjoin
df.columns = df.columns.map('|'.join)
jeszcze format
df.columns = df.columns.map('{0[0]}|{0[1]}'.format)
Aby rozszerzyć odpowiedź @ piRSquared o kolejną wersję pytania 10
Pytanie 10.1
Ramka danych:
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
Wynik:
0 1 2
A
1 a b c
2 a b None
3 a None None
5 c None None
Korzystanie df.groupby
ipd.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
Lub znacznie lepsza alternatywa używania pd.pivot_table
zdf.squeeze.
t = df.pivot_table(index='A',values='B',aggfunc=list).squeeze()
out = pd.DataFrame(t.tolist(),index=t.index)