Pandas 집계 함수에서 반환 된 열의 이름을 지정 하시겠습니까?
이 질문에 이미 답변이 있습니다.
Pandas의 groupby 기능에 문제가 있습니다. 내가 읽은 문서를 ,하지만 난 여러 컬럼에 집계 함수를 적용하는 방법을 알아 내기 위해 볼 수 와 그 열에 대한 사용자 정의 이름이 있습니다.
이것은 매우 비슷하지만 반환 된 데이터 구조에는 중첩 된 열 제목이 있습니다.
data.groupby("Country").agg(
{"column1": {"foo": sum()}, "column2": {"mean": np.mean, "std": np.std}})
(예 : column2의 평균과 표준을 취하고 싶지만 해당 열을 "평균"및 "표준"으로 반환)
내가 무엇을 놓치고 있습니까?
이렇게하면 계층 열 인덱스에서 가장 바깥 쪽 수준이 삭제됩니다.
df = data.groupby(...).agg(...)
df.columns = df.columns.droplevel(0)
가장 바깥 쪽 수준을 유지하려면 다중 수준 열에서 ravel () 함수를 사용하여 새 레이블을 만들 수 있습니다.
df.columns = ["_".join(x) for x in df.columns.ravel()]
예를 들면 :
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
또는 색인의 첫 번째 레벨을 유지하려면 다음을 수행하십시오.
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
판다> = 0.25
반환 된 집계 열의 이름을 지정하는 기능 은 master 브랜치에서 다시 도입되었으며 Pandas 0.25를 대상으로합니다. 새로운 구문은 .agg(new_col_name=('col_name', 'agg_func')
입니다. 위에 링크 된 PR의 자세한 예 :
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
이 구문 과이 PR에 따라 이전에 제안한 2 단계 이름 바꾸기 구문 (아래)을 사용하여 여러 람다 식을 사용할 수도 있습니다 . 다시 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
그런 다음 .rename()
또는 한 번에 :
In [4]: df.groupby("A").agg(b=('B', lambda x: 0), c=('B', lambda x: 1))
Out[4]:
b c
A
a 0 0
판다 <0.25
unutbu에서 현재 받아 들여지는 답변은 pandas 버전 <= 0.20에서 이것을 수행하는 좋은 방법입니다. 그러나 Pandas 0.20부터이 메서드를 사용하면 이후 버전의 Pandas에서 구문을 사용할 수 없다는 경고가 발생합니다.
시리즈:
FutureWarning : 집계를 위해 Series에서 dict를 사용하는 것은 더 이상 사용되지 않으며 향후 버전에서 제거됩니다.
데이터 프레임 :
FutureWarning : dict를 이름 변경과 함께 사용하는 것은 더 이상 사용되지 않으며 향후 버전에서 제거됩니다.
Pandas 0.20 changelog 에 따르면 집계하는 동안 열 이름을 바꾸는 권장 방법은 다음과 같습니다.
# 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'})
)
자세한 내용은 0.20 변경 로그 를 참조하십시오.
@JunkMechanic의 의견에 대한 응답으로 2017-01-03을 업데이트하십시오.
With the old style dictionary syntax, it was possible to pass multiple lambda
functions to .agg
, since these would be renamed with the key in the passed dictionary:
>>> 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
Multiple functions can also be passed to a single column as a list:
>>> df.groupby('A').agg({'B': [np.min, np.max]})
B
amin amax
A
1 0 2
2 3 4
However, this does not work with lambda functions, since they are anonymous and all return <lambda>
, which causes a name collision:
>>> df.groupby('A').agg({'B': [lambda x: x.min(), lambda x: x.max]})
SpecificationError: Function names must be unique, found multiple named <lambda>
To avoid the SpecificationError
, named functions can be defined a priori instead of using lambda
. Suitable function names also avoid calling .rename
on the data frame afterwards. These functions can be passed with the same list syntax as above:
>>> 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
If you want to have a behavior similar to JMP, creating column titles that keep all info from the multi index you can use:
newidx = []
for (n1,n2) in df.columns.ravel():
newidx.append("%s-%s" % (n1,n2))
df.columns=newidx
It will change your dataframe from:
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
to
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
I agree with the OP that it seems more natural and consistent to name and define the output columns in the same place (e.g. as is done with tidyverse's summarize
in R), but a work-around in pandas for now is to create the new columns with desired names via assign
before doing the aggregation:
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()
(Using reset_index
turns 'Country'
, 'f'
, 'mean'
, and 'std'
all into regular columns with a separate integer index.)
With the inspiration of @Joel Ostblom
For those who already have a workable dictionary for merely aggregation, you can use/modify the following code for the newer version aggregation, separating aggregation and renaming part. Please be aware of the nested dictionary if there are more than 1 item.
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)
We get
agg = {'column1': 'sum', 'column2_1': 'mean', 'column2_2': 'std'}
rename = {'column1': 'foo', 'column2_1': 'mean', 'column2_2': 'std'}
Please let me know if there is a smarter way to do it. Thanks.
such as this kind of dataframe, there are two levels of thecolumn name:
shop_id item_id date_block_num item_cnt_day
target
0 0 30 1 31
we can use this code:
df.columns = [col[0] if col[-1]=='' else col[-1] for col in df.columns.values]
result is:
shop_id item_id date_block_num target
0 0 30 1 31
참고URL : https://stackoverflow.com/questions/19078325/naming-returned-columns-in-pandas-aggregate-function
'Programing' 카테고리의 다른 글
어레이의 중복 여부를 어떻게 확인합니까? (0) | 2020.11.10 |
---|---|
오류 : psycopg2.extensions라는 모듈이 없습니다. (0) | 2020.11.10 |
/ login을 제외한 모든 경로 포착 (0) | 2020.11.10 |
Bash에서 재귀 적으로 파일 확장자 변경 (0) | 2020.11.10 |
C ++ 템플릿에서 유형의 이름 가져 오기 (0) | 2020.11.10 |