Pandas: условное самосоединение на основе нескольких условий

#python #pandas

#python #pandas

Вопрос:

Я знаком с тем, как объединить / объединить два фрейма данных Pandas следующим образом:

 result = pd.merge(user_usage,
                 user_device[['use_id', 'platform', 'device']],
                 on='use_id', 
                 how='right')
 

Однако я не знаю, как мне выполнить самосоединение таблицы:

 id    rank   ts
1     1      2015-11-01
1     2      2015-11-03
1     3      2015-11-07
 

где я хочу сравнить временную метку каждого идентификатора-ранга со следующей.

В синтаксисе SQL и Scala это просто. В SQL я бы просто сделал что-то вроде (в псевдокоде):

 SELECT *
FROM df a
LEFT JOIN df b
ON a.id = b.id amp; (a.rank   1) = b.rank;
 

В pd.merge синтаксисе я никогда не видел такого примера и до сих пор не могу его найти.

Чтобы было ясно, я ищу:

 id    rank   ts           ts_2         time_since_previous_obs
1     1      2015-11-01   <null>       0
1     2      2015-11-03   2015-11-01   2
1     3      2015-11-07   2015-11-03   4
 

Возможно ли это с помощью Python Pandas merge или join синтаксиса? Есть ли другой более разумный способ?

Комментарии:

1. попробуйте df['last_obs_since'] = df.apply(lambda row,cmp: row['ts']-cmp.loc[row.name]['ts'],axis=1,args=[df.shift(1)]) или df['last_obs_since'] = df['ts'] - df.shift(1)['ts']

Ответ №1:

Ну, вы можете изменить ранг перед слиянием:

 (df.merge(df.assign(rank=df['rank'] - 1),
          on=['id','rank'], how='left')
   .assign(last_obs_since=lambda x: x['ts_y'] - x['ts_x'])
)
 

Вывод:

    id  rank       ts_x       ts_y last_obs_since
0   1     1 2015-11-01 2015-11-02         1 days
1   1     2 2015-11-02 2015-11-03         1 days
2   1     3 2015-11-03        NaT            NaT
 

Ответ №2:

 #create a list from ts and shift by one to make ts2
ts2 =df["ts"][:-1].tolist()
ts2.insert(0,None)

#append list to dataframe
df["ts2"] = ts2

#calculate difference
df["diff"] = df["ts"] - df["ts2"]
print(df)
 

вывод:

введите описание изображения здесь

Ответ №3:

Также должно работать следующее,

 df['ts2'] = df.shift(1)['ts']
df['last_obs_since'] = df['ts'] - df['ts2']