#python #pandas #dataframe
#python #pandas #dataframe
Вопрос:
Например, предположим, что у меня есть фрейм данных типа
import pandas as pd
df = pd.DataFrame({'x': [1, 2, 3, 4]})
и я вызываю
df.agg(func='sum')
Ссылается ли это на
Я понимаю, что под капотом они делают то же самое, но я все равно хотел бы знать, какая функция отправляется. Это где-нибудь задокументировано?
Ответ №1:
Это внутренние детали, я не думаю, что это будет задокументировано.
pandas-dev обрабатывает эти строки, т.е. 'sum'
'mean'
Таким образом. У них есть сопоставление, в котором они сопоставляют функцию со своей внутренней цитонизированной реализацией этих функций.
Взято из pandas/core/base.py
_cython_table = {
builtins.sum: "sum",
builtins.max: "max",
builtins.min: "min",
np.all: "all",
np.any: "any",
np.sum: "sum",
np.nansum: "sum",
np.mean: "mean",
np.nanmean: "mean",
np.prod: "prod",
np.nanprod: "prod",
np.std: "std",
np.nanstd: "std",
np.var: "var",
np.nanvar: "var",
np.median: "median",
np.nanmedian: "median",
np.max: "max",
np.nanmax: "max",
np.min: "min",
np.nanmin: "min",
np.cumprod: "cumprod",
np.nancumprod: "cumprod",
np.cumsum: "cumsum",
np.nancumsum: "cumsum",
}
Итак, Series.agg(sum)
, Series.agg('sum')
, Series.agg(np.sum)
, Series.agg(np.nansum)
все вызывают одну и ту же внутреннюю функцию с использованием cythonized .
Взято из pandas/core/base.py
def _get_cython_func(self, arg: Callable) -> Optional[str]:
"""
if we define an internal function for this argument, return it
"""
return self._cython_table.get(arg)
Вы можете найти, как они обрабатывают это в pandas/core/aggregate.py
, они используют getattr
здесь, похоже, что cythonized funcs являются определенными атрибутами класса. Я не нашел, где, но хорошим местом для начала было бы pandas/core/generic.py
взглянуть на stat_func
def aggregate(
obj: AggObjType,
arg: AggFuncType,
*args,
**kwargs,
):
...
...
if callable(arg):
f = obj._get_cython_func(arg)
if f and not args and not kwargs:
return getattr(obj, f)(), None
...
...
Комментарии:
1. Что здесь действительно интересно, так это то, что if
x
— серия pandas,np.sum(x)
не использует реализацию NumPy ofsum()
. Скорее, он использует реализацию Pandas . Еслиx
имеет NAN,np.sum(x)
будет игнорировать их, что не так, еслиx
бы это был массив NumPy. сегодня я выучил2. @Ben Да, я сделал PR об этом за 2 месяца до этого, чтобы упомянуть об этом поведении в документах, объединенных с master, но запланированных для
V1.2
tho. github.com/pandas-dev/pandas/pull/35042
Ответ №2:
@Ch3steR, спасибо, что помог мне увидеть свет. Однако я хочу немного подробнее остановиться на вашем ответе..
Исходный код для aggregate()
включает в себя эти соответствующие строки
def aggregate(
obj: AggObjType,
arg: AggFuncType,
*args,
**kwargs,
):
...
if isinstance(arg, str):
return obj._try_aggregate_string_function(arg, *args, **kwargs), None
Затем мы отслеживаем _try_aggregate_string_function()
…
def _try_aggregate_string_function(self, arg: str, *args, **kwargs):
"""
if arg is a string, then try to operate on it:
- try to find a function (or attribute) on ourselves
- try to find a numpy function
- raise
"""
assert isinstance(arg, str)
f = getattr(self, arg, None)
if f is not None:
if callable(f):
return f(*args, **kwargs)
# people may try to aggregate on a non-callable attribute
# but don't let them think they can pass args to it
assert len(args) == 0
assert len([kwarg for kwarg in kwargs if kwarg not in ["axis"]]) == 0
return f
f = getattr(np, arg, None)
if f is not None:
if hasattr(self, "__array__"):
# in particular exclude Window
return f(self, *args, **kwargs)
raise AttributeError(
f"'{arg}' is not a valid function for '{type(self).__name__}' object"
)
Итак, когда вы выполняете вызов like df.agg('foo')
, Pandas сначала ищет атрибут DataFrame с именем foo
, а затем ищет функцию NumPy с именем foo
(предполагая foo
, что она не существует как атрибут DataFrame).