Условное присвоение в pandas сгруппированным - PullRequest
1 голос
/ 04 мая 2020

Предположим, у меня есть df ниже:

df = pd.DataFrame({
    'ID': ['a', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'd'],
    'V': np.array(range(0,10))
})

Я хочу groupby переменную ID и присваивать значения новому столбцу X в зависимости от (1) размера каждого группа и является ли каждая строка верхней (T), «средней» (больше похожей между верхней и нижней) (M) или нижней (B) строкой. Если в группе только одна строка, присваивается значение N. В этом случае результат будет выглядеть следующим образом:

    ID  V   X
0   a   0   N
1   b   1   T
2   b   2   B
3   c   3   T
4   c   4   M
5   c   5   B
6   d   6   T
7   d   7   M
8   d   8   M
9   d   9   B

Я могу сделать это пошагово, используя что-то вроде (для случая T):

df.join(df.groupby('ID').filter(lambda x: len(x)>1).groupby('ID').head(1).assign(X='T').X, how='left')

Но это похоже на плохое решение. Я бы предпочел сделать все это за один go. Есть идеи?

Ответы [ 2 ]

4 голосов
/ 04 мая 2020

Это просто из вашей логики c:

groups = df.groupby('ID')
first = groups['V'].head(1).index
last = groups['V'].tail(1).index

# the default middle values
df['X'] = 'M'

# the top and bottom values
df.loc[first, 'X'] = 'T'
df.loc[last, 'X'] = 'B'

# the unique values
ones = groups['V'].transform('size') == 1
df.loc[ones, 'X'] = 'N'

Вывод:

  ID  V  X
0  a  0  N
1  b  1  T
2  b  2  B
3  c  3  T
4  c  4  M
5  c  5  B
6  d  6  T
7  d  7  M
8  d  8  M
9  d  9  B
2 голосов
/ 04 мая 2020

Один из подходов к этому - сравнить идентификатор каждой строки с идентификатором до / после него.

Например:

df["top"] = df.ID != df.shift().ID
df["bottom"] = df.ID != df.shift(-1).ID
df["mid"] = (df.ID == df.shift(-1).ID) & (df.ID == df.shift(1).ID)

Это приводит к:

    ID  V   bottom  top mid
0   a   0   True    True    False
1   b   1   False   True    False
2   b   2   True    False   False
3   c   3   False   True    False
4   c   4   False   False   True
5   c   5   True    False   False
6   d   6   False   True    False
7   d   7   False   False   True
8   d   8   False   False   True
9   d   9   True    False   False

Теперь вы можете использовать любые логики c, которые вы хотите создать T / B / M / N столбец:

df.loc[df.bottom & (~df.mid), "V"] = "B"
df.loc[df.top & (~df.mid), "V"] = "T"
df.loc[df.mid, "V"] = "M"
df.loc[df.bottom & df.top, "V"] = "N"

df[["ID", "V"]]

результат:

    ID  V
0   a   N
1   b   T
2   b   B
3   c   T
4   c   M
5   c   B
6   d   T
7   d   M
8   d   M
9   d   B
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...