Используйте пользовательскую функцию с stack
и value_counts
:
def f(x):
s = x.stack().value_counts()
return pd.Series([s.index[0], s.index[1]], index=['top_1','top_2'])
Или используйте Counter
со сглаженными значениями с Counter.most_common
:
from collections import Counter
def f(x):
c = Counter([y for x in x.values.tolist() for y in x])
a = c.most_common(2)
return pd.Series([a[0][0], a[1][0]], index=['top_1','top_2'])
df1 = df.groupby('sex')['app_0','app_1','app_2'].apply(f)
df = df.join(df1, on='sex')
print (df)
id app_0 app_1 app_2 sex top_1 top_2
0 1 a b c 0 b c
1 2 b c b 0 b c
2 3 c d a 1 a d
3 4 d NaN a 1 a d
РЕДАКТИРОВАТЬ:
Более общее решение работает, если не существует второй верхний значения с next
:
df=pd.DataFrame({'id':[1,2,3,4],'app_0':['a','a','a','a'],
'app_1':['a','a','a',np.nan],'app_2':['a','a','a','a'],'sex':[0,0,1,1]})
print (df)
id app_0 app_1 app_2 sex
0 1 a a a 0
1 2 a a a 0
2 3 a a a 1
3 4 a NaN a 1
def f(x):
c = Counter([y for x in x.values.tolist() for y in x])
a = iter(c.most_common(2))
return pd.Series([next(a, ['no top1'])[0],
next(a, ['no top2'])[0]], index=['top_1','top_2'])
df1 = df.groupby('sex')['app_0','app_1','app_2'].apply(f)
df = df.join(df1, on='sex')
print (df)
id app_0 app_1 app_2 sex top_1 top_2
0 1 a a a 0 a no top2
1 2 a a a 0 a no top2
2 3 a a a 1 a NaN
3 4 a NaN a 1 a NaN