pandas聚合与自定义函数是否不一致?

siotufzp  于 2023-08-01  发布在  其他
关注(0)|答案(3)|浏览(114)

我想我在pandas.Series.agg方法中发现了一个异常。
这是我发现的

>>> v = pd.Series([172, 172, 170.0, 170., 168.])
>>> 
>>> v.agg(np.mean)
170.4
>>> 
>>> v.agg(lambda x: np.mean(x))
0    172.0
1    172.0
2    170.0
3    170.0
4    168.0
dtype: float64
>>> 
>>> np.mean(v)
170.4

字符串
我觉得这很令人沮丧,因为lambda x: f(x)应该和f(x)一样工作,对吗?.agg(func)的输入是Series(根据文档),但输出显示不是。这是另一个输出。

>>> v.agg(lambda x: print(type(x)))
<class 'float'>
<class 'float'>
<class 'float'>
<class 'float'>
<class 'float'>
0    None
1    None
0    None
1    None
0    None
dtype: object

>>> v.agg(lambda x: print(x.tolist()))
[172.0, 172.0, 170.0, 170.0, 168.0]


什么?输出表明lambda x:的输入对于上面两种情况是不同的。我不确定是否可能。
这是我进一步调查的结果

>>> v.agg(lambda x: np.mean(x))
0    172.0
1    172.0
0    170.0
1    170.0
0    168.0
dtype: float64
>>> v.groupby(level=0).agg(lambda x: np.mean(x))
0    170.0
1    171.0
dtype: float64
>>> v.agg(lambda x: np.mean(x.tolist()))
170.4


至少,lambda x: np.mean(x)可以像预期的那样用于分组系列!但谜团依然存在有人能帮我澄清一下这里发生了什么吗?
我用pandas.DataFrame.agg和lambda x: np.mean(x)进行了测试,结果和预期一样工作!

>>> pd.DataFrame(v)
       0
0  172.0
1  172.0
0  170.0
1  170.0
0  168.0
>>> pd.DataFrame(v).agg(lambda x: np.mean(x))
0    170.4
dtype: float64

综上所述,我的问题是,下面两个结果就是smae。

v.groupby(by = [0]*len(v)).agg(np.mean)
v.groupby(by = [0]*len(v)).agg(lambda x: np.mean(x))


但下面两个是不一样的。在Pandas里这不是被认为是不一致的吗?

v.agg(np.mean)
v.agg(lambda x: np.mean(x))


它是从哪里来的?

vyswwuz2

vyswwuz21#

>>> pd.DataFrame(v).agg(lambda x: np.mean(x))
0    170.4

字符串
上面的内容对你来说很好,因为它被应用在axis=0上,但是如果你传递axis=1,你会得到和Series相同的结果:

>>> pd.DataFrame(v).agg(lambda x: np.mean(x), axis=1)
0    172.0
1    172.0
2    170.0
3    170.0
4    168.0
dtype: float64


Dataframe 有两个轴,即0和1,但系列只有一个轴,即0.当您执行v.agg(lambda x: np.mean(x))时,它将分别应用于系列中的每个单独值,这类似于pandas.Series.apply,而当您执行v.agg(np.mean)时,它将应用于整个系列。
查看docs for pandas.Series.agg

参数:func:function,str,list或dict

用于聚合数据的函数。如果是函数,则必须在传递Series或传递到Series.apply时工作。

qvk1mo1f

qvk1mo1f2#

看看agg的来源。该方法检查传递的函数是否被向量化,然后返回一个标量,如果不是,则将其应用于每行

# try a regular apply, this evaluates lambdas
        # row-by-row; however if the lambda is expected a Series
        # expression, e.g.: lambda x: x-x.quantile(0.25)
        # this will fail, so we can try a vectorized evaluation

        # we cannot FIRST try the vectorized evaluation, because
        # then .agg and .apply would have different semantics if the
        # operation is actually defined on the Series, e.g. str

字符串
这就是为什么在组合转换和聚合函数时会出现错误:

>>> v.agg([np.mean, lambda x: np.mean(x)])
ValueError: cannot combine transform and aggregation operations

gtlvzcf8

gtlvzcf83#

Agg通过以不同的方式调用函数来“探测”函数,有时会出错。下面是我如何解决scipy.stats.iqr的情况:

import numpy as np
import scipy.stats

df = <some dataframe>

df.agg(scipy.stats.iqr)  # ok
df.agg(["mean", scipy.stats.iqr])  # !! ValueError: cannot combine transform and aggregation operations

字符串
如果我们制作一个 Package 器,只处理数组而不处理标量,它就可以工作了!

import functools

def only_vector(f):
    "decorator: the function raises ValueError if arg is not an array"
    @functools.wraps(f)
    def wrapper(arg, *args, **kwargs):
        if np.shape(arg) == ():
            raise ValueError("Expected vector argument")
        return f(arg, *args, **kwargs)
    return wrapper
iqr = only_vector(scipy.stats.iqr)
df.agg(["mean", iqr])  # OK

的数据

相关问题