Панды «уменьшают» и «накапливают» функции - неполная реализация - PullRequest
0 голосов
/ 30 мая 2018

Я хотел бы использовать функции уменьшения и накопления в Pandas таким же образом, как они применяются в нативном питоне со списками.В реализациях itertools и functools для уменьшения и накопления (иногда называемого сложением и накопительным сложением в других языках) требуется функция с двумя аргументами.В Pandas нет аналогичной реализации.Функция принимает два параметра: f (аккумулированное_значение, popped_value)

Итак, у меня есть список двоичных переменных и я хочу вычислить число длительностей, когда мы находимся в состоянии 1:

In [1]: from itertools import accumulate
        import pandas as pd
        drawdown_periods = [0,1,1,1,0,0,0,1,1,1,1,0,1,1,0]

применение накопления к этому с помощью лямбда-функции

lambda x,y: (x+y)*y

дает

In [2]: list(accumulate(drawdown_periods, lambda x,y: (x+y)*y))
Out[2]: [0, 1, 2, 3, 0, 0, 0, 1, 2, 3, 4, 0, 1, 2, 0]

подсчет длины каждого drawdown_period.

Есть ли умный, но изворотливый способпредоставить лямбда-функцию с двумя аргументами?Я могу пропустить трюк здесь.

Я знаю, что есть прекрасный рецепт с groupby (см. StackOverflow Как рассчитать последовательные равные значения в Pandas / Как эмулировать itertools.groupby с серией / dataframe ).Я повторю это, потому что это так мило:

In [3]: df = pd.DataFrame(data=drawdown_periods, columns=['dd'])
       df['dd'].groupby((df['dd'] != df['dd'].shift()).cumsum()).cumsum()
Out[3]:
    0     0
    1     1
    2     2
    3     3
    4     0
    5     0
    6     0
    7     1
    8     2
    9     3
    10    4
    11    0
    12    1
    13    2
    14    0
    Name: dd, dtype: int64   

Это не решение, которое я хочу.Мне нужен способ передачи двухпараметрической лямбда-функции в нативные функции уменьшения / накопления панд, поскольку это также будет работать для многих других рецептов функционального программирования.

Ответы [ 3 ]

0 голосов
/ 30 мая 2018

То, что вы ищете, это метод pandas, который извлекает все объекты из Серии, преобразует их в объект Python, вызывает функцию Python и имеет аккумулятор, который также является объектом Python.

ЭтоТакое поведение плохо масштабируется, когда у вас много данных, так как при обёртывании необработанных данных в объекты Python требуется много времени и памяти.Методы Pandas пытаются работать непосредственно с исходными (пустыми) необработанными данными, имея возможность обрабатывать большое количество данных без необходимости оборачивать их в объекты Python.Пример groupby + cumsum, который вы приводите, - это умный способ избежать использования функций .apply и Python, который будет медленнее.

Тем не менее, вы, конечно, можете свободно выполнять свои собственные функции в Python, еслиВы не заботитесь о производительности.Так как в любом случае это все Python и нет никакой возможности ускорить его на стороне панд, вы можете просто написать свой собственный:

df["cev"] = list(accumulate(df.dd, lambda x,y:(x+y)*y))
0 голосов
/ 21 мая 2019

Использование pandas.DataFrame.aggregate и functools.reduce :

import pandas as pd
import operator
from functools import reduce

def reduce_or(series):
    return reduce(operator.or_, series)


df = pd.DataFrame([1,0,0,0], index='a b a b'.split()).astype(bool)
df

original dataframe

df.groupby(df.index).aggregate(reduce_or)

reduced dataframe

0 голосов
/ 30 мая 2018

Вы могли бы заставить это работать со штрафом эффективности, используя numpy.На практике вам может быть лучше написать специальные векторизованные решения.

Использование np.frompyfunc:

s = pd.Series([0,1,1,1,0,0,0,1,1,1,1,0,1,1,0])
f = numpy.frompyfunc(lambda x, y: (x+y) * y, 2, 1)
f.accumulate(series.astype(object))

0     0
1     1
2     2
3     3
4     0
5     0
6     0
7     1
8     2
9     3
10    4
11    0
12    1
13    2
14    0
dtype: object
...