2 votes

Comment optimiser la somme conditionnelle de plusieurs colonnes ?

J'ai un cadre de données très similaire à celui ci-dessous :

      Date        Col1    Col2    Col3 ...
   2020/11/04     -10      0       12
   2020/11/05      31      12      42
   2020/11/07      10      1      -12
   2020/11/08      2      -15      1
   2020/11/09      2       10      0
   .
   .
   .

Ma condition de somme est la suivante : lors du calcul de la somme pour la ligne suivante, si la somme est négative changez-le en 0. La sortie de l'opération devrait ressembler à ce qui suit.

      Date        Col1    Col2    Col3 ...
   2020/11/04       0      0       12
   2020/11/05      31      12      54
   2020/11/07      41      13      42
   2020/11/08      43      0       43
   2020/11/09      45      10      43
   .
   .
   .

J'y suis parvenu en bouclant et en appliquant des conditions à chaque ligne et colonne, mais pour les données volumineuses, les performances sont très faibles.

columns = diff.columns
    for col in columns:
        if diff.iloc[0].at[col] < 0:
            diff.iloc[0].at[col] = 0
    for i,row in diff.iterrows():
        if not i == diff.first_valid_index():
            prev = diff.index.get_loc(i) - 1
            for col in columns:
                diff.loc[i].at[col] = diff.loc[i].at[col] + diff.iloc[prev].at[col]
                if diff.loc[i].at[col] < 0:
                    diff.loc[i].at[col] = 0

Comment puis-je faire mieux dans les pandas ?

UPDATE ce fil aquí est très pertinente et ma solution est la suivante :

def adj_func(x):
    total = 0
    result = []
    for i, y in enumerate(x):
        total += y
        if total < 0:
            total = 0
        result.append(total)
    return result
diff[col_list].apply(adj_func)

3voto

piRSquared Points 159

njit

Si vous avez accès à Numba

from numba import njit

@njit
def f(a):
    for i, x in enumerate(a):
        if x < 0:
            a[i:] -= x
    return a

def g(s):
    return f(s.to_numpy().cumsum())

df.assign(**df[['Col1', 'Col2', 'Col3']].apply(g))

         Date  Col1  Col2  Col3
0  2020/11/04     0     0    12
1  2020/11/05    31    12    54
2  2020/11/07    41    13    42
3  2020/11/08    43     0    43
4  2020/11/09    45    10    43

Sinon, sans Numba

def h(s):
    a = s.to_numpy().cumsum()
    for i, x in enumerate(a):
        if x < 0:
            a[i:] -= x
    return a

df.assign(**df[['Col1', 'Col2', 'Col3']].apply(h))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X