1

我有带有 ID、时间戳和状态的客户记录。

ID, TS, STATUS
1 10 GOOD
1 20 GOOD
1 25 BAD
1 30 BAD
1 50 BAD
1 600 GOOD
2 40 GOOD
.. ... 

我正在尝试计算每个客户在连续 BAD 状态中花费的时间(让我们想象上面的顺序是正确的)。因此,对于客户 id=1,30-25,50-30,600-50 总共花费了 575 秒处于 BAD 状态。

在 Pandas 中这样做的方法是什么?如果我在 TS 上计算 .diff() ,那会给我带来差异,但我如何才能将 1) 与客户 2) 某些状态“阻止”该客户?

样本数据:

df = pandas.DataFrame({'ID':[1,1,1,1,1,1,2],
                       'TS':[10,20,25,30,50,600,40],
                       'Status':['G','G','B','B','B','G','G']
                       },
                      columns=['ID','TS','Status'])

谢谢,

4

2 回答 2

2

这是一个单独聚合每个连续的不良状态块的解决方案(您问题的第 2 部分?)。

In [5]: df = pandas.DataFrame({'ID':[1,1,1,1,1,1,1,1,2,2,2],
                               'TS':[10,20,25,30,50,600,650,670,40,50,60],
                               'Status':['G','G','B','B','B','G','B','B','G','B','B']
                               },
                               columns=['ID','TS','Status'])

In [6]: grp = df.groupby('ID')

In [7]: def status_change(df):
   ...:         return (df.Status.shift(1) != df.Status).astype(int)
   ...: 

In [8]: df['BlockId'] = grp.apply(lambda df: status_change(df).cumsum())

In [9]: df['Duration'] = grp.TS.diff().shift(-1)

In [10]: df
Out[10]: 
    ID   TS Status  BlockId  Duration
0    1   10      G        1        10
1    1   20      G        1         5
2    1   25      B        2         5
3    1   30      B        2        20
4    1   50      B        2       550
5    1  600      G        3        50
6    1  650      B        4        20
7    1  670      B        4       NaN
8    2   40      G        1        10
9    2   50      B        2        10
10   2   60      B        2       NaN

In [11]: df[df.Status == 'B'].groupby(['ID', 'BlockId']).Duration.sum()
Out[11]: 
ID  BlockId
1   2          575
    4           20
2   2           10
Name: Duration
于 2013-01-08T02:38:44.820 回答
2
In [1]: df = DataFrame({'ID':[1,1,1,1,1,2,2],'TS':[10,20,25,30,50,10,40],'Stat
us':['G','G','B','B','B','B','B']}, columns=['ID','TS','Status'])

In [2]: f = lambda x: x.diff().sum()

In [3]: df['diff'] = df[df.Status=='B'].groupby('ID')['TS'].transform(f)

In [4]: df
Out[4]:
   ID  TS Status  diff
0   1  10      G   NaN
1   1  20      G   NaN
2   1  25      B    25
3   1  30      B    25
4   1  50      B    25
5   2  10      B    30
6   2  40      B    30

说明:dataframe仅对具有所需状态的那些记录进行子集。 GroupbyID 并将 lambda 函数diff().sum()应用于每个组。使用transform而不是apply因为transform返回一个索引系列,您可以使用它来分配给新列 'diff'。

编辑:对扩大问题范围的新回应。

In [1]: df
Out[1]:
   ID   TS Status
0   1   10      G
1   1   20      G
2   1   25      B
3   1   30      B
4   1   50      B
5   1  600      G
6   2   40      G

In [2]: df['shift'] = -df['TS'].diff(-1)

In [3]: df['diff'] = df[df.Status=='B'].groupby('ID')['shift'].transform('sum')
In [4]: df
Out[4]:
   ID   TS Status  shift  diff
0   1   10      G     10   NaN
1   1   20      G      5   NaN
2   1   25      B      5   575
3   1   30      B     20   575
4   1   50      B    550   575
5   1  600      G   -560   NaN
6   2   40      G    NaN   NaN
于 2013-01-07T16:47:06.680 回答