【问题标题】:How to Pivot the data Based on another column value如何基于另一列值透视数据
【发布时间】:2019-09-11 03:24:58
【问题描述】:

我正在尝试透视/转置我的列值并尝试获取相应的日期时间。

我的桌子:

User  Status     LogTime
----------------------------------------
Tom   Active     2019-09-06 17:36:08.233
Tom   Active     2019-09-06 18:37:08.244
Tom   Active     2019-09-06 20:46:08.133
Tom   InActive   2019-09-06 23:46:08.133
Tom   Active     2019-09-07 12:37:08.244
Tom   Active     2019-09-08 10:46:08.133
Tom   InActive   2019-09-08 11:46:08.133

尝试获取如下数据。

User  Active                     InActive
------------------------------------------------------
Tom  2019-09-06 20:46:08.133   2019-09-06 23:46:08.133
Tom  2019-09-08 10:46:08.133   2019-09-08 11:46:08.133  

我正在尝试在最后一次活动之后用最后一次活动的日志时间和非活动的日志时间转置状态列

【问题讨论】:

    标签: pandas hive pyspark pivot impala


    【解决方案1】:

    此查询在 Hive 中与您的数据集一起使用。 当用户的日志中没有 InActive 或 Active 状态时,我尝试考虑可能的边界条件,当然应该在真实数据集上验证和调整逻辑。

    演示:

    with data as (
    select stack(7,
    'Tom','Active',   '2019-09-06 17:36:08.233',
    'Tom','Active',   '2019-09-06 18:37:08.244',
    'Tom','Active',   '2019-09-06 20:46:08.133',
    'Tom','InActive', '2019-09-06 23:46:08.133',
    'Tom','Active',   '2019-09-07 12:37:08.244',
    'Tom','Active',   '2019-09-08 10:46:08.133',
    'Tom','InActive', '2019-09-08 11:46:08.133'
    ) as(User,Status,LogTime)
    ) --use your_table instead of this
    
    
    select User, Active, InActive
    from
    (
    select User,MaxInActive,MaxActive,--Status,LogTime,nextStatus,
           case when (prevStatus='Active' and Status='InActive')  --the last Active LogTime
                     then prevLogTime
                when (Status='Active' and nextStatus is NULL) --boundary condition, Active is the last status, take current
                     OR (LogTime=MaxActive  and MaxInActive is NULL) --No InActive, take current
                     then LogTime             
           end as Active,
    
           case when (prevStatus='Active' and Status='InActive') --InActive LogTime after the last Active
                     OR (LogTime=MaxInActive and MaxActive is NULL) --No Active exists, take current
                     then LogTime
           end as InActive
    
    from       
    (
    select User,Status,LogTime,
           max(case when Status='InActive' then LogTime end) over(partition by User) as MaxInActive ,
           max(case when Status='Active' then LogTime end) over(partition by User) as MaxActive,
           lead(Status) over(partition by User order by LogTime) nextStatus,
           lag(Status) over(partition by User order by LogTime) prevStatus,
           lag(LogTime) over(partition by User order by LogTime) prevLogTime
      from data
    )s
    )s
    where (Active is not NULL and InActive is not NULL)
          or (MaxInActive is NULL and Active is not NULL) --only active records exist
          or (MaxActive is NULL and MaxInActive is not NULL) --only inactive exists
     ;
    

    结果:

    OK
    user    active  inactive
    Tom     2019-09-06 20:46:08.133 2019-09-06 23:46:08.133
    Tom     2019-09-08 10:46:08.133 2019-09-08 11:46:08.133
    Time taken: 100.645 seconds, Fetched: 2 row(s)
    

    【讨论】:

    • 完美运行...非常感谢@leftjoin
    • @Rahul 你很高兴
    • @leftjoin.. 整理“用户日志中没有InActive或Active状态时的边界条件”
    【解决方案2】:

    您可以尝试使用shift() 抓取InActive 的上一行,然后将每2 行分隔为一组并unstack()

    m=df[df.Status.eq('InActive')|df.Status.eq('InActive').shift(-1)].reset_index(drop=True)
    m.assign(k=m.groupby(m.index//2).ngroup()).set_index(['User','Status','k']).unstack(1)
    

                            LogTime                         
    Status                   Active                 InActive
    User k                                                  
    Tom  0  2019-09-06 20:46:08.133  2019-09-06 23:46:08.133
         1  2019-09-08 10:46:08.133  2019-09-08 11:46:08.133
    

    或者使用相同的mpivot_table

    m.assign(k=m.groupby(m.index//2).ngroup()).pivot_table(index=['User','k']
              ,columns='Status',values='LogTime',aggfunc='first').rename_axis(None,axis=1)
    

                          Active                 InActive
    User k                                                  
    Tom  0  2019-09-06 20:46:08.133  2019-09-06 23:46:08.133
         1  2019-09-08 10:46:08.133  2019-09-08 11:46:08.133
    

    【讨论】:

      【解决方案3】:

      在 'LogTime' 的 'User'、'Status'、'date' 部分尝试 groupby 并在 'LogTime' 上调用 'last'。接下来,'unstack',将索引放入列并删除不需要的列和'dropna'

      df1 = (df.groupby(['User','Status', df.LogTime.dt.date]).LogTime.last()
              .unstack(1).reset_index().drop('LogTime',1).dropna())
      
      Out[890]:
      Status User                  Active                InActive
      0       Tom 2019-09-06 20:46:08.133 2019-09-06 23:46:08.133
      2       Tom 2019-09-08 10:46:08.133 2019-09-08 11:46:08.133
      

      【讨论】:

        猜你喜欢
        • 2022-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-25
        • 1970-01-01
        • 2020-06-18
        • 1970-01-01
        • 2021-07-04
        相关资源
        最近更新 更多