Je analyse un ensemble d'événements, chacun ayant un type, un début et une heure de fin. Je cherche à résumer le nombre simultané de chaque événement au fil du temps dans la plage de temps.
Considérez l'ensemble de données ci-dessous, répertoriant les événements N1-N4, chacun avec des plages qui se chevauchent :
>>> data = {
... 'name' : [ 'N1', 'N2', 'N3', 'N4', 'N1', 'N2', 'N7'],
... 'start_dt_str' : ['01-01-2020', '01-03-2020', '01-01-2020', '01-01-2020', '01-03-2020', '01-04-2020','01-10-2020'],
... 'end_dt_str' : ['01-03-2020', '01-05-2020', '01-05-2020', '01-02-2020', '01-04-2020', '01-05-2020', '01-11-2020']
... }
>>> df = pd.DataFrame(data)
>>> df['start_dt'] = pd.to_datetime(df['start_dt_str'])
>>> df['end_dt'] = pd.to_datetime(df['end_dt_str'])
>>> del df['start_dt_str']
>>> del df['end_dt_str']
>>> df
name start_dt end_dt
0 N1 2020-01-01 2020-01-03
1 N2 2020-01-03 2020-01-05
2 N3 2020-01-01 2020-01-05
3 N4 2020-01-01 2020-01-02
4 N1 2020-01-03 2020-01-04
5 N2 2020-01-04 2020-01-05
6 N7 2020-01-10 2020-01-11
Mon objectif est de produire ce résumé, le nombre d'événements simultanés, par type, pour chaque date dans la plage. Voici la réponse correcte :
N1 N2 N3 N4 N7
2020-01-01 1 0 1 1 0
2020-01-02 1 0 1 1 0
2020-01-03 2 1 1 0 0
2020-01-04 1 2 1 0 0
2020-01-05 1 2 0 0 0
2020-01-06 0 0 0 0 0
2020-01-07 0 0 0 0 0
2020-01-08 0 0 0 0 0
2020-01-09 0 0 0 0 0
2020-01-10 0 0 0 0 1
2020-01-11 0 0 0 0 1
Notez qu'il y a des dates en double dans les colonnes start_dt et end_dt.
Remarquez également que la solution doit permettre de reconstituer les données pour remplir les dates manquantes avec des lignes contenant uniquement des zéros. Dans cet exemple, la date 01-09 n'apparaît pas en tant que date de début ou de fin, mais doit être présente dans la sortie. Dans le cas général, je souhaite pouvoir effectuer une reconstitution pour sélectionner des intervalles arbitraires.
Pour simplifier l'explication du problème, à la fois la période de déclaration et les données sont précises au jour près dans l'ensemble de données ci-dessus. Dans l'ensemble de données réel, start_dt et end_dt sont précis au milliseconde (mais contiennent toujours des doublons), et la période de déclaration pourrait être en heures, jours, semaines, etc.
Remarquez également qu'il existe des lacunes dans les données, donc une reconstitution est nécessaire pour produire la série de dates. (c'est-à-dire, même si les données sont précises au milliseconde, il manque des journéees entières).
J'ai essayé plusieurs approches qui NE fonctionnent PAS. Au début, cela semblait simple, j'ai essayé :
df.set_index(['name','start_dt']).groupby('name').resample('D',level='start_dt').ffill()
ValueError: L'augmentation de niveau= ou de sélection on= n'est pas prise en charge, utilisez .set_index(...) pour définir explicitement l'index comme chronologie
Cela conduit à ce problème de pandas concernant l'augmentation qui est ouvert, et fournit quelques contournements. Malheureusement, Nous ne pouvons pas utiliser seulement start_dt (ou end_dt) comme index car il n'est pas unique :
Traceback (most recent call last):
File "", line 1, in
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/resample.py", line 453, in pad
return self._upsample("pad", limit=limit)
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/resample.py", line 1095, in _upsample
res_index, method=method, limit=limit, fill_value=fill_value
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/util/_decorators.py", line 227, in wrapper
return func(*args, **kwargs)
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/frame.py", line 3856, in reindex
return super().reindex(**kwargs)
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/generic.py", line 4544, in reindex
axes, level, limit, tolerance, method, fill_value, copy
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/frame.py", line 3744, in _reindex_axes
index, method, copy, level, fill_value, limit, tolerance
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/frame.py", line 3760, in _reindex_index
new_index, method=method, level=level, limit=limit, tolerance=tolerance
File "/home/dcowden/envs/analysis-env/lib/python3.6/site-packages/pandas/core/indexes/base.py", line 3149, in reindex
"cannot reindex a non-unique index "
ValueError: impossible de réindexer un index non unique avec une méthode ou une limite
Cette question qui semble similaire à mon problème, mais ne remplit pas toutes les dates dans la plage pour chaque type d'événement :
>>> df.set_index('start_dt').groupby('name').resample('D').asfreq()
name end_dt
name start_dt
N1 2020-01-01 N1 2020-01-03
2020-01-02 NaN NaT
2020-01-03 N1 2020-01-04
N2 2020-01-03 N2 2020-01-05
2020-01-04 N2 2020-01-05
N3 2020-01-01 N3 2020-01-05
N4 2020-01-01 N4 2020-01-02
Cette solution semblait prometteuse, mais n'est pas exactement ce dont j'ai besoin non plus. Elle cherche essentiellement un seul événement dans une plage, mais ne comptabilise pas le nombre total en cours. Cependant, utiliser un IntervalIndex semble être un bon départ.
Je pense que cela devrait être assez simple, mais il est clair que mon expertise en pandas est lamentablement insuffisante.
Toute aide est grandement appréciée !
EDIT :