后续时间序列数据上的匹配条件的递增计数器标志

时间:2019-05-01 00:40:31

标签: python pandas

我有一个如下所示的数据框

ID      DATE          PROFIT
2342  2017-03-01       457
2342  2017-06-01       658
2342  2017-09-01       3456
2342  2017-12-01       345
2342  2018-03-01       235
2342  2018-06-01       23
808   2016-12-01       200        
808   2017-03-01       9346
808   2017-06-01       54
808   2017-09-01       314
808   2017-12-01       57
....
....

对于每个ID:

我想确定利润是否保持在200到1000之间。 我想以这样的方式进行操作:计数器(新列)指示连续有多少个季度(最新和之前)满足此条件。如果由于某种原因,中间四分之一之一不符合条件,则计数器应重置。

所以输出应类似于:

ID      DATE          PROFIT    COUNTER
2342  2017-03-01       457        1
2342  2017-06-01       658        2
2342  2017-09-01       3456       0
2342  2017-12-01       345        1
2342  2018-03-01       235        2
2342  2018-06-01       23         0
808   2016-12-01       200        1
808   2017-03-01       9346       0
808   2017-06-01       54         0
808   2017-09-01       314        1
808   2017-12-01       57         0
....
....

我正在考虑使用shift功能访问/访问前几行的条件,但是,如果有更好的方法来检查datetime值中的条件,将是一个很好的了解。

5 个答案:

答案 0 :(得分:3)

IIUC通过使用cumsum创建帮助键,然后我们只需要过滤一下,然后分配回去的fillna,而不是200到1000之间的0

s=(~df.PROFIT.between(200,1000)).groupby(df['ID']).cumsum()
df['COUNTER']=df[df.PROFIT.between(200,1000)].groupby([df.ID,s]).cumcount()+1
df.COUNTER.fillna(0,inplace=True)
df
Out[226]: 
      ID        DATE  PROFIT  COUNTER
0   2342  2017-03-01     457      1.0
1   2342  2017-06-01     658      2.0
2   2342  2017-09-01    3456      0.0
3   2342  2017-12-01     345      1.0
4   2342  2018-03-01     235      2.0
5   2342  2018-06-01      23      0.0
6    808  2016-12-01     200      1.0
7    808  2017-03-01    9346      0.0
8    808  2017-06-01      54      0.0
9    808  2017-09-01     314      1.0
10   808  2017-12-01      57      0.0

答案 1 :(得分:2)

设置一个满足条件的值1的条件列,然后进行分组和求和。

df['criteria'] = 0

df.loc[(df['PROFIT'] >= 200) & (df['PROFIT'] <= 1000), 'criteria'] = 1

df['result'] = df.groupby(['ID', df.criteria.eq(0).cumsum()])['criteria'].cumsum()


     ID        DATE  PROFIT  criteria  result
0   2342  2017-03-01     457         1       1
1   2342  2017-06-01     658         1       2
2   2342  2017-09-01    3456         0       0
3   2342  2017-12-01     345         1       1
4   2342  2018-03-01     235         1       2
5   2342  2018-06-01      23         0       0
6    808  2016-12-01     200         1       1
7    808  2017-03-01    9346         0       0
8    808  2017-06-01      54         0       0
9    808  2017-09-01     314         1       1
10   808  2017-12-01      57         0       0

答案 2 :(得分:0)

groupbycumsumcumcount结合使用,然后简单地使用loc来获取第一行并根据需要进行排列:

df['BOOL'] = (~df['PROFIT'].between(200, 1000)).cumsum()
df['COUNTER'] = df.groupby('BOOL', 'ID']).cumcount()
df.loc[df.groupby('ID', as_index=False)['BOOL'].apply(lambda x: x.loc[:x.idxmin()-1]).index.levels[1], 'COUNTER'] += 1

现在:

print(df)

是:

      ID        DATE  PROFIT  COUNTER
0   2342  2017-03-01     457        1
1   2342  2017-06-01     658        2
2   2342  2017-09-01    3456        0
3   2342  2017-12-01     345        1
4   2342  2018-03-01     235        2
5   2342  2018-06-01      23        0
6    808  2016-12-01     200        1
7    808  2017-03-01    9346        0
8    808  2017-06-01      54        0
9    808  2017-09-01     314        1
10   808  2017-12-01      57        0

如您所期望的输出中所示。

答案 3 :(得分:0)

def magic(y):
    return y * (y.groupby((y != y.shift()).cumsum()).cumcount() + 1)

data["condition"] = data['PROFIT'].between(200, 1000)
data["COUNTER"] = data.groupby("ID").condition.apply(magic)


      ID        DATE  PROFIT  condition  COUNTER
0   2342  2017-03-01     457       True        1
1   2342  2017-06-01     658       True        2
2   2342  2017-09-01    3456      False        0
3   2342  2017-12-01     345       True        1
4   2342  2018-03-01     235       True        2
5   2342  2018-06-01      23      False        0
6    808  2016-12-01     200       True        1
7    808  2017-03-01    9346      False        0
8    808  2017-06-01      54      False        0
9    808  2017-09-01     314       True        1
10   808  2017-12-01      57      False        0

答案 4 :(得分:-1)

会不会像以下工作那么简单?

int strlen(char* str)
{
    int i = 0;

    while (*str != '\0')
    {
        i++;
        str++;

    }

    return i;
}

int main()
{
    char line[1];
    char* v = line;
    char* s = new char[1];
    cout << "for s " << strlen(s) << endl;
    cout << "for v " << strlen(v) << endl;

}