Одним из способов является использование логических значений и добавление их для создания категориальной категории:
In [11]: a = pd.Series(df.type.str.match('correct|incorrect').values, df.key).groupby(level=0).transform('all')
In [12]: m = pd.Series((df.type == 'missed').values, df.key).groupby(level=0).transform('all')
In [13]: pd.Categorical.from_codes(a + 2 * m, ['pass', 'no', 'yes'])
Out[13]:
[no, no, pass, pass, yes, yes, pass, pass]
Categories (3, object): [pass, no, yes]
In [14]: df["only_missed"] = pd.Categorical.from_codes(a + 2 * m, ['pass', 'no', 'yes'])
In [15]: df
Out[15]:
key type only_missed
0 1 correct no
1 1 incorrect no
2 2 missed pass
3 2 incorrect pass
4 3 missed yes
5 3 missed yes
6 2 correct pass
7 4 pass pass
Это выглядит как маленький хакер с .values
(чтобы избежать повторной индексации)но должно быть весьма эффективным ...
Посмотрев еще раз, это был "неправильный" вывод, но я оставлю его там, поскольку он по сути тот же.Для того, чтобы получить правильное значение, вы должны посмотреть на все «пасы»:
In [21]: p = pd.Series((df.type == 'pass').values, df.key).groupby(level=0).transform('all')
In [22]: pd.Categorical.from_codes(m + 2 * p, ['no', 'yes', 'pass'])
Out[22]:
[no, no, no, no, yes, yes, no, pass]
Categories (3, object): [no, yes, pass]
In [23]: df['only_missed'] = pd.Categorical.from_codes(m + 2 * p, ['no', 'yes', 'pass'])
In [24]: df
Out[24]:
key type only_missed
0 1 correct no
1 1 incorrect no
2 2 missed no
3 2 incorrect no
4 3 missed yes
5 3 missed yes
6 2 correct no
7 4 pass pass