Pandas DataFrame在<,>上加入2个表条件

时间:2018-03-07 13:51:59

标签: python pandas

我想在用户转换后删除所有会话(并删除转换当天发生的会话)

full_sessions = pd.DataFrame(data={'user_id':[1,1,2,3,3], 'visit_no':[1,2,1,1,2], 'date':['20180307','20180308','20180307','20180308','20180308'], 'result':[0,1,1,0,0]})
print full_sessions 

       date  result  user_id  visit_no
0  20180307       0        1         1
1  20180308       1        1         2
2  20180307       1        2         1
3  20180308       0        3         1
4  20180308       0        3         2

人们什么时候转换?

conversion = full_sessions[full_sessions['result'] == 1][['user_id','date']]
print conversion
   user_id      date
0        1  20180308
2        2  20180307

理想输出:

       date  result  user_id  visit_no
0  20180307       0        1         1
3  20180308       0        3         1
4  20180308       0        3         2

SQL中我想要什么?

SQL would be:
SELECT * FROM (
SELECT * FROM full_sessions
LEFT JOIN conversion
ON 
full_sessions.user_id = conversion.user_id AND full_sessions.date <  conversion.date
UNION ALL
SELECT * FROM full_sessions
WHERE user_id NOT IN (SELECT user_id FROM conversion)
)

4 个答案:

答案 0 :(得分:1)

IIUC在pandas中使用merge

full_sessions.merge(conversion,on='user_id',how='left').loc[lambda x : (x.date_y>x.date_x)|(x.date_y.isnull())].dropna(1)
Out[397]: 
     date_x  result  user_id  visit_no
0  20180307       0        1         1
3  20180308       0        3         1
4  20180308       0        3         2

答案 1 :(得分:1)

您可以加入数据框,然后以这种方式过滤符合条件的行:

df_join = full_sessions.join(conversion,lsuffix='',
                            rsuffix='_right',how='left',on='user_id')
print(df_join)

      date  result  user_id  visit_no  user_id_right date_right
0  20180307       0        1         1            1.0   20180308
1  20180308       1        1         2            1.0   20180308
2  20180307       1        2         1            2.0   20180307
3  20180308       0        3         1            NaN        NaN
4  20180308       0        3         2            NaN        NaN

然后只需将NaN保留在正确的日期或date_right小于date

>>> df_join[df_join.apply(lambda x: x.date < x.date_right 
                          if pd.isna(x.date_right) is False 
                          else True,axis=1)][['date','visit_no','user_id']]

        date  visit_no  user_id
0  20180307         1        1
3  20180308         1        3
4  20180308         2        3

答案 2 :(得分:1)

这是一种映射系列而不是连接/合并替代方法的方法。

fs['date'] = pd.to_numeric(fs['date'])

s = fs[fs['result'] == 1].set_index('user_id')['date']

result = fs.loc[fs['date'] < fs['user_id'].map(s).fillna(fs['date'].max()+1)]

<强>结果

       date  result  user_id  visit_no
0  20180307       0        1         1
3  20180308       0        3         1
4  20180308       0        3         2

<强>解释

  • 创建从user_id到转换日期的映射,并将其存储在一系列s中。
  • 然后,只需在通过user_id映射的转化日期之前过滤日期。
  • 如果没有转换日期,那么我们将fillna包含最大日期的数据。
  • 考虑使用datetime个对象。为简单起见,我已将其转换为数字。

答案 3 :(得分:1)

使用groupby&amp;适用&amp;使用重置索引进行一些最终清理,您可以在1 very long语句中表达它:

full_sessions.groupby('user_id', as_index=False).apply(
    lambda x: x[:(x.result==1).values.argmax()] if any(x.result==1) else x
).reset_index(level=0, drop=True)

输出:

       date  result  user_id  visit_no
0  20180307       0        1         1
3  20180308       0        3         1
4  20180308       0        3         2