Mam ramkę danych z hierarchicznym indeksem w osi 1 (kolumny) (z groupby.agg
operacji):
USAF WBAN year month day s_PC s_CL s_CD s_CNT tempf
sum sum sum sum amax amin
0 702730 26451 1993 1 1 1 0 12 13 30.92 24.98
1 702730 26451 1993 1 2 0 0 13 13 32.00 24.98
2 702730 26451 1993 1 3 1 10 2 13 23.00 6.98
3 702730 26451 1993 1 4 1 0 12 13 10.04 3.92
4 702730 26451 1993 1 5 3 0 10 13 19.94 10.94
Chcę go spłaszczyć, aby wyglądał tak (nazwy nie są krytyczne - mógłbym zmienić nazwę):
USAF WBAN year month day s_PC s_CL s_CD s_CNT tempf_amax tmpf_amin
0 702730 26451 1993 1 1 1 0 12 13 30.92 24.98
1 702730 26451 1993 1 2 0 0 13 13 32.00 24.98
2 702730 26451 1993 1 3 1 10 2 13 23.00 6.98
3 702730 26451 1993 1 4 1 0 12 13 10.04 3.92
4 702730 26451 1993 1 5 3 0 10 13 19.94 10.94
Jak mam to zrobic? (Dużo próbowałem, bezskutecznie.)
Według sugestii, tutaj jest głowa w formie dykta
{('USAF', ''): {0: '702730',
1: '702730',
2: '702730',
3: '702730',
4: '702730'},
('WBAN', ''): {0: '26451', 1: '26451', 2: '26451', 3: '26451', 4: '26451'},
('day', ''): {0: 1, 1: 2, 2: 3, 3: 4, 4: 5},
('month', ''): {0: 1, 1: 1, 2: 1, 3: 1, 4: 1},
('s_CD', 'sum'): {0: 12.0, 1: 13.0, 2: 2.0, 3: 12.0, 4: 10.0},
('s_CL', 'sum'): {0: 0.0, 1: 0.0, 2: 10.0, 3: 0.0, 4: 0.0},
('s_CNT', 'sum'): {0: 13.0, 1: 13.0, 2: 13.0, 3: 13.0, 4: 13.0},
('s_PC', 'sum'): {0: 1.0, 1: 0.0, 2: 1.0, 3: 1.0, 4: 3.0},
('tempf', 'amax'): {0: 30.920000000000002,
1: 32.0,
2: 23.0,
3: 10.039999999999999,
4: 19.939999999999998},
('tempf', 'amin'): {0: 24.98,
1: 24.98,
2: 6.9799999999999969,
3: 3.9199999999999982,
4: 10.940000000000001},
('year', ''): {0: 1993, 1: 1993, 2: 1993, 3: 1993, 4: 1993}}
df[:5].to_dict()
jako przykład, aby inni mogli je odczytać w zestawie danych?pandas
aby zaimplementować do tego dedykowaną metodę.dat.columns = dat.columns.to_flat_index()
. Wbudowana funkcja pand.Odpowiedzi:
Myślę, że najłatwiejszym sposobem jest ustawienie kolumn na najwyższym poziomie:
Uwaga: jeśli poziom do ma nazwę, możesz również uzyskać do niej dostęp, zamiast 0.
.
Jeśli chcesz połączyć /
join
swój MultiIndex w jeden Indeks (zakładając, że masz tylko ciąg znaków w kolumnach), możesz:Uwaga: musimy
strip
wprowadzić białe znaki, gdy nie ma drugiego indeksu.źródło
['_'.join(col).rstrip('_') for col in df.columns.values]
sum s_CD
zamiasts_CD sum
, możesz to zrobićdf.columns = ['_'.join(col).rstrip('_') for col in [c[::-1] for c in df.columns.values]]
.źródło
pd.DataFrame(df.to_records(), columns=df.index.names + list(df.columns))
pd.DataFrame(df_volume.to_records(), index=df_volume.index).drop('index', axis=1)
Wszystkie aktualne odpowiedzi w tym wątku musiały być nieco przestarzałe. Począwszy od
pandas
wersji 0.24.0,.to_flat_index()
robi to, czego potrzebujesz.Z własnej dokumentacji pandy :
Prosty przykład z jego dokumentacji:
Zastosowanie
to_flat_index()
:Używanie go do zastąpienia istniejącej
pandas
kolumnyPrzykład, w jaki sposób będziesz go używać
dat
, czyli DataFrame zMultiIndex
kolumną:źródło
Odpowiedź Andy'ego Haydena jest z pewnością najłatwiejszym sposobem - jeśli chcesz uniknąć powielania etykiet kolumn, musisz trochę ulepszyć
źródło
źródło
A jeśli chcesz zachować informacje o agregacji z drugiego poziomu multiindeksu, możesz spróbować:
źródło
new_cols
nie jest zdefiniowany.Najbardziej pythonowy sposób, aby to zrobić, aby użyć
map
funkcji.Wyjście
print(df.columns)
:Zaktualizuj za pomocą Python 3.6+ z ciągiem f:
Wynik:
źródło
Najłatwiejszym i najbardziej intuicyjnym rozwiązaniem było dla mnie połączenie nazw kolumn za pomocą wartości get_level_values . Zapobiega to duplikowaniu nazw kolumn, gdy wykonujesz więcej niż jedną agregację w tej samej kolumnie:
Jeśli chcesz separator między kolumnami, możesz to zrobić. Zwróci to samo, co komentarz Seiji Armstronga do zaakceptowanej odpowiedzi, który zawiera tylko podkreślenia dla kolumn z wartościami na obu poziomach indeksu:
Wiem, że robi to to samo, co świetna odpowiedź Andy'ego Haydena powyżej, ale myślę, że jest to nieco bardziej intuicyjne i łatwiejsze do zapamiętania (więc nie muszę ciągle odwoływać się do tego wątku), szczególnie dla początkujących użytkowników pand .
Ta metoda jest również bardziej rozszerzalna w przypadku, gdy możesz mieć 3 poziomy kolumn.
źródło
Po przeczytaniu wszystkich odpowiedzi wpadłem na to:
Stosowanie:
Biorąc pod uwagę ramkę danych:
Metoda pojedynczej agregacji : zmienne wynikowe nazwane tak samo jak źródło :
df.groupby(by="grouper",
as_index = False)
lub.agg(...)
.reset_index ()Zmienna z jednego źródła, wiele agregacji : zmienne wynikowe nazwane na podstawie statystyk :
a = df.groupby(..).agg(..); a.columns = a.columns.droplevel(0); a.reset_index()
.Wiele zmiennych, wiele agregacji : zmienne wynikowe o nazwie (varname) _ (statname) :
a.columns = ["_".join(filter(None, map(str, levels))) for levels in a.columns.values]
pod maską (ponieważ ta formaagg()
powodujeMultiIndex
kolumnach).my_flatten_cols
pomocnika, może być łatwiej wpisać rozwiązanie sugerowane przez @Seigi :a.columns = ["_".join(t).rstrip("_") for t in a.columns.values]
, który działa podobnie jak w tym przypadku (ale nie działa, jeśli masz etykiet numerycznych na kolumnach)a.columns = ["_".join(tuple(map(str, t))).rstrip("_") for t in a.columns.values]
), ale nie rozumiem, dlaczegotuple()
wywołanie jest potrzebne i uważam, żerstrip()
jest wymagane tylko wtedy, gdy niektóre kolumny mają deskryptor podobny do("colname", "")
( co może się zdarzyć, jeślireset_index()
przed próbą naprawy.columns
)Chcesz wymienić wynikające zmienne ręcznie: (jest to przestarzała od pand 0.20.0 z braku odpowiedniej alternatywy 0,23 )
res.columns = ['A_sum', 'B_sum', 'count']
lub wprowadzenie.join()
wielugroupby
instrukcji.Przypadki obsługiwane przez funkcję pomocnika
map(str, ..)
filter(None, ..)
columns.values
zwraca nazwy (str
nie krotek).agg()
może być konieczne zachowanie najniższej etykiety kolumny lub połączenie wielu etykietreset_index()
mieć możliwość regularnej pracy z kolumnami grupowania, więc domyślnie tak jestźródło
tuple()
jest to potrzebne, możesz skomentować post jxstanford. W przeciwnym razie może to być pomocne dla kontrolującej.columns.values
w podanym przykładzie:[('val1', 'min'), (2, 'sum'), (2, 'size')]
. 1)for t in a.columns.values
pętle nad kolumnami dla drugiej kolumnyt == (2, 'sum')
; 2)map(str, t)
stosuje sięstr()
do każdego „poziomu”, co powoduje('2', 'sum')
; 3)"_".join(('2','sum'))
wyniki w „2_sum”,Ogólne rozwiązanie, które obsługuje wiele poziomów i typy mieszane:
źródło
df.columns = ['_'.join(tuple(map(str, t))).rstrip('_') for t in df.columns.values]
Może trochę za późno, ale jeśli nie martwisz się o zduplikowane nazwy kolumn:
źródło
(year, )
i(tempf, amax)
Jeśli chcesz mieć w nazwie separator między poziomami, ta funkcja działa dobrze.
źródło
df.columns = ["_".join(filter(None, c)) for c in df.columns]
Po @jxstanford i @ tvt173 napisałem szybką funkcję, która powinna załatwić sprawę, niezależnie od nazw kolumn string / int:
źródło
Możesz także zrobić jak poniżej. Weź pod uwagę
df
ramkę danych i załóż dwupoziomowy indeks (jak w twoim przykładzie)źródło
Podzielę się prostym sposobem, który zadziałał dla mnie.
źródło
Aby spłaszczyć MultiIndex w łańcuchu innych metod DataFrame, zdefiniuj taką funkcję:
Następnie użyj
pipe
metody, aby zastosować tę funkcję w łańcuchu metod DataFrame, przedgroupby
iagg
przed innymi metodami w łańcuchu:źródło
Kolejna prosta rutyna.
źródło