Панды объединяют строки с одинаковым временем начала и окончания - PullRequest
0 голосов
/ 09 сентября 2018

У меня есть файл с несколькими данными из доступа Wi-Fi.База данных разделена на несколько столбцов: user_id, start (при подключении устройства к маршрутизатору), end (при отключении устройства от маршрутизатора).

Пример:

user_id   start     end 
1   15/05/16 13:51  15/05/16 14:06 
1   15/05/16 14:06  15/05/16 14:32 
1   15/05/16 14:32  15/05/16 14:34 
2   15/05/16 11:14  15/05/16 11:25 
2   15/05/16 11:25  15/05/16 12:09 
2   15/05/16 12:14  15/05/16 12:42 
2   15/05/16 17:33  15/05/16 17:41 
2   15/05/16 17:41  15/05/16 18:27

Проблема в том, что иногда устройства отключаются и снова подключаются.Я хотел бы сгруппировать данные в случае, подобном этому:

user_id start   end
1   15/05/16 13:51  15/05/16 14:34
2   15/05/16 11:14  15/05/16 12:42
2   15/05/16 17:33  15/05/16 18:27

Есть ли эффективный способ сделать это с пандами?

Ответы [ 3 ]

0 голосов
/ 09 сентября 2018

Вы можете использовать функцию pandas Groupby для идентификатора пользователя, один раз, если вы разделили данные каждого идентификатора пользователя, вычислите разницу между началом и концом. Затем примените кумулятивную сумму к отдельным группам, а затем вы можете извлечь начало первой строки и конец последней строки каждой группы: -)

def func(threshold,df1):
    # Calculating the difference of start and end time of each row
    df1['diff1'] = ((df1.start - df1.end.shift()).dt.seconds).fillna(0)
    # if difference is less than threshold equating with 0
    df1.loc[df1['diff1'] < threshold, 'diff1'] = 0
    # assigning cummulative sum of column
    df1['diff1'] = df1.diff1.cumsum()
    # Grouping the cummulatice sum of time differences and keeping only required row
    df1 = df1.groupby(['diff1']).apply(lambda x: x.set_value(0,'end',x['end'].tail(1).values[0]).loc[x.head(1).index.values[0]])
    return df1

data.start = pd.to_datetime(data.start)
data.end = pd.to_datetime(data.end) 
# Threshold setting to consider the difference "threshold is in seconds"
threshold = 500
# Calling the function for each ID
data.groupby('userid').apply(lambda x: func(threshold,x))

Из:

     userid        start                end        diff1
userid  diff1               
1        0.0    1.0 2016-05-15 13:51:00 2016-05-15 14:34:00 0.0
2        0.0    2.0 2016-05-15 11:14:00 2016-05-15 11:25:00 0.0
2     17460.0   2.0 2016-05-15 11:14:00 2016-05-15 11:25:00 0.0
0 голосов
/ 09 сентября 2018

Во-первых, нам нужны столбцы: «начало» и «конец» в правильном формате:

df[['start']] =pd.to_datetime(df['start'])
df[['end']] =pd.to_datetime(df['end'])

Затем вам нужно сгенерировать новый столбец, чтобы определить состояние другого соединения:

df['id_connection'] = False

Следующим шагом является определение первого наблюдения нового пользователя (это всегда будет новое соединение):

indexes = df.drop_duplicates(subset='user_id', keep='first').index
df.loc[indexes,'id_connection'] = True

Теперь нам нужно определить другое условие при создании нового соединения. Вам нужно принять критерии, чтобы определить, является ли это новое соединение или нет:

diff_ = (df['start'].values[1:] - df['end'].values[:-1]).astype('float')
time_criteria_mins = 5
new_connection = np.insert(( diff_ / (60*10**9)) > time_criteria_mins, 0, 1)

Затем вам нужно объединить два условия: (1) новый пользователь (2) один и тот же пользователь с временем между соединениями более 5 минут:

df['id_connection'] = (new_connection | df['id_connection']).cumsum()

Наконец, мы создаем группу по атрибуту id_connection:

gb = df.groupby('id_connection').agg({'user_id': 'first', 'start': 'first','end':'last'})

Примечание: будьте осторожны, чтобы убедиться, что кадр данных отсортирован по (пользователю и дате и времени начала)

0 голосов
/ 09 сентября 2018

У нас может быть что-то вроде этого

import pandas as pd
data=pd.DataFrame(
    [
        [1,'15/05/16 13:51','15/05/16 14:06'],
        [1,'15/05/16 14:06','15/05/16 14:32'], 
        [1,'15/05/16 14:32','15/05/16 14:34'], 
        [2,'15/05/16 11:14','15/05/16 11:25'],
        [2,'15/05/16 11:25','15/05/16 12:09'],
        [2,'15/05/16 12:14','15/05/16 12:42'],
        [2,'15/05/16 17:33','15/05/16 17:41'], 
        [2,'15/05/16 17:41','15/05/16 18:27']
    ]
    ,columns=['userid','start','end']
)

from datetime import datetime
data['start']=data['start'].map(lambda x: datetime.strptime(x,'%d/%m/%y %H:%M'))
data['end']=data['end'].map(lambda x: datetime.strptime(x,'%d/%m/%y %H:%M'))

diffData=[]
for i in range(1, len(data)):
    diffData.append((data.loc[i,'start'] - data.loc[i-1,'end']).seconds / 60)

data['diff']=[0] + diffData

def getStartEnd(tempData,THRESHOLD):
    tempData=tempData.reset_index()
    finalData=[]
    startTime=tempData.loc[0,'start']
    for i in range(1,len(tempData)):
        if(tempData.loc[i,'diff'] > THRESHOLD):
            finalData.append([tempData.loc[i,'userid'],startTime,tempData.loc[i-1,'end']])
            startTime=tempData.loc[i,'start']
    finalData.append([tempData.loc[i,'userid'],startTime,tempData.loc[i,'end']])
    return(pd.DataFrame(finalData,columns=['userid','start','end']))

finalData=pd.DataFrame(columns=['userid','start','end'])
for user in data['userid'].unique():
    finalData=pd.concat([finalData,getStartEnd(data[data['userid']==user],60)])

print(finalData)

  userid               start                 end
0      1 2016-05-15 13:51:00 2016-05-15 14:34:00
0      2 2016-05-15 11:14:00 2016-05-15 12:42:00
1      2 2016-05-15 17:33:00 2016-05-15 18:27:00
...