2017-10-13 8 views
2

Préoccupés est cette exemplaire pandas géants dataframe:moyenne conditionnelle et la somme des lignes précédentes N en pandas géants dataframe

 Measurement Trigger Valid 
    0   2.0 False True 
    1   4.0 False True 
    2   3.0 False True 
    3   0.0  True False 
    4  100.0 False True 
    5   3.0 False True 
    6   2.0 False True 
    7   1.0  True True 

Chaque fois que Trigger est True, je souhaite calculer la somme et la moyenne des 3 dernières (à partir de courant) valide des mesures. Les mesures sont considérées comme valides si la colonne Valid est True. Donc, clarifions en utilisant les deux exemples ci-dessus dans la trame de données:

  1. Index 3: Indices 2,1,0 devraient être utilisés. Sum = 9.0, Mean = 3.0
  2. Index 7: Les index 7,6,5 doivent être utilisés. Expected Sum = 6.0, Mean = 2.0

J'ai essayé pandas.rolling et la création de nouvelles, déplacé des colonnes, mais n'a pas réussi. Voir l'extrait suivant de mes tests (qui devraient directement fonctionner):

import unittest 
import pandas as pd 
import numpy as np 
from pandas.util.testing import assert_series_equal 

def create_sample_dataframe_2(): 
    df = pd.DataFrame(
     {"Measurement" : [2.0, 4.0, 3.0, 0.0, 100.0, 3.0, 2.0, 1.0 ], 
     "Valid"  : [True, True, True, False, True, True, True, True], 
     "Trigger"  : [False, False, False, True, False, False, False, True], 
     }) 
    return df 

def expected_result(): 
    return pd.DataFrame({"Sum" : [np.nan, np.nan, np.nan, 9.0, np.nan, np.nan, np.nan, 6.0], 
         "Mean" :[np.nan, np.nan, np.nan, 3.0, np.nan, np.nan, np.nan, 2.0]}) 

class Data_Preparation_Functions(unittest.TestCase): 

    def test_backsummation(self): 
     N_SUMMANDS = 3 
     temp_vars = [] 

     df = create_sample_dataframe_2() 
     for i in range(0,N_SUMMANDS): 
      temp_var = "M_{0}".format(i) 
      df[temp_var] = df["Measurement"].shift(i) 
      temp_vars.append(temp_var) 

     df["Sum"] = df[temp_vars].sum(axis=1) 
     df["Mean"] = df[temp_vars].mean(axis=1) 
     df.loc[(df["Trigger"]==False), "Sum"] = np.nan 
     df.loc[(df["Trigger"]==False), "Mean"] = np.nan 

     assert_series_equal(expected_result()["Sum"],df["Sum"]) 
     assert_series_equal(expected_result()["Mean"],df["Mean"]) 

    def test_rolling(self): 
     df = create_sample_dataframe_2() 
     df["Sum"] = df[(df["Valid"] == True)]["Measurement"].rolling(window=3).sum() 
     df["Mean"] = df[(df["Valid"] == True)]["Measurement"].rolling(window=3).mean() 

     df.loc[(df["Trigger"]==False), "Sum"] = np.nan 
     df.loc[(df["Trigger"]==False), "Mean"] = np.nan 
     assert_series_equal(expected_result()["Sum"],df["Sum"]) 
     assert_series_equal(expected_result()["Mean"],df["Mean"]) 


if __name__ == '__main__': 
    suite = unittest.TestLoader().loadTestsFromTestCase(Data_Preparation_Functions) 
    unittest.TextTestRunner(verbosity=2).run(suite) 

Toute aide ou solution est grandement appréciée. Merci et à bientôt!

EDIT: Précision: Ceci est la trame de données résultante je me attends:

 Measurement Trigger Valid Sum Mean 
    0   2.0 False True NaN NaN 
    1   4.0 False True NaN NaN 
    2   3.0 False True NaN NaN 
    3   0.0  True False 9.0 3.0 
    4  100.0 False True NaN NaN 
    5   3.0 False True NaN NaN 
    6   2.0 False True NaN NaN 
    7   1.0  True True 6.0 2.0 

EDIT2: Une autre précision:

Je ne en effet pas mésestimer, mais je ne l'ai pas fait mes intentions aussi clairement que je Pourrais avoir. Voici un autre essai en utilisant la même dataframe:

Desired dataframe, relevant fields highlighted

Examinons d'abord la colonne Trigger: Nous trouvons le premier True indice 3 (rectangle vert). Donc, l'index 3 est le point où nous commençons à chercher. Il n'y a pas de mesure valide à l'index 3 (la colonne Valid est False, rectangle rouge). Ainsi, nous commençons à aller plus loin dans le temps, jusqu'à ce que nous ayons accumulé trois lignes, où Valid est True. Cela se produit pour les indices 2,1 et 0. Pour ces trois indices, on calcule la somme et la moyenne de la colonne Measurement (rectangle bleu):

  • SUM: 2,0 + 4,0 + 3,0 = 9,0
  • MEAN: (2,0 + 4,0 + 3,0)/3 = 3,0

maintenant, nous commençons la prochaine itération de ce petit algorithme: Regardez à nouveau pour la prochaine True dans la colonne Trigger. Nous le trouvons à l'index 7 (rectangle vert). Il y a aussi un mesuremnt valide à l'index 7, donc nous l'incluons cette fois. Pour notre calcul, nous utilisons les indices 7,6 et 5 (rectangle vert), et ainsi obtenir:

  • SUM: 1,0 + 2,0 + 3,0 = 6,0
  • MEAN: (1,0 + 2,0 + 3,0)/3 = 2.0

J'espère que cela éclaircira davantage ce petit problème.

+0

J'ai vu une question comme celui-ci, est essentiellement à détecter la cumsum, je vais maintenant trouver dehors! – ileadall42

Répondre

1

Heres une option, prenez la moyenne mobile sur 3 période et la somme

df['RollM'] = df.Measurement.rolling(window=3,min_periods=0).mean() 

df['RollS'] = df.Measurement.rolling(window=3,min_periods=0).sum() 

Réglez maintenant Faux Déclencheurs équivaut à NaN

df.loc[df.Trigger == False,['RollS','RollM']] = np.nan 

rendements

Measurement Trigger Valid  RollM RollS 
0   2.0 False True  NaN NaN 
1   4.0 False True  NaN NaN 
2   3.0 False True  NaN NaN 
3   0.0  True False 2.333333 7.0 
4  100.0 False True  NaN NaN 
5   3.0 False True  NaN NaN 
6   2.0 False True  NaN NaN 
7   1.0  True True 2.000000 6.0 

Edition, mis à jour pour reflec t argument valable

df['mean'],df['sum'] = np.nan,np.nan 

roller = df.Measurement.rolling(window=3,min_periods=0).agg(['mean','sum']) 

df.loc[(df.Trigger == True) & (df.Valid == True),['mean','sum']] = roller 

df.loc[(df.Trigger == True) & (df.Valid == False),['mean','sum']] = roller.shift(1) 

Les rendements

Measurement Trigger Valid mean sum 
0   2.0 False True NaN NaN 
1   4.0 False True NaN NaN 
2   3.0 False True NaN NaN 
3   0.0  True False 3.0 9.0 
4  100.0 False True NaN NaN 
5   3.0 False True NaN NaN 
6   2.0 False True NaN NaN 
7   1.0  True True 2.0 6.0 
+0

Ce n'est pas tout à fait ce que je cherche. Pour clarifier, j'ai ajouté le résultat attendu sous forme de tableau au message original. – bolla

+0

Pouvez-vous expliquer plus loin comment c'est incorrect? Il correspond à votre échantillon, sauf pour les chiffres de l'index trois, je crois que vous avez manqué de les calculer, et a fait les trois précédents, sans compter la valeur actuelle @bolla – DJK

+0

Voir deuxième édition dans mon message original. – bolla