Это расширение принятого ответа.
Мой фрейм данных:
import pandas as pd
df = pd.DataFrame(
{
'a': [-3, -1, -2, -5, 10, -3, -13, -3, -2, 1, 2, -100],
'b': [1, 2, 3, 4, 5, 10, 80, 90, 100, 99, 1, 12]
}
)
Ожидаемый результат:
a b
5 -3 10
6 -13 80
7 -3 90
8 -2 100
Логика:
а) Выбор самой длинной серии негативов в a
.
б) Если, например, есть две полосы одинакового размера, мне нужна та, у которой сумма b
больше. В df
есть две полосы размером 4, но мне нужна вторая, потому что сумма b
больше.
Моя попытка:
import numpy as np
s = np.sign(df['a'])
df['g'] = s.ne(s.shift()).cumsum()
df['size'] = df.groupby('g')['g'].transform('size')
df['b_sum'] = df.groupby('g')['b'].transform('sum')
Код
cond = df['a'] >= 0
grp = cond.cumsum()
idx = (df[~cond].groupby(grp).agg({'a': 'count', 'b': 'sum'})
.sort_values('b', ascending=False)['a'].idxmax())
out = df[~cond & grp.eq(idx)]
вне:
a b
5 -3 10
6 -13 80
7 -3 90
8 -2 100
Вы можете сохранить ту же логику, просто добавьте один дополнительный шаг фильтрации (например, с помощью запроса ), чтобы получить все максимальные размеры, прежде чем получить idxmax суммы «b»:
# negative numbers
m = df['a'].lt(0)
# form groups
g = m.ne(m.shift()).cumsum()
out = df[g.eq(df.groupby(g)['b'].agg(['size', 'sum'])
.query('size == size.max()')['sum'].idxmax())]
Выход:
a b
5 -3 10
6 -13 80
7 -3 90
8 -2 100
Средний:
df.groupby(g)['b'].agg(['size', 'sum'])
size sum
a
1 4 10
2 1 5
3 4 280
4 2 100
5 1 12
Или, используя ваш подход (обратите внимание, что это не гарантирует уникальную группу, если две или более имеют максимальную длину и одинаковую сумму b):
s = np.sign(df['a'])
g = df.groupby(s.ne(s.shift()).cumsum())
s1 = g['a'].transform('size')
s2 = g['b'].transform('sum')
out = df[s1.eq(s1.max()) & s2.eq(s2.max())]
import numpy as np
import pandas as pd
# Sample DataFrame
df = pd.DataFrame(
{
'a': [-3, -1, -2, -5, 10, -3, -13, -3, -2, 1, 2, -100],
'b': [1, 2, 3, 4, 5, 10, 80, 90, 100, 99, 1, 12]
}
)
# Determine the groups based on sign changes
m = df['a'] < 0
df['gr'] = gr = m.ne(m.shift()).cumsum()
'''
DataFrame with groups:
a b gr
0 -3 1 1
1 -1 2 1
2 -2 3 1
3 -5 4 1
4 10 5 2
5 -3 10 3
6 -13 80 3
7 -3 90 3
8 -2 100 3
9 1 99 4
10 2 1 4
11 -100 12 5
'''
# Calculate the size of each group where 'a' is negative
gr_size = df.loc[m, 'gr'].value_counts()
'''
Group sizes where 'a' is negative:
gr
1 4
3 4
5 1
'''
# Filter DataFrame for the group with the maximum size
res = df[df['gr'] == gr_size.idxmax()]
'''
Filtered DataFrame for largest group size:
a b gr
0 -3 1 1
1 -1 2 1
2 -2 3 1
3 -5 4 1
'''
# Aggregate statistics for each group
gr_stats = df[m].groupby('gr').agg(size=('gr', 'size'), b_sum=('b', 'sum'))
'''
Group statistics:
size b_sum
gr
1 4 10
3 4 280
5 1 12
'''
# Find the group with the maximum b_sum
max_b_sum_group = gr_stats['b_sum'].idxmax()
'''
Group with maximum b_sum: 3
'''
# Display the rows of the group with maximum b_sum
result = df[df['gr'] == max_b_sum_group]
'''
Rows of the group with maximum b_sum:
a b gr
5 -3 10 3
6 -13 80 3
7 -3 90 3
8 -2 100 3
'''