0
votes

Comment filtrer des points de données avec des horodatages très proches

J'ai dataframe df:

          Id    timestamp               data    sig     events1 Start   Peak    Timediff    Datadiff

104514  104755  2012-03-21 16:23:21.423 20.0    -1.0    0.0     0.0     1.0     0.100       0.5
104623  104864  2012-03-22 04:27:04.550 19.5    0.0     0.0     0.0     0.0     43423.127   -0.5
104630  104871  2012-03-22 04:27:11.670 19.5    -1.0    0.0     0.0     1.0     7.120       0.0
105148  105389  2012-03-23 06:12:24.623 18.5    1.0     1.0     0.0     0.0     0.100       -0.5

Pour les lignes où Timediff == 0.100 et timestamp code > ont la même heure, minute et seconde (par exemple 16: 23: 21.323 et 16: 23: 21.423 ), supprimez le premier de la paire, c.-à-d. 16: 23: 21.323 (la ligne précédente). Comment puis-je faire cela?

Résultat attendu:

          Id    timestamp               data    sig     events1 Start   Peak    Timediff    Datadiff
104513  104754  2012-03-21 16:23:21.323 19.5    1.0     0.0     1.0     0.0     28732.920   0.5
104514  104755  2012-03-21 16:23:21.423 20.0    -1.0    0.0     0.0     1.0     0.100       0.5
104623  104864  2012-03-22 04:27:04.550 19.5    0.0     0.0     0.0     0.0     43423.127   -0.5
104630  104871  2012-03-22 04:27:11.670 19.5    -1.0    0.0     0.0     1.0     7.120       0.0
105147  105388  2012-03-23 06:12:24.523 19.0    -1.0    0.0     0.0     0.0     92712.853   -0.5
105148  105389  2012-03-23 06:12:24.623 18.5    1.0     1.0     0.0     0.0     0.100       -0.5


8 commentaires

L'index de votre dataframe est-il ordonné? Peut-il être réinitialisé?


@jfaccioni Oui. Je pense que cela peut être du repos - y a-t-il des problèmes avec la réinitialisation normale de l'index?


Cela dépend si l'index a une signification pour vous / vos données ou non.


L'agrégation des séries temporelles à une fréquence requise est le meilleur dôme par df.resample ()


@jfaccioni Dans ce cas, je pense que l'index n'a pas de signification particulière.


@nilsinelabore pourriez-vous coller ici le code pour votre exemple de dataframe ad df = pd.Dataframe (data)? il sera plus confortable de vous aider


@wwnde Est-ce que df.resample () me permet de spécifier les conditions supplémentaires? Je veux dire que les lignes que je veux supprimer ne se produisent pas à des fréquences fixes (c'est-à-dire pas toutes les autres lignes) mais sont des événements irréguliers dans la trame de données.


Indiquez la fréquence. Si indiqué, rééchantillonner choisissez le dernier élément de jour demandé. Par exemple, le mois de rééchantillonnage choisira la dernière date du mois. J'ai trouvé la lecture de la documentation utile car elle contient à la fois des explications et des exemples.


3 Réponses :


1
votes

Il existe peut-être un moyen plus simple d'y parvenir, mais je pense que cela fonctionne compte tenu de vos conditions:

# reset index to make our life easier
df = df.reset_index()

# get rows with small timediffs
small_timediffs = df.loc[df.Timediff <= 0.1]
# get rows immediately above rows with small timediffs
prev_small_timediffs = df.loc[small_timediffs.index-1]

# helper function to allow comparison of timestamps without milisseconds
remove_milisseconds = lambda x: x.split('.')[0]

# compare if timestamps from rows with small timediffs 
# and rows above them are the same 
stamps = small_timediffs.timestamp.apply(remove_milisseconds).values
prev_stamps = prev_small_timediffs.timestamp.apply(remove_milisseconds).values
cond = (stamps == prev_stamps)

# extract results based on both conditions
# (small timediff and same timestamp)
result = df.loc[~df.index.isin(small_timediffs.loc[cond].index-1)]


2 commentaires

Merci pour votre réponse! Il a renvoyé AttributeError: l'objet 'Timestamp' n'a pas d'attribut 'split'


Je devrais voir vos données réelles pour comprendre ce qui ne va pas. Mon code fonctionne lorsque je copie le dataframe de votre question et le charge dans des pandas avec df = pd.read_clipboard .



1
votes

L'idée est de regrouper les dates et heures de plancher par seconde par Series.dt.floor , puis supprimez la ligne précédente s'il existe au moins un masque correspondant m1:

m1 = df3['Timediff'].eq(0.100) & df3['Start'].ne(1) & df3['Start'].shift(1).ne(1)

MODIFIER: Répondre au commentaire du formulaire avec les constions suivantes:

#convert to datetimes
df['timestamp'] = pd.to_datetime(df['timestamp'])

#test 0.1
m1 = df['Timediff'].eq(0.1)
#test previous values of m1
m2 = m1.shift(-1, fill_value=False)
#test if in groups floored by seconds is at least one True in m1
m3 = m1.groupby([df['timestamp'].dt.floor('S')]).transform('any')
#filter chained m3 with m2 and invert mask
df = df[~(m3 & m2)]
print (df)
            Id               timestamp  data  sig  events1  Start  Peak  \
104514  104755 2012-03-21 16:23:21.423  20.0 -1.0      0.0    0.0   1.0   
104623  104864 2012-03-22 04:27:04.550  19.5  0.0      0.0    0.0   0.0   
104630  104871 2012-03-22 04:27:11.670  19.5 -1.0      0.0    0.0   1.0   
105148  105389 2012-03-23 06:12:24.623  18.5  1.0      1.0    0.0   0.0   

         Timediff  Datadiff  
104514      0.100       0.5  
104623  43423.127      -0.5  
104630      7.120       0.0  
105148      0.100      -0.5  


10 commentaires

C'est ce que je veux. Merci pour le code succinct!


Btw j'ai ajouté une autre condition en utilisant df3 ['m1'] = df3 ['Timediff']. Eq (0.100) & df3 ['Start']. Ne (1) & df3 ['Start']. Shift ( 1) .ne (1) (df3 [ Start ] et df3 ['Start']. Shift (1) ne peut pas être 1 ). Seriez-vous en mesure d'ajouter cette condition à votre code modifié? Merci.


@nilsinelabore - Je suis d'accord, le code est sympa. Il filtre 0.100 et supprime 1,1 valeurs consécutives


Oui. J'ai appris l'astuce à partir du code dans votre réponse précédente; Pouvez-vous modifier votre nouvelle réponse en ajoutant cette condition supplémentaire s'il vous plaît?


@nilsinelabore - Une chose, ça marche correctement? Sinon, est-il possible d'ajouter la sortie attendue par de nouvelles conditions?


Oui, les deux fonctionnent. Je veux juste ajouter une autre condition: pour les lignes où Timediff == 0.100 , et horodatage ont les mêmes heure, minute et seconde (par exemple. 16: 23: 21.323 et 16: 23: 21.423 ), supprimez le premier de la paire, mais si df3 ['Start'] ou df3 ['Start'] .shift (1) vaut 1 pour cette ligne, nous ne supprimons pas la ligne car c'est important .


Ne vous inquiétez pas si c'est trop de problèmes. Votre code précédent fonctionnait parfaitement :)


@nilsinelabore - Je suis un peu confus maintenant, mais j'ai ajouté une solution d'un commentaire à l'autre.


Ouais c'est ce que je veux dire! Désolé pour la confusion. Merci beaucoup :)


Je viens de réaliser un problème, des cas comme 11: 56: 51.980 et 11: 56: 52.080 seront manqués car ils ne partagent pas les mêmes secondes. Existe-t-il un moyen de résoudre ce problème?



1
votes

J'ai ajouté des valeurs à votre trame de données pour recevoir les mêmes heures, minutes et secondes pour les enregistrements avec une valeur = 0,100

df = pd.DataFrame({'data':['16:23:21.323 19.5','16:23:21.423 20.0','04:27:04.550 19.5',
                               '04:27:11.670 19.5','06:12:24.523 19.0','06:12:24.623 18.5',
                               '16:23:21.323 19.5','06:12:24.523 19.0'],
                       'timestamp':['2012-03-21','2012-03-21','2012-03-22','2012-03-22','2012-03-23','2012-03-23',
                                    '2012-03-23','2012-03-23'],
                       'timediff':[28732.920,0.100,43423.127,7.120,0.100,0.100,92712.853,0.100]})

df['h_m_s'] = df['data'].str.extract(r'(.*) ')

                data   timediff   timestamp         h_m_s
0  16:23:21.323 19.5  28732.920  2012-03-21  16:23:21.323
1  16:23:21.423 20.0      0.100  2012-03-21  16:23:21.423
2  04:27:04.550 19.5  43423.127  2012-03-22  04:27:04.550
3  04:27:11.670 19.5      7.120  2012-03-22  04:27:11.670
4  06:12:24.523 19.0      0.100  2012-03-23  06:12:24.523
5  06:12:24.623 18.5      0.100  2012-03-23  06:12:24.623
6  16:23:21.323 19.5  92712.853  2012-03-23  16:23:21.323
7  06:12:24.523 19.0      0.100  2012-03-23  06:12:24.523

df_same = df[(df.timediff==0.100)]
df = df[~(df.timediff==0.100)]
df_same = df_same.drop_duplicates(subset=['h_m_s'],keep='first')
df=pd.concat([df,df_same])
print(df)
                data   timediff   timestamp         h_m_s
0  16:23:21.323 19.5  28732.920  2012-03-21  16:23:21.323
2  04:27:04.550 19.5  43423.127  2012-03-22  04:27:04.550
3  04:27:11.670 19.5      7.120  2012-03-22  04:27:11.670
6  16:23:21.323 19.5  92712.853  2012-03-23  16:23:21.323
1  16:23:21.423 20.0      0.100  2012-03-21  16:23:21.423
4  06:12:24.523 19.0      0.100  2012-03-23  06:12:24.523
5  06:12:24.623 18.5      0.100  2012-03-23  06:12:24.623


0 commentaires