이 문서 는 출력 열 이름을 키로 사용하는 dict를 사용하여 한 번에 groupby 객체에 여러 기능을 적용하는 방법을 보여줍니다.
In [563]: grouped['D'].agg({'result1' : np.sum,
.....: 'result2' : np.mean})
.....:
Out[563]:
result2 result1
A
bar -0.579846 -1.739537
foo -0.280588 -1.402938
그러나 이것은 Series groupby 객체에서만 작동합니다. 또한 dict이 DataFrame에 의해 그룹으로 유사하게 전달되면 키가 함수가 적용되는 열 이름이 될 것으로 예상합니다.
내가하고 싶은 것은 여러 열에 여러 기능을 적용하는 것입니다 (그러나 특정 열은 여러 번 운영됩니다). 또한 일부 함수는 sumby 함수와 같은 groupby 객체의 다른 열에 따라 다릅니다 . 내 현재 솔루션은 열별로 이동하고 다른 행에 의존하는 함수에 람다를 사용하여 위의 코드와 같은 작업을 수행하는 것입니다. 그러나 이것은 오랜 시간이 걸립니다 (그룹 별 객체를 반복하는 데 시간이 오래 걸린다고 생각합니다). 한 번의 실행으로 전체 그룹 별 객체를 반복하도록 변경해야하지만 팬더에이를 깨끗하게 수행하는 방법이 내장되어 있는지 궁금합니다.
예를 들어, 나는 다음과 같은 것을 시도했다.
grouped.agg({'C_sum' : lambda x: x['C'].sum(),
'C_std': lambda x: x['C'].std(),
'D_sum' : lambda x: x['D'].sum()},
'D_sumifC3': lambda x: x['D'][x['C'] == 3].sum(), ...)
그러나 예상대로 KeyError가 발생합니다 ( agg
DataFrame에서 호출 되면 키가 열 이어야하기 때문에).
내가하고 싶은 일을 수행하는 방법이 있거나이 기능이 추가 될 가능성이 있습니까? 아니면 그룹별로 수동으로 반복해야합니까?
감사
답변
현재 허용되는 답변의 후반부는 구식이며 두 가지 더 이상 사용되지 않습니다. 가장 중요한 것은 더 이상 사전 사전을 agg
groupby 메소드에 전달할 수 없다는 것입니다. 둘째, 절대 사용하지 마십시오 .ix
.
두 개의 별도 열을 동시에 사용하려면 apply
DataFrame을 적용된 함수에 암시 적으로 전달하는 메서드를 사용하는 것이 좋습니다 . 위에서와 비슷한 데이터 프레임을 사용합시다
df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
df['group'] = [0, 0, 1, 1]
df
a b c d group
0 0.418500 0.030955 0.874869 0.145641 0
1 0.446069 0.901153 0.095052 0.487040 0
2 0.843026 0.936169 0.926090 0.041722 1
3 0.635846 0.439175 0.828787 0.714123 1
열 이름에서 집계 함수로 매핑 된 사전은 여전히 집계를 수행하는 데 가장 좋은 방법입니다.
df.groupby('group').agg({'a':['sum', 'max'],
'b':'mean',
'c':'sum',
'd': lambda x: x.max() - x.min()})
a b c d
sum max mean sum <lambda>
group
0 0.864569 0.446069 0.466054 0.969921 0.341399
1 1.478872 0.843026 0.687672 1.754877 0.672401
못생긴 람다 열 이름이 마음에 들지 않으면 일반 함수를 사용하고 다음과 __name__
같이 특수 속성에 사용자 지정 이름을 제공 할 수 있습니다 .
def max_min(x):
return x.max() - x.min()
max_min.__name__ = 'Max minus Min'
df.groupby('group').agg({'a':['sum', 'max'],
'b':'mean',
'c':'sum',
'd': max_min})
a b c d
sum max mean sum Max minus Min
group
0 0.864569 0.446069 0.466054 0.969921 0.341399
1 1.478872 0.843026 0.687672 1.754877 0.672401
apply
시리즈 사용 및 반환
이제 서로 상호 작용해야하는 여러 열이 있으면를 사용할 수 없습니다 agg
.이 함수는 Series를 암시 적으로 집계 함수에 전달합니다. 사용하는 경우 apply
전체 그룹 DataFrame은 함수에 전달됩니다있다.
일련의 모든 집계를 반환하는 단일 사용자 지정 함수를 만드는 것이 좋습니다. 시리즈 색인을 새 열의 레이블로 사용하십시오.
def f(x):
d = {}
d['a_sum'] = x['a'].sum()
d['a_max'] = x['a'].max()
d['b_mean'] = x['b'].mean()
d['c_d_prodsum'] = (x['c'] * x['d']).sum()
return pd.Series(d, index=['a_sum', 'a_max', 'b_mean', 'c_d_prodsum'])
df.groupby('group').apply(f)
a_sum a_max b_mean c_d_prodsum
group
0 0.864569 0.446069 0.466054 0.173711
1 1.478872 0.843026 0.687672 0.630494
MultiIndexes를 좋아한다면 다음과 같이 Series를 반환 할 수 있습니다.
def f_mi(x):
d = []
d.append(x['a'].sum())
d.append(x['a'].max())
d.append(x['b'].mean())
d.append((x['c'] * x['d']).sum())
return pd.Series(d, index=[['a', 'a', 'b', 'c_d'],
['sum', 'max', 'mean', 'prodsum']])
df.groupby('group').apply(f_mi)
a b c_d
sum max mean prodsum
group
0 0.864569 0.446069 0.466054 0.173711
1 1.478872 0.843026 0.687672 0.630494
답변
첫 번째 부분에서는 키에 대한 열 이름과 값에 대한 함수 목록을 전달할 수 있습니다.
In [28]: df
Out[28]:
A B C D E GRP
0 0.395670 0.219560 0.600644 0.613445 0.242893 0
1 0.323911 0.464584 0.107215 0.204072 0.927325 0
2 0.321358 0.076037 0.166946 0.439661 0.914612 1
3 0.133466 0.447946 0.014815 0.130781 0.268290 1
In [26]: f = {'A':['sum','mean'], 'B':['prod']}
In [27]: df.groupby('GRP').agg(f)
Out[27]:
A B
sum mean prod
GRP
0 0.719580 0.359790 0.102004
1 0.454824 0.227412 0.034060
업데이트 1 :
집계 함수는 Series에서 작동하므로 다른 열 이름에 대한 참조는 손실됩니다. 이 문제를 해결하려면 전체 데이터 프레임을 참조하고 람다 함수 내의 그룹 색인을 사용하여 색인화하십시오.
해키 해결 방법은 다음과 같습니다.
In [67]: f = {'A':['sum','mean'], 'B':['prod'], 'D': lambda g: df.loc[g.index].E.sum()}
In [69]: df.groupby('GRP').agg(f)
Out[69]:
A B D
sum mean prod <lambda>
GRP
0 0.719580 0.359790 0.102004 1.170219
1 0.454824 0.227412 0.034060 1.182901
여기서 결과 ‘D’열은 합산 된 ‘E’값으로 구성됩니다.
업데이트 2 :
여기에 내가 원하는 모든 것을 할 것이라고 생각되는 방법이 있습니다. 먼저 커스텀 람다 함수를 만드십시오. 아래에서 g는 그룹을 나타냅니다. 집계 할 때 g는 시리즈가됩니다. df에서 현재 그룹 g.index
을 df.ix[]
선택하여 전달 합니다 . 그런 다음 C 열이 0.5보다 작은 지 테스트합니다. 반환 된 부울 계열이 전달되어 g[]
조건을 충족하는 행만 선택합니다.
In [95]: cust = lambda g: g[df.loc[g.index]['C'] < 0.5].sum()
In [96]: f = {'A':['sum','mean'], 'B':['prod'], 'D': {'my name': cust}}
In [97]: df.groupby('GRP').agg(f)
Out[97]:
A B D
sum mean prod my name
GRP
0 0.719580 0.359790 0.102004 0.204072
1 0.454824 0.227412 0.034060 0.570441
답변
Ted Petrou의 답변에 대한 대안 (주로 미학에 대한 대안)으로, 나는 조금 더 작은 목록을 선호한다는 것을 알았습니다. 수락하는 것을 고려하지 마십시오. Ted의 답변과 코드 / 데이터에 대한 자세한 설명 일뿐입니다. 파이썬 / 팬더는 내 첫 번째 / 최고가 아니지만 잘 읽습니다.
df.groupby('group') \
.apply(lambda x: pd.Series({
'a_sum' : x['a'].sum(),
'a_max' : x['a'].max(),
'b_mean' : x['b'].mean(),
'c_d_prodsum' : (x['c'] * x['d']).sum()
})
)
a_sum a_max b_mean c_d_prodsum
group
0 0.530559 0.374540 0.553354 0.488525
1 1.433558 0.832443 0.460206 0.053313
dplyr
파이프와 data.table
연쇄 명령을 연상시키는 것으로 나타 났습니다. 그들이 더 나아 졌다고 말하지 않고, 나에게 더 친숙합니다. (나는 분명히 def
이러한 유형의 작업에 더 공식화 된 기능을 사용하는 힘과 많은 사람들의 선호를 인식하고 있습니다. 이것은 반드시 대안 일 뿐이며 반드시 더 나은 것은 아닙니다.)
Ted와 같은 방식으로 데이터를 생성했습니다. 재현성을 위해 시드를 추가하겠습니다.
import numpy as np
np.random.seed(42)
df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
df['group'] = [0, 0, 1, 1]
df
a b c d group
0 0.374540 0.950714 0.731994 0.598658 0
1 0.156019 0.155995 0.058084 0.866176 0
2 0.601115 0.708073 0.020584 0.969910 1
3 0.832443 0.212339 0.181825 0.183405 1
답변
Pandas >= 0.25.0
, 명명 된 집계
팬더 버전 0.25.0
이상 이므로 사전 기반 집계 및 이름 변경에서 벗어나 이름이 지정된 집계로 이동 하고 tuple
있습니다. 이제 더 많은 정보를 제공하는 열 이름으로 집계 + 이름 바꾸기를 동시에 수행 할 수 있습니다.
예 :
df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
df['group'] = [0, 0, 1, 1]
a b c d group
0 0.521279 0.914988 0.054057 0.125668 0
1 0.426058 0.828890 0.784093 0.446211 0
2 0.363136 0.843751 0.184967 0.467351 1
3 0.241012 0.470053 0.358018 0.525032 1
GroupBy.agg
명명 된 집계로 적용 :
df.groupby('group').agg(
a_sum=('a', 'sum'),
a_mean=('a', 'mean'),
b_mean=('b', 'mean'),
c_sum=('c', 'sum'),
d_range=('d', lambda x: x.max() - x.min())
)
a_sum a_mean b_mean c_sum d_range
group
0 0.947337 0.473668 0.871939 0.838150 0.320543
1 0.604149 0.302074 0.656902 0.542985 0.057681
답변
출력 열 이름을 제어하여 열별 집계를 지원하기 위해 pandas는 GroupBy.agg () 에서 “named aggregation”이라는 특수 구문을 허용합니다 . 여기서
- 키워드는 출력 열 이름입니다.
- 값은 첫 번째 요소가 선택할 열이고 두 번째 요소가 해당 열에 적용 할 집계 인 튜플입니다. Pandas는 pandas.NamedAgg라는 이름의 tuple을 필드 [ ‘column’, ‘aggfunc’]와 함께 제공하여 인수가 무엇인지 더 명확하게 만듭니다. 일반적으로 집계는 호출 가능 또는 문자열 별명 일 수 있습니다.
In [79]: animals = 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 [80]: animals
Out[80]:
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 [81]: animals.groupby("kind").agg(
....: min_height=pd.NamedAgg(column='height', aggfunc='min'),
....: max_height=pd.NamedAgg(column='height', aggfunc='max'),
....: average_weight=pd.NamedAgg(column='weight', aggfunc=np.mean),
....: )
....:
Out[81]:
min_height max_height average_weight
kind
cat 9.1 9.5 8.90
dog 6.0 34.0 102.75
pandas.NamedAgg는 단지 명명 된 튜플입니다. 일반 튜플도 허용됩니다.
In [82]: animals.groupby("kind").agg(
....: min_height=('height', 'min'),
....: max_height=('height', 'max'),
....: average_weight=('weight', np.mean),
....: )
....:
Out[82]:
min_height max_height average_weight
kind
cat 9.1 9.5 8.90
dog 6.0 34.0 102.75
추가 키워드 인수는 집계 함수로 전달되지 않습니다. (열, aggfunc) 쌍만 ** kwargs로 전달해야합니다. 집계 함수에 추가 인수가 필요한 경우 functools.partial ()을 사용하여 인수를 부분적으로 적용하십시오.
명명 된 집계는 시리즈 그룹 별 집계에도 유효합니다. 이 경우 열 선택이 없으므로 값은 함수일뿐입니다.
In [84]: animals.groupby("kind").height.agg(
....: min_height='min',
....: max_height='max',
....: )
....:
Out[84]:
min_height max_height
kind
cat 9.1 9.5
dog 6.0 34.0
답변
테드의 대답은 놀랍습니다. 누군가 관심이 있으시면 더 작은 버전을 사용했습니다. 여러 열의 값에 따라 하나의 집계를 찾을 때 유용합니다.
데이터 프레임 만들기
df=pd.DataFrame({'a': [1,2,3,4,5,6], 'b': [1,1,0,1,1,0], 'c': ['x','x','y','y','z','z']})
a b c
0 1 1 x
1 2 1 x
2 3 0 y
3 4 1 y
4 5 1 z
5 6 0 z
apply를 사용하여 그룹화 및 집계 (여러 열 사용)
df.groupby('c').apply(lambda x: x['a'][(x['a']>1) & (x['b']==1)].mean())
c
x 2.0
y 4.0
z 5.0
집계를 사용하여 그룹화 및 집계 (여러 열 사용)
나는 여전히 집계를 사용할 수 있기 때문에이 접근법을 좋아합니다. 아마도 사람들은 그룹에서 집계를 수행 할 때 여러 열을 가져 오기 위해 apply가 필요한 이유를 알려줄 것입니다.
지금은 분명해 보이지만 groupby 바로 다음 에 관심있는 열을 선택하지 않으면 집계 함수 내에서 데이터 프레임의 모든 열에 액세스 할 수 있습니다.
선택한 열에 만 액세스
df.groupby('c')['a'].aggregate(lambda x: x[x>1].mean())
선택은 모든 마법 이후 모든 열에 액세스
df.groupby('c').aggregate(lambda x: x[(x['a']>1) & (x['b']==1)].mean())['a']
또는 유사하게
df.groupby('c').aggregate(lambda x: x['a'][(x['a']>1) & (x['b']==1)].mean())
이게 도움이 되길 바란다.