Je cherche un moyen efficace de traiter les données suivantes dans pandas.
J'ai un dataframe contenant plusieurs centaines de milliers de timestamps de début et de fin :
data_df
start_ts end_ts
0 2019-06-10 12:00:00+00:00 2019-06-10 22:30:00+00:00
1 2019-06-11 12:00:00+00:00 2019-06-11 13:30:00+00:00
2 2019-06-11 14:00:00+00:00 2019-06-11 19:00:00+00:00
3 2019-06-14 12:00:00+00:00 2019-06-14 18:30:00+00:00
4 2019-06-10 12:00:00+00:00 2019-06-10 21:30:00+00:00
5 2019-06-11 12:00:00+00:00 2019-06-11 18:30:00+00:00
...
J'ai également un ensemble d'intervalles de temps étiquetés (tp1
-tp10
). Il y a 10 intervalles par jour, mais les heures de ces intervalles peuvent changer d'un jour à l'autre (par exemple - tp1
peut être de 00:00 à 01:30 un jour, puis de 00:00 à 01:45 un autre jour). Chaque ensemble de données à traiter comporte 7 jours, avec 10 périodes de temps par jour, donc l'ensemble des plages est de taille 70, et ressemble à ceci :
labeled_bins_df
start_range end_range label
0 2019-06-10 00:00:00+00:00 2019-06-10 04:30:00+00:00 tp1
1 2019-06-10 04:30:00+00:00 2019-06-10 09:45:00+00:00 tp2
2 2019-06-10 09:45:00+00:00 2019-06-10 12:30:00+00:00 tp3
...
Ce que je voudrais, c'est une table avec les données originales de data_df
, mais avec des colonnes supplémentaires, tp1
à tp10
, avec le nombre de minutes pour chaque ligne :
timed_bins
start_ts end_ts tp1 tp2 tp3 tp4 ...
0 2019-06-10 12:00:00+00:00 2019-06-10 22:30:00+00:00 0 0 30 120 ...
1 2019-06-11 12:00:00+00:00 2019-06-11 13:30:00+00:00 0 45 45 0 ...
Je le fais actuellement de manière naïve, en bouclant sur mes lignes et en cherchant les intervalles dans lesquels se trouve chaque ligne de données, et comme vous pouvez l'imaginer, c'est assez lent. Y a-t-il une manipulation pandas à effectuer pour faire ce genre de regroupement sur les plages de dates ?
EDIT : Une pensée, qui pourrait aider à réfléchir dans une nouvelle direction. Si je convertissais tous mes timestamps (à la fois dans mes données et dans mes intervalles étiquetés) en timestamps Unix (secondes depuis le 1er janvier 1970), il suffirait d'effectuer un regroupement/somme basé sur des plages entières plutôt que des dates. Cela donnerait alors le nombre de secondes dans chaque intervalle, il suffirait de diviser par 60, et j'obtiendrai mes minutes dans chaque intervalle. Cela élimine toutes les préoccupations concernant les limites de dates, etc.
EDIT 2 : Comme demandé, voici un ensemble de données d'exemple simplifié, en utilisant trois intervalles de temps différents. J'ai spécifiquement fait en sorte qu'un des échantillons de données (la deuxième ligne) s'étende sur 2 jours. De plus, il y a un result_df
qui montre le résultat attendu.
data_samples = [
{'start_ts': '2019-06-10T12:00:00+0000', 'end_ts': '2019-06-10T22:30:00+0000'},
{'start_ts': '2019-06-10T22:00:00+0000', 'end_ts': '2019-06-11T05:30:00+0000'},
{'start_ts': '2019-06-10T10:00:00+0000', 'end_ts': '2019-06-10T14:15:00+0000'},
{'start_ts': '2019-06-12T08:07:00+0000', 'end_ts': '2019-06-12T18:22:00+0000'},
{'start_ts': '2019-06-11T14:03:00+0000', 'end_ts': '2019-06-11T15:30:00+0000'},
{'start_ts': '2019-06-11T02:33:00+0000', 'end_ts': '2019-06-11T10:31:00+0000'}
]
data_set = [{
'start_ts': datetime.datetime.strptime(x['start_ts'], '%Y-%m-%dT%H:%M:%S%z'),
'end_ts': datetime.datetime.strptime(x['end_ts'], '%Y-%m-%dT%H:%M:%S%z')} for x in data_samples]
data_df = pd.DataFrame(data_set)[['start_ts', 'end_ts']]
time_bin_samples = [
{'start_ts': '2019-06-10T00:00:00+0000', 'end_ts': '2019-06-10T08:15:00+0000', 'label': 't1'},
{'start_ts': '2019-06-10T08:15:00+0000', 'end_ts': '2019-06-10T18:00:00+0000', 'label': 't2'},
{'start_ts': '2019-06-10T18:00:00+0000', 'end_ts': '2019-06-11T00:00:00+0000', 'label': 't3'},
{'start_ts': '2019-06-11T00:00:00+0000', 'end_ts': '2019-06-11T09:00:00+0000', 'label': 't1'},
{'start_ts': '2019-06-11T09:00:00+0000', 'end_ts': '2019-06-11T19:15:00+0000', 'label': 't2'},
{'start_ts': '2019-06-11T19:15:00+0000', 'end_ts': '2019-06-12T00:00:00+0000', 'label': 't3'},
{'start_ts': '2019-06-12T00:00:00+0000', 'end_ts': '2019-06-12T10:30:00+0000', 'label': 't1'},
{'start_ts': '2019-06-12T10:30:00+0000', 'end_ts': '2019-06-12T12:00:00+0000', 'label': 't2'},
{'start_ts': '2019-06-12T12:00:00+0000', 'end_ts': '2019-06-13T00:00:00+0000', 'label': 't3'},
]
time_bin_set = [{
'start_ts': datetime.datetime.strptime(x['start_ts'], '%Y-%m-%dT%H:%M:%S%z'),
'end_ts': datetime.datetime.strptime(x['end_ts'], '%Y-%m-%dT%H:%M:%S%z'),
'label': x['label']} for x in time_bin_samples
]
time_bin_df = pd.DataFrame(time_bin_set)[['start_ts', 'end_ts', 'label']]
result_set = [
{'t1': 0, 't2': 360, 't3': 270},
{'t1': 330, 't2': 0, 't3': 120},
{'t1': 0, 't2': 255, 't3': 0},
{'t1': 143, 't2': 90, 't3': 382},
{'t1': 0, 't2': 87, 't3': 0},
{'t1': 387, 't2': 91, 't3': 0}
]
result_df = pd.DataFrame(result_set)