这里的答案都没有解决why这是失败的。如果您深入研究 pandas 代码,当 UDF 传递给df.agg
,每列的 Series 对象将传递给 UDF。
在您的情况下,使用字典选择 Series 对象(一列),然后将 UDF 传递到 Series 对象的Series.agg
功能。因为它不是一个已知的函数(比如字符串'mean'
),它最终被传递给Series.apply
,它将函数映射到 Series 对象中的每个值。这就是您看到的结果。
幸运的是,UDF 传递给Series.apply
发生在一个try/except
堵塞。如果无法使用Series.apply(func)
,它通过以下方式将 Series 对象传递给函数func(Series)
。如果传递的对象不是 Series 或 DataFrame,您可以使用它来修改代码以引发错误。
def CoV(_s):
if not isinstance(_s, (pd.Series, pd.DataFrame, np.array)):
raise TypeError()
return pd.Series({'CoV' : np.std(_s)/np.mean(_s)})
现在将其传递给.agg
正如您所期望的那样工作。这是一个很棘手的解决方法,但它确实有效。
df.agg({'a': CoV})
# returns:
a
CoV 0.584645
EDIT:
为了让它与其他功能一起使用,比如'mean'
,不幸的是,您还必须将它们作为 UDF 传递。更糟糕的是,UDF 的结果累积与内置函数的结果累积不同。 Pandas 只是使用分层列索引水平堆叠它们。一个简单的stack
and reset_index
解决这个问题。
def check_input(fn):
def wrapper(_s, *args, **kwargs):
if not isinstance(_s, (pd.Series, pd.DataFrame, np.array)):
raise TypeError()
return fn(_s, *args, **kwargs)
wrapper.__name__ = fn.__name__
return wrapper
@check_input
def Mean(_s):
return pd.Series({'Mean': np.mean(_s)})
@check_input
def CoV(_s):
return pd.Series({'CoV' : np.std(_s)/np.mean(_s)})
df.agg({'a': [CoV, Mean], 'c': Mean}).stack().reset_index(level=-1, drop=True)
# returns:
a c
CoV 0.584645 NaN
Mean 0.511350 2.011