web-dev-qa-db-fra.com

Pandas DataFrame utilise la valeur de la ligne précédente pour des conditions «si» compliquées pour déterminer la valeur actuelle

Je veux savoir s'il existe un moyen plus rapide de faire la boucle suivante? Peut-être utiliser la fonction Apply ou Rolling Apply pour réaliser cela Fondamentalement, j'ai besoin d'accéder à la valeur de la ligne précédente pour déterminer la valeur actuelle de la cellule.

df.ix[0] = (np.abs(df.ix[0]) >= So) * np.sign(df.ix[0])
for i in range(1, len(df)):
    for col in list(df.columns.values):
        if ((df[col].ix[i] > 1.25) & (df[col].ix[i-1] == 0)) | :
            df[col].ix[i] = 1
        Elif ((df[col].ix[i] < -1.25) & (df[col].ix[i-1] == 0)):
            df[col].ix[i] = -1
        Elif ((df[col].ix[i] <= -0.75) & (df[col].ix[i-1] < 0)) | ((df[col].ix[i] >= 0.5) & (df[col].ix[i-1] > 0)):
            df[col].ix[i] = df[col].ix[i-1]
        else:
            df[col].ix[i] = 0

Comme vous pouvez le voir, dans la fonction, je mets à jour la trame de données, j'ai besoin d'accéder à la ligne précédente la plus mise à jour, donc l'utilisation de shift ne fonctionnera pas.

Par exemple: Entrée:

A      B     C
1.3  -1.5   0.7
1.1  -1.4   0.6
1.0  -1.3   0.5
0.4   1.4   0.4

Production:

 A      B     C
1     -1      0
1     -1      0
1     -1      0
0      1      0
13
user5025141

vous pouvez utiliser la fonction . shift () pour accéder à précédent ou suivant valeurs:

valeur précédente de la colonne col:

df['col'].shift()

valeur suivante pour la colonne col:

df['col'].shift(-1)

Exemple:

In [38]: df
Out[38]:
   a  b  c
0  1  0  5
1  9  9  2
2  2  2  8
3  6  3  0
4  6  1  7

In [39]: df['prev_a'] = df['a'].shift()

In [40]: df
Out[40]:
   a  b  c  prev_a
0  1  0  5     NaN
1  9  9  2     1.0
2  2  2  8     9.0
3  6  3  0     2.0
4  6  1  7     6.0

In [43]: df['next_a'] = df['a'].shift(-1)

In [44]: df
Out[44]:
   a  b  c  prev_a  next_a
0  1  0  5     NaN     9.0
1  9  9  2     1.0     2.0
2  2  2  8     9.0     6.0
3  6  3  0     2.0     6.0
4  6  1  7     6.0     NaN
25
MaxU

Je suis surpris qu'il n'y ait pas non plus de solution native pandas à cela, car le changement et le roulement ne le font pas. J'ai conçu un moyen de le faire en utilisant la norme pandas mais je ne sais pas si elle fonctionne mieux que votre boucle ... Mes objectifs l'exigeaient juste pour la cohérence (pas la vitesse).

import pandas as pd

df = pd.DataFrame({'a':[0,1,2], 'b':[0,10,20]})

new_col = 'c'

def apply_func_decorator(func):
    prev_row = {}
    def wrapper(curr_row, **kwargs):
        val = func(curr_row, prev_row)
        prev_row.update(curr_row)
        prev_row[new_col] = val
        return val
    return wrapper

@apply_func_decorator
def running_total(curr_row, prev_row):
    return curr_row['a'] + curr_row['b'] + prev_row.get('c', 0)

df[new_col] = df.apply(running_total, axis=1)

print(df)
# Output will be:
#    a   b   c
# 0  0   0   0
# 1  1  10  11
# 2  2  20  33

Avertissement: J'ai utilisé pandas 0,16 mais avec seulement une légère modification, cela fonctionnera également pour les dernières versions.

D'autres avaient des questions similaires et j'ai également posté cette solution sur celles-ci:

4
CoreDump

@maxU a raison avec shift, je pense que vous pouvez même comparer directement les trames de données, quelque chose comme ceci:

df_prev = df.shift(-1)
df_out = pd.DataFrame(index=df.index,columns=df.columns)

df_out[(df>1.25) & (df_prev == 0)] = 1
df_out[(df<-1.25) & (df_prev == 0)] = 1
df_out[(df<-.75) & (df_prev <0)] = df_prev
df_out[(df>.5) & (df_prev >0)] = df_prev

La syntaxe peut être désactivée, mais si vous fournissez des données de test, je pense que cela pourrait fonctionner.

Vous évite d'avoir à boucler du tout.

EDIT - Mise à jour basée sur le commentaire ci-dessous

Je ferais de mon mieux pour ne pas parcourir le DF lui-même. Vous feriez mieux d'aller colonne par colonne, d'envoyer à une liste et de faire la mise à jour, puis de simplement réimporter. Quelque chose comme ce:

df.ix[0] = (np.abs(df.ix[0]) >= 1.25) * np.sign(df.ix[0]) 
for col in df.columns.tolist():
    currData = df[col].tolist()
    for currRow in range(1,len(currData)):
        if  currData[currRow]> 1.25 and currData[currRow-1]== 0:
            currData[currRow] = 1
        Elif currData[currRow] < -1.25 and currData[currRow-1]== 0:
            currData[currRow] = -1
        Elif currData[currRow] <=-.75 and currData[currRow-1]< 0:
            currData[currRow] = currData[currRow-1]
        Elif currData[currRow]>= .5 and currData[currRow-1]> 0:
            currData[currRow] = currData[currRow-1]
        else:
            currData[currRow] = 0
    df[col] = currData
1
flyingmeatball