Как отслеживать, сколько раз возникает уникальное условие

#python #pandas

#python #панды

Вопрос:

У меня есть df, который выглядит следующим образом:

 time  val
0      1
1      1
2      2
3      3
4      1
5      2
6      3
7      3
8      3
9      3
10     1
11     1

 

Как мне создать новые столбцы, которые содержат количество раз, когда условие возникает и не меняется? В этом случае я хочу создать столбец для каждого уникального значения в val , который содержит совокупную сумму в заданной строке вхождений, но не увеличивает значение, если условие не изменяется.

Ожидаемый результат ниже:

 time  val  sum_1   sum_2    sum_3
0      1    1        0       0 
1      1    1        0       0
2      2    1        1       0
3      3    1        1       1
4      1    2        1       1
5      2    2        2       1
6      3    2        2       2 
7      3    2        2       2
8      3    2        2       2
9      3    2        2       2
10     1    3        2       2
11     1    3        2       2

 

Редактировать

Чтобы быть более конкретным с условием:

Я хочу подсчитать, сколько раз появляется уникальное значение val . Например, используя приведенный ниже код, я мог бы получить этот результат:

 df['sum_1'] = (df['val'] == 1).cumsum()
df['sum_2'] = (df['val'] == 2).cumsum()
df['sum_3'] = (df['val'] == 3).cumsum()

   time  val  sum_1  sum_2  sum_3
0     0    1      1      0      0
1     1    1      2      0      0
2     2    2      2      1      0
3     3    3      2      1      1
4     4    1      3      1      1
5     5    2      3      2      1

 

Однако этот код учитывает КАЖДОЕ возникновение условия. Например, val показывает 1 , что происходит всего 3 раза. Однако я хочу рассматривать последовательные вхождения 1 как единую группу, считая только количество встречающихся последовательных группировок. В приведенном выше примере 1 это происходит всего 3 раза, но только 2 раза в виде последовательной группировки.

Комментарии:

1. @LoukasPap да, это так

2. Не могли бы вы уточнить условие?

3. Внесено редактирование для конкретики. Надеюсь, этого достаточно.

4. Вы пробовали использовать цикл?

Ответ №1:

Вы можете связать маску с помощью amp; побитовой AND для проверки первых последовательных значений путем сравнения по сдвинутым значениям с помощью Series.ne с Series.shift и запустить код для проверки всех уникальных значений столбца val :

 uniq = df['val'].unique()
m = df['val'].ne(df['val'].shift())

for c in uniq:
    df[f'sum_{c}'] = (df['val'].eq(c) amp; m).cumsum()
print (df)
    time  val  sum_1  sum_2  sum_3
0      0    1      1      0      0
1      1    1      1      0      0
2      2    2      1      1      0
3      3    3      1      1      1
4      4    1      2      1      1
5      5    2      2      2      1
6      6    3      2      2      2
7      7    3      2      2      2
8      8    3      2      2      2
9      9    3      2      2      2
10    10    1      3      2      2
11    11    1      3      2      2
 

Для повышения производительности (я надеюсь) вот numpy альтернатива:

 a = df['val'].to_numpy()
uniq = np.unique(a)
m = np.concatenate(([False], a[:-1])) != a

arr = np.cumsum((a[:, None] == uniq) amp; m[:, None], axis=0)

df = df.join(pd.DataFrame(arr, index=df.index, columns=uniq).add_prefix('sum_'))
print (df)
    time  val  sum_1  sum_2  sum_3
0      0    1      1      0      0
1      1    1      1      0      0
2      2    2      1      1      0
3      3    3      1      1      1
4      4    1      2      1      1
5      5    2      2      2      1
6      6    3      2      2      2
7      7    3      2      2      2
8      8    3      2      2      2
9      9    3      2      2      2
10    10    1      3      2      2
11    11    1      3      2      2