Применить изменения к столбцу на основе условия в pandas groupby - PullRequest
2 голосов
/ 06 марта 2020

Извините, если я упустил из виду подобную проблему, которая была решена в другом месте. Это посты, которые я изучал перед тем, как задавать этот вопрос:

Pandas Группировка данных в режиме групповой работы на основе условия

pandas групповой заменой на основе условия

Python pandas сгруппировать данные в соответствии с условием

проблема:

Для данного кадра данных

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'a': [1,2,2,3,3,4,5,5,6,6],
    'b': np.random.rand(10),
    'c': 10*[0],
})

со столбцом a, в котором хранятся тождества, и столбцом b со случайными значениями, я хочу пометить значения замены в столбце c.

Если есть только одна запись для a изменения не применяются.

Если есть две записи для a, я хочу пометить запись в c, для которой b минимально:

    a   b           c
0   1   0.472015    0  # <-- only one entry for a => nothing changes
1   2   0.553018    2  # <-- b is minimal => c gets value 2
2   2   0.770302    0
3   3   0.992023    0
4   3   0.119448    2  # <-- b is minimal => c gets value 2

подход:

Сочетание groupby, agg и .loc

g = df.groupby('a').agg({'b': [np.argmin, np.argmax]})
df.loc[g[g[('b', 'argmin')] != g[('b', 'argmax')]][('b', 'argmin')], 'c' ] = 2

Это работает, но кажется довольно окольным.

вопрос

есть ли менее неуклюжий способ go об этом?

спасибо

помощь очень ценится!

edit:

Группы имеют одного или двух членов. Если оба члена имеют одинаковое значение b, ничего не должно происходить.

df = pd.DataFrame({
    'a': [1,2,2,3,3,4,5,5,6,6],
    'b': [1,1,2,1,2,1,1,1,2,1],
    'c': 10*[0],
})

df.loc[df['b'].eq(df.groupby('a')['b'].transform('min')),'c']=2

out:

    a   b   c
0   1   1   2
1   2   1   2
2   2   2   0
3   3   1   2
4   3   2   0
5   4   1   2
6   5   1   2
7   5   1   2
8   6   2   0
9   6   1   2

df.loc[df.index==df.groupby('a')['b'].transform('idxmin'),'c']=2

    a   b   c
0   1   1   2  # <-- a has only one member, so this shouldn't be changed
1   2   1   2
2   2   2   0
3   3   1   2
4   3   2   0
5   4   1   2
6   5   1   2
7   5   1   0
8   6   2   0
9   6   1   2

1 Ответ

1 голос
/ 06 марта 2020

Вы можете использовать groupby+transform с df.loc[]:

df.loc[df['b'].eq(df.groupby('a')['b'].transform('min')),'c']=2

Пример:

df.loc[df['b'].eq(df.groupby('a')['b'].transform('min')),'c']=2
print(df)
   a         b  c
0  1  0.126956  2
1  2  0.249078  2
2  2  0.929619  0
3  3  0.013735  2
4  3  0.192781  0
5  4  0.268828  2
6  5  0.649238  2
7  5  0.767545  0
8  6  0.678478  2
9  6  0.815916  0

РЕДАКТИРОВАТЬ:

g = df.groupby('a')
cond = pd.Series(df.index==g['b'].transform('idxmin')) & g['a'].transform('count').gt(1)
df.loc[cond,'c'] = 2

print(df)

   a  b  c
0  1  1  0
1  2  1  2
2  2  2  0
3  3  1  2
4  3  2  0
5  4  1  0
6  5  1  2
7  5  1  0
8  6  2  0
9  6  1  2
...