#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