Python Pandas groupby: фильтровать и применять в соответствии с условием для значений

#python #pandas #dataframe

#python #pandas #фрейм данных

Вопрос:

У меня есть этот фрейм данных pandas

 interval_mins = {
    '10' : 0.11,
    '15' : 0.4,
    '20' : 0.19
}
pd.DataFrame({
    'id' : [10, 15, 20, 10, 20, 15],
    'interval' : [0.1, 0.39, 0.2, 0.12, 0.25, 0.42]
})
 

В pandas DataFrame я хочу выбрать элементы со interval значениями, меньшими, чем interval_mins для каждого id , а затем добавить к следующему interval тому же значению id .

Есть ли способ без использования for ?

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

 pd.DataFrame({
    'id' : [10, 15, 20, 10, 20, 15],
    'interval' : [0.1, 0.39, 0.2, 0.22, 0.25, 0.81]
})
 

введите описание изображения здесь

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

1. неясно (элементы меньше интервала минут?) относительно того, что требуется, пожалуйста, вставьте ожидаемый результат

2. Я не думаю, что ваш пример (на изображении) соответствует вашему правилу, для id = 20 вы также должны добавить, поскольку 0.22> 0.2?

Ответ №1:

Давайте сделаем:

 m = df['interval'] < df['id'].astype(str).map(interval_mins)
df.loc[m.groupby(df['id']).shift(fill_value=False), 'interval']  = df.groupby('id')['interval'].shift()
 

Подробные сведения:

Создайте логическую маску, представляющую условие, в котором interval значения меньше, чем interval_mins для каждого id :

 print(m)

0     True
1     True
2    False
3    False
4    False
5    False
dtype: bool
 

groupby логическая маска m включается id и shift выключается:

 print(m.groupby(df['id']).shift(fill_value=False))

0    False
1    False
2    False
3     True
4    False
5     True
dtype: bool
 

groupby фрейм данных и столбец id shift interval :

 print(df.groupby('id')['interval'].shift())

0     NaN
1     NaN
2     NaN
3    0.10
4    0.20
5    0.39
Name: interval, dtype: float64
 

Используйте логическую индексацию с loc помощью, чтобы добавить значения, соответствующие сдвинутой маске:

 print(df)

   id  interval
0  10      0.10
1  15      0.39
2  20      0.20
3  10      0.22
4  20      0.25
5  15      0.81
 

Ответ №2:

В соответствии с вашим правилом, но не с вашим выводом (см. Мой комментарий), это должно сработать. Я оставляю промежуточные вычисления на месте, чтобы было легче понять, что происходит. Обратите внимание, что я заменил ключи на interval_mis int s из str s. Желаемый результат в столбце interval_2

 df['add'] = df['id'].map(interval_mins)
df['add_cond'] = df['add']*(df['add'] > df['interval'])
df = (df.groupby('id')
        .apply(lambda d: d.assign(add_cond_shift=d['add_cond'].shift()))
        .fillna(0)
        .reset_index(drop = True)
    )
df['interval_2'] = df['interval']   df['add_cond_shift']
df
 

выдает

     id  interval    add add_cond    add_cond_shift  interval_2
0   10  0.10        0.11    0.11    0.00    0.10
1   10  0.12        0.11    0.00    0.11    0.23
2   15  0.39        0.40    0.40    0.00    0.39
3   15  0.42       0.40     0.00    0.40    0.82
4   20  0.20       0.22     0.22    0.00    0.20
5   20  0.25       0.22     0.00    0.22    0.47