仅根据分组记录计算pandas数据帧中的新列

时间:2017-06-14 15:38:20

标签: python pandas

我有一个包含各种事件(id)和以下结构的数据框,df按 id 分组,并按时间戳排序:

id | timestamp | A | B
1  | 02-05-2016|bla|bla
1  | 04-05-2016|bla|bla
1  | 05-05-2016|bla|bla
2  | 11-02-2015|bla|bla
2  | 14-02-2015|bla|bla
2  | 18-02-2015|bla|bla
2  | 31-03-2015|bla|bla
3  | 02-08-2016|bla|bla
3  | 07-08-2016|bla|bla
3  | 27-09-2016|bla|bla

每个 timestamp-id 组合表示事件过程中具有特定 id 的不同阶段。特定 id 的每个新记录都表示该事件ID的新阶段的开始。

我想添加一个新列持续时间,用于计算每个事件的每个阶段的持续时间(请参阅下面所需的df)。这很容易,因为我可以简单地计算同一事件id的下一阶段的时间戳与当前阶段的时间戳之间的差异,如下所示:

df['Start'] = pd.to_datetime(df['timestamp'])
df['End'] = pd.to_datetime(df['timestamp'].shift(-1))
df['Duration'] = df['End'] - df['Start']

我的问题出现在每个事件id的最后一个阶段,因为我想简单地显示NaN或短划线,因为舞台尚未完成且结束时间未知。我的解决方案只是采用下一行的时间戳并不总是正确的,因为它可能属于一个完整的不同事件。

期望的输出:

id | timestamp | A | B | Duration
1  | 02-05-2016|bla|bla| 2 days
1  | 04-05-2016|bla|bla| 1 days
1  | 05-05-2016|bla|bla| ------
2  | 11-02-2015|bla|bla| 3 days
2  | 14-02-2015|bla|bla| 4 days
2  | 18-02-2015|bla|bla| 41 days
2  | 31-03-2015|bla|bla| -------
3  | 02-08-2016|bla|bla| 5 days
3  | 07-08-2016|bla|bla| 50 days
3  | 27-09-2016|bla|bla| -------

2 个答案:

答案 0 :(得分:2)

我认为这可以满足您的需求:

df['timestamp'] = pd.to_datetime(df['timestamp'])
df['Duration']  = df.groupby('id')['timestamp'].diff().shift(-1)

如果我理解正确:groupby('id')告诉pandas将.diff()。shift(-1)应用于每个组,就好像它是一个独立于其他行的微型DataFrame。我在这个假数据上测试了它:

import pandas as pd
import numpy as np

# Generate some fake data
df = pd.DataFrame()
df['id'] = [1]*5 + [2]*3 + [3]*4
df['timestamp'] = pd.to_datetime('2017-01-1')
duration = sorted(np.random.randint(30,size=len(df)))
df['timestamp'] += pd.to_timedelta(duration)
df['A'] = 'spam'
df['B'] = 'eggs'

但仔细检查以确保我没有犯错!

答案 1 :(得分:1)

以下是使用 Glide.with(getContext()) .using(new FirebaseImageLoader()) .load(storageReference.child(item.getImageUrl())) .placeholder(R.drawable.category_image_not_found) .signature(???) .into(image);

的一种方法
apply

<强>输出:

def timediff(row):
    row['timestamp'] = pd.to_datetime(row['timestamp'], format='%d-%m-%Y')
    return pd.DataFrame(row['timestamp'].diff().shift(-1))
res = df.assign(duration=df.groupby('id').apply(timediff))