Мне нужно выяснить, сколько раз велосипед был на превышении скорости, и в каждом случае как долго (для простоты сколько км)

df = pd.DataFrame({'bike':['b1']*15, 'km':list(range(1,16)), 'speed':[20,30,38,33,28,39,26,33,35,46,53,27,37,42,20]})
>>> df
   bike  km  speed
0    b1   1     20
1    b1   2     30
2    b1   3     38
3    b1   4     33
4    b1   5     28
5    b1   6     39
6    b1   7     26
7    b1   8     33
8    b1   9     35
9    b1  10     46
10   b1  11     53
11   b1  12     27
12   b1  13     37
13   b1  14     42
14   b1  15     20
#Expected result is
bike  last_OS_loc  for_how_long_on_OS
b1      4                2km
b1      11               5km
b1      15               1km

Теперь логика-

  1. должен помечать скорость> = 30 как Overspeed_Flag

  2. Если скорость остается на уровне более 30 в течение 1 или 1 + км, то это продолжение рассматривается как сеанс превышения скорости (например: когда b1 находился между 2–4 км, 6–11, 13–14 км, MARK, это не было сеансом превышения скорости, когда b1 находился на 6 км, так как это было только для этого ряда, продолжения на> 30 не найдено).

  3. затем измерьте для сеанса, как долго / сколько км он остается на пределе превышения скорости. Обратитесь к вкладке ожидаемых результатов.

  4. также выяснение для сессии превышения скорости, какова была последняя отметка км.

Пожалуйста, подскажите, как я могу этого добиться. И дайте мне знать, если в вопросе что-то неясно.

П: С: Я тоже пытаюсь, но для меня это немного сложно (я не понимаю, как отмечать, является ли это продолжением OS_flag или отдельным экземпляром ОС). Вернусь, если это удастся. Спасибо в ADV.

1
Satya 27 Сен 2018 в 09:23

2 ответа

Лучший ответ

Ты можешь использовать:

#boolean mask
mask = df['speed'] >= 30
#consecutive groups
df['g'] = mask.ne(mask.shift()).cumsum()
#get size of each group
df['count'] = mask.groupby(df['g']).transform('size')
#filter by mask and remove unique rows
df = df[mask & (df['count'] > 1)]
print (df)
   bike  km  speed  g  count
1    b1   2     30  2      3
2    b1   3     38  2      3
3    b1   4     33  2      3
7    b1   8     33  6      4
8    b1   9     35  6      4
9    b1  10     46  6      4
10   b1  11     53  6      4
12   b1  13     37  8      2
13   b1  14     42  8      2

#aggregate first and last values
df1 = df.groupby(['bike','g'])['km'].agg([('last_OS_loc', 'last'), 
                                          ('for_how_long_on_OS','first')])
#substract last with first
df1['for_how_long_on_OS'] = df1['last_OS_loc'] - df1['for_how_long_on_OS']
#data cleaning
df1 = df1.reset_index(level=1, drop=True).reset_index()
print (df1)
  bike  last_OS_loc  for_how_long_on_OS
0   b1            4                   2
1   b1           11                   3
2   b1           14                   1

РЕДАКТИРОВАТЬ:

print (pd.concat([mask,
                  mask.shift(), 
                  mask.ne(mask.shift()), 
                  mask.ne(mask.shift()).cumsum()], axis=1, 
                  keys=('mask', 'shifted', 'not equal (!=)', 'cumsum')))

     mask shifted  not equal (!=)  cumsum
0   False     NaN            True       1
1    True   False            True       2
2    True    True           False       2
3    True    True           False       2
4   False    True            True       3
5    True   False            True       4
6   False    True            True       5
7    True   False            True       6
8    True    True           False       6
9    True    True           False       6
10   True    True           False       6
11  False    True            True       7
12   True   False            True       8
13   True    True           False       8
14  False    True            True       9
2
jezrael 27 Сен 2018 в 07:20

Вот еще один подход с использованием пары вспомогательных функций Series и lambda:

os_session = (df['speed'].ge(30) & (df['speed'].shift(-1).ge(30) | df['speed'].shift().ge(30))).astype(int)
groups =  (os_session.diff(1) != 0).astype('int').cumsum()

f_how_long = lambda x: x.max() - x.min()

grouped_df = (df.groupby([os_session, groups, 'bike'])['km']
           .agg([('last_OS_loc', 'max'),
                 ('for_how_long_on_OS',f_how_long)])
           .xs(1, level=0)
           .reset_index(level=0, drop=True))

print(grouped_df)

      last_OS_loc  for_how_long_on_OS
bike                                 
b1              4                   2
b1             11                   3
b1             14                   1
1
Chris A 27 Сен 2018 в 07:14