如何找到一组最后一行与下一组第一行之间的时差

时间:2019-06-24 15:28:04

标签: python pandas dataframe

我有一个像这样的表:

| date                | activity |
|---------------------|----------|
| 2017-03-30 01:00:00 | 1        |
| 2017-03-30 01:00:30 | 1        |
| 2017-03-30 01:01:00 | 1        |
| 2017-03-30 01:01:30 | 2        |
| 2017-03-30 01:02:00 | 2        |
| 2017-03-30 01:02:30 | 2        |
| 2017-03-30 01:03:00 | 1        |

我的最终目标是从该时间序列中得出活动1的一些统计信息。为此,我需要从构造一个列表开始,该列表将汇总有关活动的信息。

基本上,我想为每个块(标记为1的连续行的块)获取一个元组,其中该元组将包含该块的开始日期以及其中的行总数。 对于前面的示例,相应的列表为:

[(2017-03-30 01:00:00,3),(2017-03-30 01:03:00,1)]

关于如何实现此目标的任何想法?我也愿意接受最终会产生相同信息的其他建议。

3 个答案:

答案 0 :(得分:2)

通过cumsum +比较shift完成具有相同连续值的查找组。使用where忽略不需要的组。

#df = df.sort_values('date')

s = df.activity.ne(df.activity.shift(1)).cumsum()
res = df.groupby(s.where(df.activity.eq(1)).rename(None)).date.agg(['first', 'size'])

输出:

                   first  size
1.0  2017-03-30 01:00:00     3
3.0  2017-03-30 01:03:00     1

如果您真的想要元组列表,则:

[tuple(x) for x in res.to_numpy()]
#[('2017-03-30 01:00:00', 3), ('2017-03-30 01:03:00', 1)]

答案 1 :(得分:1)

更易消化,但熊猫风格可能更少:

  • 首先,您创建一些标识符以区分等于1的不同活动“运行”
  • 然后您删除所有活动不等于1的所有记录
  • 现在最困难的逻辑已经完成,我们可以使用简单的分组方式

如果您随后想要获取所要查找的元组列表,则可以在末尾使用.iterrows()

df['id'] = (df['activity'].shift(1) != df['activity']).cumsum()

inds = df['activity'] == 1
df = df.loc[inds, :]

result = df.groupby('id')['date'].agg(['min', 'size])
result
# id size   min 
#  1    3   2017-03-30 01:00:00
#  3    1   2017-03-30 01:03:00    

对于元组列表,您可以执行以下操作:

[(row[1][1], row[1][0]) for row in result.iterrows()]

答案 2 :(得分:0)

您可以先为每个组分配一个号码,然后使用groupby。第一部分不是那个pythonic,而是有效的:

import pandas as pd
 df = {'date': {0: '2017-03-30 01:00:00',
  1: '2017-03-30 01:00:30',
  2: '2017-03-30 01:01:00',
  3: '2017-03-30 01:01:30',
  4: '2017-03-30 01:02:00',
  5: '2017-03-30 01:02:30',
  6: '2017-03-30 01:03:00'},
 'activity': {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 2, 6: 1}}

df = pd.DataFrame(df)

# add group
group = 0
groups = []
initial_value = df.iloc[0]["activity"]
for _, row in df.iterrows():
    if row["activity"]!= initial_value:
        initial_value = row["activity"]
        group +=1
    groups.append(group)

df["group"] = groups

# count and min date
out = df.groupby(["group", "activity"])\
        .agg({"date":{"min", "count"}})

out.columns = ["_".join(o) for o in out.columns]
out = out.reset_index()