programing

이전 값이 적용에서도 계산될 때 Pandas에서 dataframe.apply의 이전 행 값을 사용할 수 있는 방법이 있습니까?

i4 2023. 7. 20. 21:41
반응형

이전 값이 적용에서도 계산될 때 Pandas에서 dataframe.apply의 이전 행 값을 사용할 수 있는 방법이 있습니까?

다음과 같은 데이터 프레임이 있습니다.

Index_Date    A   B     C    D
================================
2015-01-31    10   10   Nan   10
2015-02-01     2    3   Nan   22 
2015-02-02    10   60   Nan  280
2015-02-03    10  100   Nan  250

요구 사항:

Index_Date    A   B    C     D
================================
2015-01-31    10   10    10   10
2015-02-01     2    3    23   22
2015-02-02    10   60   290  280
2015-02-03    10  100  3000  250

Column C에 대해 파생된 값2015-01-31을 가져감하여valueD.

그러면 저는 그것을 사용해야 합니다.valueC위해서2015-01-31그리고 곱셈은 다음과 같습니다.valueA2015-02-01추가B.

시도해 본 적이 있습니다.apply그리고 ashift사용하여if else이로 인해 키 오류가 발생합니다.

먼저 파생된 값을 만듭니다.

df.loc[0, 'C'] = df.loc[0, 'D']

그런 다음 나머지 행을 반복하고 계산된 값을 채웁니다.

for i in range(1, len(df)):
    df.loc[i, 'C'] = df.loc[i-1, 'C'] * df.loc[i, 'A'] + df.loc[i, 'B']


  Index_Date   A   B    C    D
0 2015-01-31  10  10   10   10
1 2015-02-01   2   3   23   22
2 2015-02-02  10  60  290  280

주어진 숫자 열:

lst = []
cols = ['A']
for a in range(100, 105):
    lst.append([a])
df = pd.DataFrame(lst, columns=cols, index=range(5))
df

    A
0   100
1   101
2   102
3   103
4   104

다음을 사용하여 이전 행을 참조할 수 있습니다.shift:

df['Change'] = df.A - df.A.shift(1)
df

    A   Change
0   100 NaN
1   101 1.0
2   102 1.0
3   103 1.0
4   104 1.0

결측값을 다음으로 채울 수 있습니다.fill_value매개 변수

df['Change'] = df.A - df.A.shift(1, fill_value=df.A[0]) # fills in the missing value e.g. 100<br>
df

    A   Change
0   100 0.0
1   101 1.0
2   102 1.0
3   103 1.0
4   104 1.0

numba

벡터화가 불가능한 재귀적 계산의 경우,numbaJIT 컴파일을 사용하고 하위 수준의 개체와 함께 작동하는 이 소프트웨어는 종종 성능을 크게 향상시킵니다.정규만 정의하면 됩니다.for루프를 하고 장식기를 사용합니다.@njit또는 (이전 버전의 경우)@jit(nopython=True):

합리적인 크기의 데이터 프레임의 경우 일반 데이터 프레임에 비해 최대 30배의 성능 향상 효과를 제공합니다.for루프:

from numba import jit

@jit(nopython=True)
def calculator_nb(a, b, d):
    res = np.empty(d.shape)
    res[0] = d[0]
    for i in range(1, res.shape[0]):
        res[i] = res[i-1] * a[i] + b[i]
    return res

df['C'] = calculator_nb(*df[list('ABD')].values.T)

n = 10**5
df = pd.concat([df]*n, ignore_index=True)

# benchmarking on Python 3.6.0, Pandas 0.19.2, NumPy 1.11.3, Numba 0.30.1
# calculator() is same as calculator_nb() but without @jit decorator
%timeit calculator_nb(*df[list('ABD')].values.T)  # 14.1 ms per loop
%timeit calculator(*df[list('ABD')].values.T)     # 444 ms per loop

numpy 배열에 재귀 함수를 적용하는 것이 현재 답변보다 빠를 것입니다.

df = pd.DataFrame(np.repeat(np.arange(2, 6),3).reshape(4,3), columns=['A', 'B', 'D'])
new = [df.D.values[0]]
for i in range(1, len(df.index)):
    new.append(new[i-1]*df.A.values[i]+df.B.values[i])
df['C'] = new

산출량

      A  B  D    C
   0  1  1  1    1
   1  2  2  2    4
   2  3  3  3   15
   3  4  4  4   64
   4  5  5  5  325

이 질문이 나온 지 오래되었지만 누군가에게 도움이 되기를 바라며 답변을 올리겠습니다.

고지 사항:이 솔루션이 표준 솔루션이 아닌 것은 알지만 잘 작동한다고 생각합니다.

import pandas as pd
import numpy as np

data = np.array([[10, 2, 10, 10],
                 [10, 3, 60, 100],
                 [np.nan] * 4,
                 [10, 22, 280, 250]]).T
idx = pd.date_range('20150131', end='20150203')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df
               A    B     C    D
 =================================
 2015-01-31    10   10    NaN  10
 2015-02-01    2    3     NaN  22 
 2015-02-02    10   60    NaN  280
 2015-02-03    10   100   NaN  250

def calculate(mul, add):
    global value
    value = value * mul + add
    return value

value = df.loc['2015-01-31', 'D']
df.loc['2015-01-31', 'C'] = value
df.loc['2015-02-01':, 'C'] = df.loc['2015-02-01':].apply(lambda row: calculate(*row[['A', 'B']]), axis=1)
df
               A    B     C     D
 =================================
 2015-01-31    10   10    10    10
 2015-02-01    2    3     23    22 
 2015-02-02    10   60    290   280
 2015-02-03    10   100   3000  250

그래서 우리는 기본적으로 판다의 a와 이전의 계산된 값을 추적하는 전역 변수의 도움을 사용합니다.


와의 시간 비교for루프:

data = np.random.random(size=(1000, 4))
idx = pd.date_range('20150131', end='20171026')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df.C = np.nan

df.loc['2015-01-31', 'C'] = df.loc['2015-01-31', 'D']

%%timeit
for i in df.loc['2015-02-01':].index.date:
    df.loc[i, 'C'] = df.loc[(i - pd.DateOffset(days=1)).date(), 'C'] * df.loc[i, 'A'] + df.loc[i, 'B']

루프당 3.2초 ± 114 ms(1987 ± 표준시).dev. 7회 주행, 각 루프 1회)

data = np.random.random(size=(1000, 4))
idx = pd.date_range('20150131', end='20171026')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df.C = np.nan

def calculate(mul, add):
    global value
    value = value * mul + add
    return value

value = df.loc['2015-01-31', 'D']
df.loc['2015-01-31', 'C'] = value

%%timeit
df.loc['2015-02-01':, 'C'] = df.loc['2015-02-01':].apply(lambda row: calculate(*row[['A', 'B']]), axis=1)

루프당 1.82초 ± 64.4ms(1987 ± 표준시).dev. 7회 주행, 각 루프 1회)

그래서 평균 0.57배 더 빠릅니다.

오래된 질문이지만 아래 솔루션( for 루프 없음)이 도움이 될 수 있습니다.

def new_fun(df):
    prev_value = df.iloc[0]["C"]
    def func2(row):
        # non local variable ==> will use pre_value from the new_fun function
        nonlocal prev_value
        new_value =  prev_value * row['A'] + row['B']
        prev_value = row['C']
        return new_value
    # This line might throw a SettingWithCopyWarning warning
    df.iloc[1:]["C"] = df.iloc[1:].apply(func2, axis=1)
    return df

df = new_fun(df)

일반적으로 명시적 루프를 방지하는 핵심은 데이터 프레임의 2개 인스턴스를 rowindex-1==rowindex에 조인(결합)하는 것입니다.

그러면 df.apply() 함수를 수행할 수 있는 r과 r-1 행이 포함된 빅 데이터 프레임이 생성됩니다.

그러나 대규모 데이터 세트를 생성할 때의 오버헤드는 병렬 처리의 이점을 상쇄할 수 있습니다.

언급URL : https://stackoverflow.com/questions/34855859/is-there-a-way-in-pandas-to-use-previous-row-value-in-dataframe-apply-when-previ

반응형