Как выполнить итерацию с результатом предыдущих строк того же столбца?

Начиная с кадра данных со столбцами A B D P:

import numba
import numpy as np
import pandas as pd
import vaex

d = {'A':[0,1,2,3,4,5,6],'B':[30,35,32,35,31,39,37],'D':[12,10,13,19,12,21,13],'P':[3,3,3,3,3,3,3]}
df = pd.DataFrame(data=d)

df['C'] = 0

df

Экспорт в hdf5:

df.to_csv("v_df", index=False)
    
df = vaex.from_csv("v_df", convert=True, chunk_size=5_000_000)

Мне нужно вычислить столбец «C» с каждой строкой с желаемым результатом следующим образом:

'C': [0, 1.666666667, 0.552380952, 2.333630952, 0.962202381, 6.38155722, 5.714890553]

Чтобы достичь этого результата, мне нужно перебрать каждую строку, начиная с row (1), и вычислить что-то вроде:

%%time
@numba.njit
def func(B, D, C, b_0=0):
    n = len(B)
    b = np.full(n, b_0, dtype=np.float64)
    for i in range(1, n):
        b[i] = ((((B[i] - B[i - 1]) / B[i - 1])) * D[i]) + C[i-1]
    return b
df['C'] = func(df['B'].to_numpy(),df['D'].to_numpy(),df['C'].to_numpy())
df

Но не работает.

Это нормально для первой и второй строки:

'C': [0, 1.666666667, -1.114286, 1.781250, -1.371429, 5.419355, -0.666667]

Я пробовал «сдвиг» (предложение Сэммивемми). Он работает нормально для этого примера кадра данных перед 'vaex.from_csv', но при реализации концепции для кадра больших данных через vaex сдвиг не работает.

Итак, возникает вопрос: существует ли способ «хорошей практики» для выполнения этого вычисления (повторение результата строки в столбце «C» с учетом предыдущих строк в «C») с большим источником данных (я использую vaex импортировать из 1 миллиона строк csv)?

Заранее спасибо.


person juliothomaz    schedule 11.04.2021    source источник
comment
попробуйте это: df.B.shift(-1).sub(df.B).div(df.B).mul(df.D.shift(-1)).cumsum().shift(fill_value=0)   -  person sammywemmy    schedule 12.04.2021
comment
sammywemmy, спасибо за ваш быстрый ответ и помощь ... Он отлично работает для моего примера createad с простым фреймом данных pandas! Спасибо! Но ... когда я пытаюсь реализовать эту концепцию в фрейме больших данных от vaex, это не работает. Показывает сообщение: 'AttributeError: объект' Expression 'не имеет атрибута' shift ''. Спасибо за помощь ...   -  person juliothomaz    schedule 12.04.2021
comment
Я не знаком с vaex; вы можете взглянуть на их API и посмотреть, есть ли альтернатива shift   -  person sammywemmy    schedule 12.04.2021
comment
Еще раз хочу поблагодарить вас за помощь и доброту. Спасибо!   -  person juliothomaz    schedule 12.04.2021


Ответы (1)


Я не уверен, что это оптимальное решение, но, по крайней мере, оно работает: вы можете использовать apply с vectorize, установленным на True.

Вот полный фрагмент:

import numba
import numpy as np
import pandas as pd
import vaex

d = {'A':[0,1,2,3,4,5,6],'B':[30,35,32,35,31,39,37],'D':[12,10,13,19,12,21,13],'P':[3,3,3,3,3,3,3]}
df = pd.DataFrame(data=d)

df['C'] = 0

df

# I removed the b_0 for simplicity
def my_func(B, D, C):
    n = len(B)
    b = np.full(n, 0, dtype=np.float64)
    for i in range(1, n):
        b[i] = ((((B[i] - B[i - 1]) / B[i - 1])) * D[i]) + C[i-1]

    return b

df_vaex = vaex.from_pandas(df)

df_vaex.apply(my_func, arguments=[df_vaex["B"], df_vaex["D"], df_vaex["C"]], vectorize=True)

Это дает ожидаемый результат:

0          0
1    1.66667
2   -1.11429
3    1.78125
4   -1.37143
5    5.41935
6  -0.666667

По сути, метод apply позволяет применять функции построчно, и если вы установите vectorize на True, вместо значений строк будут передаваться полные массивы. В вашем случае это обязательно, поскольку вам нужны значения из предыдущих строк для вычисления значения C в данной строке.

person M. Perier--Dulhoste    schedule 13.04.2021
comment
Идеально! Я очень рада достичь результатов без необходимости «сдвигаться» и узнать немного больше! Большое спасибо! - person juliothomaz; 14.04.2021
comment
Идеально! Другое предложение - реализовать метод сдвига для vaex, здесь вы можете найти ответ, связанный с этой задачей: stackoverflow.com/a/61075267/ 8056572 - person M. Perier--Dulhoste; 14.04.2021