이 문서 는 출력 열 이름을 키로 사용하는 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가 발생합니다 ( aggDataFrame에서 호출 되면 키가 열 이어야하기 때문에).
내가하고 싶은 일을 수행하는 방법이 있거나이 기능이 추가 될 가능성이 있습니까? 아니면 그룹별로 수동으로 반복해야합니까?
감사
답변
현재 허용되는 답변의 후반부는 구식이며 두 가지 더 이상 사용되지 않습니다. 가장 중요한 것은 더 이상 사전 사전을 agggroupby 메소드에 전달할 수 없다는 것입니다. 둘째, 절대 사용하지 마십시오 .ix.
두 개의 별도 열을 동시에 사용하려면 applyDataFrame을 적용된 함수에 암시 적으로 전달하는 메서드를 사용하는 것이 좋습니다 . 위에서와 비슷한 데이터 프레임을 사용합시다
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())
이게 도움이 되길 바란다.
답변
