Накопительный счет Pandas

У меня есть такой кадр данных:

0 04:10 obj1
1 04:10 obj1
2 04:11 obj1
3 04:12 obj2
4 04:12 obj2
5 04:12 obj1
6 04:13 obj2

Хотел бы получить кумулятивный счет для всех объектов вроде этого:

idx time object obj1_count obj2_count 
0 04:10 obj1 1 0
1 04:10 obj1 2 0
2 04:11 obj1 3 0
3 04:12 obj2 3 1
4 04:12 obj2 3 2
5 04:12 obj1 4 2
6 04:13 obj2 4 3

Пробовал играть с cumsum, но не уверен, что это правильный путь. Какие-либо предложения?

4 ответа

Вы можете просто сравнить столбец со значением интереса и вызвать cumsum:

In [12]:
df['obj1_count'] = (df['object'] == 'obj1').cumsum()
df['obj2_count'] = (df['object'] == 'obj2').cumsum()
df

Out[12]:
 time object obj1_count obj2_count
idx 
0 04:10 obj1 1 0
1 04:10 obj1 2 0
2 04:11 obj1 3 0
3 04:12 obj2 3 1
4 04:12 obj2 3 2
5 04:12 obj1 4 2
6 04:13 obj2 4 3

Здесь сравнение приведет к созданию булевой последовательности:

In [13]:
df['object'] == 'obj1'

Out[13]:
idx
0 True
1 True
2 True
3 False
4 False
5 True
6 False
Name: object, dtype: bool

когда вы вызываете cumsum на выше, значения True преобразуются в 1 и False в 0 и суммируются кумулятивно


Вы можете обобщить этот процесс, получив cumsum pd.get_dummies. Это должно работать для произвольного количества объектов, которые вы хотите подсчитать, без необходимости указывать их отдельно:

# Get the cumulative counts.
counts = pd.get_dummies(df['object']).cumsum()

# Rename the count columns as appropriate.
counts = counts.rename(columns=lambda col: col+'_count')

# Join the counts to the original df.
df = df.join(counts)

Результат:

time object obj1_count obj2_count
0 04:10 obj1 1 0
1 04:10 obj1 2 0
2 04:11 obj1 3 0
3 04:12 obj2 3 1
4 04:12 obj2 3 2
5 04:12 obj1 4 2
6 04:13 obj2 4 3

Вы можете опустить шаг rename если допустимо использовать count в качестве префикса вместо суффикса, то есть 'count_obj1' вместо 'obj1_count'. Просто используйте prefix параметр pd.get_dummies:

counts = pd.get_dummies(df['object'], prefix='count').cumsum()


Здесь можно использовать numpy

u, iv = np.unique(
 df.object.values,
 return_inverse=True
)

objcount = pd.DataFrame(
 (iv[:, None] == np.arange(len(u))).cumsum(0),
 df.index, u
)
pd.concat([df, objcount], axis=1)


Для такой операции существует специальная функция: cumcount

>>> df = pd.DataFrame([['a'], ['a'], ['a'], ['b'], ['b'], ['a']], columns=['A'])
>>> df
 A
0 a
1 a
2 a
3 b
4 b
5 a
>>> df.groupby('A').cumcount()
0 0
1 1
2 2
3 0
4 1
5 3
dtype: int64
>>> df.groupby('A').cumcount(ascending=False)
0 3
1 2
2 1
3 1
4 0
5 0
 dtype: int64

licensed under cc by-sa 3.0 with attribution.