집계 DataFrame.agg
되는 데이터의 둘 이상의 열에 액세스 할 수 있는 메서드에서 사용되는 집계 함수를 작성하는 방법이 있습니까? 일반적인 사용 사례는 가중 평균, 가중 표준 편차 함수입니다.
다음과 같이 쓸 수 있기를 바랍니다.
def wAvg(c, w):
return ((c * w).sum() / w.sum())
df = DataFrame(....) # df has columns c and w, i want weighted average
# of c using w as weight.
df.aggregate ({"c": wAvg}) # and somehow tell it to use w column as weights ...
답변
예; .apply(...)
각 하위에서 호출되는 함수를 사용합니다 DataFrame
. 예를 들면 :
grouped = df.groupby(keys)
def wavg(group):
d = group['data']
w = group['weights']
return (d * w).sum() / w.sum()
grouped.apply(wavg)
답변
내 솔루션은 Nathaniel의 솔루션과 유사하지만 단일 열에 대한 것이며 매번 전체 데이터 프레임을 딥 복사하지 않아 엄청나게 느릴 수 있습니다. groupby (…). apply (…) 솔루션에 비해 성능 향상은 약 100x (!)입니다.
def weighted_average(df, data_col, weight_col, by_col):
df['_data_times_weight'] = df[data_col] * df[weight_col]
df['_weight_where_notnull'] = df[weight_col] * pd.notnull(df[data_col])
g = df.groupby(by_col)
result = g['_data_times_weight'].sum() / g['_weight_where_notnull'].sum()
del df['_data_times_weight'], df['_weight_where_notnull']
return result
답변
를 사용하여 groupby 개체에서 집계 된 값을 원하는만큼 반환 할 수 apply
있습니다. 간단히 Series를 반환하면 인덱스 값이 새 열 이름이됩니다.
간단한 예를 보겠습니다.
df = pd.DataFrame({'group':['a','a','b','b'],
'd1':[5,10,100,30],
'd2':[7,1,3,20],
'weights':[.2,.8, .4, .6]},
columns=['group', 'd1', 'd2', 'weights'])
df
group d1 d2 weights
0 a 5 7 0.2
1 a 10 1 0.8
2 b 100 3 0.4
3 b 30 20 0.6
에 전달 될 사용자 지정 함수를 정의합니다 apply
. data
매개 변수가 DataFrame임을 의미하는 DataFrame을 암시 적으로 허용합니다 . agg
groupby 메서드 에서는 불가능한 여러 열을 사용하는 방법 에 유의하십시오.
def weighted_average(data):
d = {}
d['d1_wa'] = np.average(data['d1'], weights=data['weights'])
d['d2_wa'] = np.average(data['d2'], weights=data['weights'])
return pd.Series(d)
apply
사용자 지정 함수를 사용 하여 groupby 메서드를 호출합니다 .
df.groupby('group').apply(weighted_average)
d1_wa d2_wa
group
a 9.0 2.2
b 58.0 13.2
다른 답변에서 설명한대로 가중치 합계를 새 DataFrame 열로 미리 계산하여 더 나은 성능을 얻을 수 있으며 함께 사용하지 마십시오 apply
.
답변
다음 (Wes McKinney의 답변을 기반으로 함)은 내가 찾고 있던 것을 정확하게 수행합니다. .NET에서이 작업을 수행하는 더 간단한 방법이 있는지 배우게되어 기쁩니다 pandas
.
def wavg_func(datacol, weightscol):
def wavg(group):
dd = group[datacol]
ww = group[weightscol] * 1.0
return (dd * ww).sum() / ww.sum()
return wavg
def df_wavg(df, groupbycol, weightscol):
grouped = df.groupby(groupbycol)
df_ret = grouped.agg({weightscol:sum})
datacols = [cc for cc in df.columns if cc not in [groupbycol, weightscol]]
for dcol in datacols:
try:
wavg_f = wavg_func(dcol, weightscol)
df_ret[dcol] = grouped.apply(wavg_f)
except TypeError: # handle non-numeric columns
df_ret[dcol] = grouped.agg({dcol:min})
return df_ret
이 함수 df_wavg()
는 “groupby”열로 그룹화 된 데이터 프레임을 반환하고 가중치 열에 대한 가중치의 합계를 반환합니다. 다른 열은 가중 평균이거나 숫자가 아닌 경우 min()
함수가 집계에 사용됩니다.
답변
나는 이것을 많이하고 다음이 매우 편리하다는 것을 알았다.
def weighed_average(grp):
return grp._get_numeric_data().multiply(grp['COUNT'], axis=0).sum()/grp['COUNT'].sum()
df.groupby('SOME_COL').apply(weighed_average)
이것은 모든 숫자 열의 가중 평균을 계산하고 df
숫자가 아닌 열을 삭제합니다.
답변
이 비아를 달성하는 것은 groupby(...).apply(...)
성과가 없습니다. 여기 내가 항상 사용하는 솔루션이 있습니다 (본질적으로 kalu의 논리를 사용).
def grouped_weighted_average(self, values, weights, *groupby_args, **groupby_kwargs):
"""
:param values: column(s) to take the average of
:param weights_col: column to weight on
:param group_args: args to pass into groupby (e.g. the level you want to group on)
:param group_kwargs: kwargs to pass into groupby
:return: pandas.Series or pandas.DataFrame
"""
if isinstance(values, str):
values = [values]
ss = []
for value_col in values:
df = self.copy()
prod_name = 'prod_{v}_{w}'.format(v=value_col, w=weights)
weights_name = 'weights_{w}'.format(w=weights)
df[prod_name] = df[value_col] * df[weights]
df[weights_name] = df[weights].where(~df[prod_name].isnull())
df = df.groupby(*groupby_args, **groupby_kwargs).sum()
s = df[prod_name] / df[weights_name]
s.name = value_col
ss.append(s)
df = pd.concat(ss, axis=1) if len(ss) > 1 else ss[0]
return df
pandas.DataFrame.grouped_weighted_average = grouped_weighted_average