J'ai une trame de données:

ID           time
A1      2019-04-04 08:04:56 
A11     2019-04-04 08:14:22 
BB      2019-04-04 08:44:53
C5      2019-04-04 09:01:12
C1      2019-04-04 09:03:51
DD      2019-04-04 10:02:42

Donc, je veux obtenir un maximum de nombres d'identifiants dans un échantillon de "temps" de 20 minutes. Nous avons donc ici 2 identifiants uniques (2019-04-04 08:04:56 et 2019-04-04 08:14:22), 3 identifiants uniques (2019-04-04 08:44:53, 2019-04- 04 09:01:12, 2019-04-04 09:03:51) et 1 ID unique (2019-04-04 10:02:42). max (2,3,1) = 3. La réponse est donc 3. Comment puis-je l'obtenir? Le résultat souhaité est de l'obtenir en tant que dataframe:

time                    ID_num
2019-04-04 08:04:56        2
2019-04-04 08:44:53        3
2019-04-04 10:02:42        1

Je peux définir mon tableau d'échantillonnage comme ceci:

numpy.arange(8, 20, 0.3)

C'est-à-dire de 8 h 00 à 20 h 00 par incrément de 0,3 heure

3
french_fries 1 oct. 2020 à 01:24

3 réponses

Meilleure réponse
#Lets define some groups based on time differences

s=((df.time.diff(1) / np.timedelta64(1, 'm') >=20)|(df.time.diff(1).isna())).cumsum()

#Now let us groupby as we pick the first occurrence of time in a group and find how many ids are in each group using .groupby() and agg()

    df.groupby(s).agg(ftime=('time','first'), idcount=('ID','count'))



                 ftime      idcount
        time                             
1    2019-04-04 08:04:56        2
2    2019-04-04 08:44:53        3
3    2019-04-04 10:02:42        1
1
wwnde 30 sept. 2020 à 22:54

Vous pouvez parcourir les "heures", décaler chacune de 20 minutes et découper la trame de données pour vérifier la longueur d'un sous-ensemble. Ensuite, obtenez le maximum de chacun de ces sous-ensembles.

df= df.set_index("time")
offset = pd.Timedelta("20min")

lengths = []
for start_time in df.index:
    stop_time = start_time + offset
    chunk_length = df.loc[start_time:stop_time].shape[0]
    
    record = (start_time, chunk_length)
    lengths.append(record)
    
max(lengths, key=lambda item: item[1])
(Timestamp('2019-04-04 08:44:53'), 3)

La sortie indique que l'horodatage 2019-04-04 08:44:53 avait 3 enregistrements dans la trame de données qui existaient entre cet horodatage et 20 minutes après cet horodatage. Vous donnant ainsi la longueur maximale consécutive, ainsi que l'horodatage où la course consécutive a commencé.

1
Cameron Riddell 30 sept. 2020 à 22:35

Si vous êtes intéressé par la période de 20 minutes avec le plus d'échantillons, où la période de 20 minutes est librement définissable, vous pouvez le faire comme suit:

from datetime import timedelta

df= pd.DataFrame(
    dict(
        ID=['A1', 'A11', 'BB', 'C5', 'C1', 'DD'],
        time=pd.to_datetime(['2019-04-04 08:04:56', '2019-04-04 08:14:22', '2019-04-04 08:44:53', '2019-04-04 09:01:12', '2019-04-04 09:03:51', '2019-04-04 10:02:42'])
    )
)
df.dtypes

previous_time= df['time'].shift(1)
previous_time= df['time'].where(previous_time.isnull(), previous_time)
df['fake']= (df['time'] > previous_time + timedelta(minutes=20)).cumsum()
df2= df.merge(df, on='fake', suffixes=('', '_next'))

df2.dtypes

indexer= df2['time_next'].between(df2['time'], df2['time'] + timedelta(minutes=20))
result= df2[indexer].groupby('time').agg(
    count=('time', 'count'), 
    period_start=('time_next', 'min'),
    last_sample_in_period=('time_next', 'max')
)

result.sort_values('count', ascending=False).iloc[0]

Les dernières sorties de ligne:

count                                      3
period_start             2019-04-04 08:44:53
last_sample_in_period    2019-04-04 09:03:51
Name: 2019-04-04 08:44:53, dtype: object

La même chose peut également être obtenue avec ce code:

from datetime import timedelta

df= pd.DataFrame(
    dict(
        ID=['A1', 'A11', 'BB', 'C5', 'C1', 'DD'],
        time=pd.to_datetime(['2019-04-04 08:04:56', '2019-04-04 08:14:22', '2019-04-04 08:44:53', '2019-04-04 09:01:12', '2019-04-04 09:03:51', '2019-04-04 10:02:42'])
    )
)

df['period_end']= df['time'] + timedelta(minutes=20)
df['count']= 1
time_series=df['time']
continue_iteration= True
period_end_series= df['period_end']
while continue_iteration:
    time_series= time_series.shift(-1)
    in_period= (~time_series.isnull()) & (time_series <= period_end_series)
    df['count']+= in_period
    continue_iteration= in_period.any()
df.sort_values(by='count', ascending=False, inplace=True)
df.iloc[0]

La différence entre les deux méthodes est que la première produit un sous-ensemble du produit croisé en joignant le dataframe avec lui-même. Il convient aux petits ensembles de données et aux ensembles de données avec beaucoup de lacunes avec plus de 20 minutes et un nombre pas si grand d'échantillons maximum dans une période de 20 minutes. Le second n'a pas besoin de rejoindre le dataframe avec lui-même. Il décale simplement la colonne de temps tant qu'il y a au moins une correspondance avec la période. Donc, si m désigne le nombre maximum d'échantillons dans une période arbitraire de 20 minutes dans la trame de données, alors la boucle se termine exactement après m opérations de décalage (à cause du critère d'arrêt in_period.any())

1
jottbe 3 oct. 2020 à 19:13