Nazywanie zwracanych kolumn w funkcji agregatowej? [duplikat]
Jest to bardzo zbliżone, ale zwracana struktura danych ma zagnieżdżone nagłówki kolumn:
data.groupby("Country").agg(
{"column1": {"foo": sum()}, "column2": {"mean": np.mean, "std": np.std}})
(tj. Chcę wziąć mean I std column2, ale zwróć te kolumny jako "mean" I "std")
Co mi umyka?
6 answers
Spowoduje to spadek zewnętrznego poziomu z indeksu hierarchicznej kolumny:
df = data.groupby(...).agg(...)
df.columns = df.columns.droplevel(0)
Jeśli chcesz zachować najbardziej zewnętrzny poziom, możesz użyć funkcji ravel () na wielopoziomowej kolumnie, aby utworzyć nowe etykiety:
df.columns = ["_".join(x) for x in df.columns.ravel()]
Na przykład:
import pandas as pd
import pandas.rpy.common as com
import numpy as np
data = com.load_data('Loblolly')
print(data.head())
# height age Seed
# 1 4.51 3 301
# 15 10.89 5 301
# 29 28.72 10 301
# 43 41.74 15 301
# 57 52.70 20 301
df = data.groupby('Seed').agg(
{'age':['sum'],
'height':['mean', 'std']})
print(df.head())
# age height
# sum std mean
# Seed
# 301 78 22.638417 33.246667
# 303 78 23.499706 34.106667
# 305 78 23.927090 35.115000
# 307 78 22.222266 31.328333
# 309 78 23.132574 33.781667
df.columns = df.columns.droplevel(0)
print(df.head())
sum std mean
Seed
301 78 22.638417 33.246667
303 78 23.499706 34.106667
305 78 23.927090 35.115000
307 78 22.222266 31.328333
309 78 23.132574 33.781667
Alternatywnie, aby zachować pierwszy poziom indeksu:
df = data.groupby('Seed').agg(
{'age':['sum'],
'height':['mean', 'std']})
df.columns = ["_".join(x) for x in df.columns.ravel()]
age_sum height_std height_mean
Seed
301 78 22.638417 33.246667
303 78 23.499706 34.106667
305 78 23.927090 35.115000
307 78 22.222266 31.328333
309 78 23.132574 33.781667
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-30 08:56:23
Dla pand >= 0,25
Funkcja nazw zwracanych kolumn zbiorczych została ponownie wprowadzona w gałęzi master i jest przeznaczona dla pand 0.25. Nowa składnia to .agg(new_col_name=('col_name', 'agg_func')
. Szczegółowy przykład z PR linkowanego powyżej:
In [2]: df = pd.DataFrame({'kind': ['cat', 'dog', 'cat', 'dog'],
...: 'height': [9.1, 6.0, 9.5, 34.0],
...: 'weight': [7.9, 7.5, 9.9, 198.0]})
...:
In [3]: df
Out[3]:
kind height weight
0 cat 9.1 7.9
1 dog 6.0 7.5
2 cat 9.5 9.9
3 dog 34.0 198.0
In [4]: df.groupby('kind').agg(min_height=('height', 'min'),
max_weight=('weight', 'max'))
Out[4]:
min_height max_weight
kind
cat 9.1 9.9
dog 6.0 198.0
Będzie również możliwe użycie wielu wyrażeń lambda z tą składnią i dwuetapową zmianą nazwy składni, którą zaproponowałem wcześniej (poniżej) zgodnie z this PR. Ponownie kopiowanie z przykładu w PR:
In [2]: df = pd.DataFrame({"A": ['a', 'a'], 'B': [1, 2], 'C': [3, 4]})
In [3]: df.groupby("A").agg({'B': [lambda x: 0, lambda x: 1]})
Out[3]:
B
<lambda> <lambda 1>
A
a 0 1
A następnie .rename()
, lub za jednym razem:
In [4]: df.groupby("A").agg(b=('B', lambda x: 0), c=('B', lambda x: 1))
Out[4]:
b c
A
a 0 0
Dla pand
Obecnie akceptowana odpowiedź przez unutbu opisuje to świetny sposób na zrobienie tego w wersjach pand
Seria:
FutureWarning: używanie dict na Serii do agregacji jest przestarzałe i zostanie usunięte w future version
DataFrames:
FutureWarning: używanie dict ze zmianą nazwy jest przestarzałe i zostanie usunięte w przyszłej wersji
Zgodnie z pandas 0.20 changelog , zalecany sposób zmiany nazw kolumn podczas agregowania jest następujący.
# Create a sample data frame
df = pd.DataFrame({'A': [1, 1, 1, 2, 2],
'B': range(5),
'C': range(5)})
# ==== SINGLE COLUMN (SERIES) ====
# Syntax soon to be deprecated
df.groupby('A').B.agg({'foo': 'count'})
# Recommended replacement syntax
df.groupby('A').B.agg(['count']).rename(columns={'count': 'foo'})
# ==== MULTI COLUMN ====
# Syntax soon to be deprecated
df.groupby('A').agg({'B': {'foo': 'sum'}, 'C': {'bar': 'min'}})
# Recommended replacement syntax
df.groupby('A').agg({'B': 'sum', 'C': 'min'}).rename(columns={'B': 'foo', 'C': 'bar'})
# As the recommended syntax is more verbose, parentheses can
# be used to introduce line breaks and increase readability
(df.groupby('A')
.agg({'B': 'sum', 'C': 'min'})
.rename(columns={'B': 'foo', 'C': 'bar'})
)
Zobacz 0.20 changelog aby uzyskać dodatkowe informacje.
[53]}Aktualizacja 2017-01-03 w odpowiedzi na komentarz @JunkMechanic.W starym stylu składnia słownika, możliwe było przekazanie wielu funkcji {[10] } do .agg
, ponieważ nazwy te byłyby zmieniane za pomocą klucza w przekazywanym słowniku:
>>> df.groupby('A').agg({'B': {'min': lambda x: x.min(), 'max': lambda x: x.max()}})
B
max min
A
1 2 0
2 4 3
Wiele funkcji może być również przekazywanych do jednej kolumny jako lista:
>>> df.groupby('A').agg({'B': [np.min, np.max]})
B
amin amax
A
1 0 2
2 3 4
Nie działa to jednak z funkcjami lambda, ponieważ są one anonimowe i wszystkie zwracają <lambda>
, co powoduje kolizję nazw: {]}
>>> df.groupby('A').agg({'B': [lambda x: x.min(), lambda x: x.max]})
SpecificationError: Function names must be unique, found multiple named <lambda>
Aby uniknąć SpecificationError
, nazwane funkcje mogą być zdefiniowane a priori zamiast lambda
. Odpowiednie nazwy funkcji również unikają wywoływania .rename
w ramce danych. Funkcje te mogą być przekazywane z tą samą składnią listy jak powyżej:
>>> def my_min(x):
>>> return x.min()
>>> def my_max(x):
>>> return x.max()
>>> df.groupby('A').agg({'B': [my_min, my_max]})
B
my_min my_max
A
1 0 2
2 3 4
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-04 23:02:16
Zgadzam się z OP, że bardziej naturalne i spójne wydaje się nazywanie i definiowanie kolumn wyjściowych w tym samym miejscu( np. jak to jest zrobione z tidyverse summarize
W R ), ale obejściem w pandach na razie jest tworzenie nowych kolumn z żądanymi nazwami poprzez assign
przed wykonaniem agregacji:
data.assign(
f=data['column1'],
mean=data['column2'],
std=data['column2']
).groupby('Country').agg(dict(f=sum, mean=np.mean, std=np.std)).reset_index()
(za pomocą reset_index
zakręty 'Country'
, 'f'
, 'mean'
, i 'std'
wszystkie w regularne kolumny z oddzielnym indeksem całkowitym.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-27 14:54:26
Jeśli chcesz mieć zachowanie podobne do JMP, Utwórz tytuły kolumn, które przechowują wszystkie informacje z wielu indeksów, których możesz użyć:
newidx = []
for (n1,n2) in df.columns.ravel():
newidx.append("%s-%s" % (n1,n2))
df.columns=newidx
Zmieni ramkę danych z:
I V
mean std first
V
4200.0 25.499536 31.557133 4200.0
4300.0 25.605662 31.678046 4300.0
4400.0 26.679005 32.919996 4400.0
4500.0 26.786458 32.811633 4500.0
Do
I-mean I-std V-first
V
4200.0 25.499536 31.557133 4200.0
4300.0 25.605662 31.678046 4300.0
4400.0 26.679005 32.919996 4400.0
4500.0 26.786458 32.811633 4500.0
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-20 12:29:02
Takie jak ten rodzaj ramki danych, istnieją dwa poziomy nazwy kolumny:
shop_id item_id date_block_num item_cnt_day
target
0 0 30 1 31
Możemy użyć tego kodu:
df.columns = [col[0] if col[-1]=='' else col[-1] for col in df.columns.values]
Wynik to:
shop_id item_id date_block_num target
0 0 30 1 31
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-05 10:53:13
Z inspiracji @ Joel Ostblom
Dla tych, którzy mają już wykonalny słownik służący jedynie do agregacji, możesz użyć / zmodyfikować poniższy kod dla agregacji nowszej wersji, oddzielając agregację i zmieniając nazwę części. Należy pamiętać o zagnieżdżonym słowniku, jeśli jest więcej niż 1 pozycja.
def agg_translate_agg_rename(input_agg_dict):
agg_dict = {}
rename_dict = {}
for k, v in input_agg_dict.items():
if len(v) == 1:
agg_dict[k] = list(v.values())[0]
rename_dict[k] = list(v.keys())[0]
else:
updated_index = 1
for nested_dict_k, nested_dict_v in v.items():
modified_key = k + "_" + str(updated_index)
agg_dict[modified_key] = nested_dict_v
rename_dict[modified_key] = nested_dict_k
updated_index += 1
return agg_dict, rename_dict
one_dict = {"column1": {"foo": 'sum'}, "column2": {"mean": 'mean', "std": 'std'}}
agg, rename = agg_translator_aa(one_dict)
Otrzymujemy
agg = {'column1': 'sum', 'column2_1': 'mean', 'column2_2': 'std'}
rename = {'column1': 'foo', 'column2_1': 'mean', 'column2_2': 'std'}
Proszę dać mi znać, jeśli jest mądrzejszy sposób, aby to zrobić. Dzięki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-08 01:26:51