Найдите индекс столбца, который имеет максимальное значение для каждой строки
У меня есть ниже фрейм данных:
Name1 Scr1 Name2 Scr2 Name3 Scr3
NY 21 CA 45 SF 37
AZ 31 BK 46 AK 23
Я пытаюсь получить максимальное значение каждой строки и соответствующее имя для каждой строки:
df.idxmax(axis=1)
Но как мне получить соответствующее имя?
Ожидаемый результат:
Name Hi_Scr
CA 45
BK 46
3 ответа
Решение
Использование:
- фильтровать столбцы с
Scr
отfilter
, преобразовать значения в массив numyvalues
- получить индексы максимальных значений с
argmax
- фильтровать столбцы с
Name
и выберите индексированием - получить максимальные значения числовых
- Создайте
DataFrame
по конструктору
a = df.filter(like='Scr').values
b = a.argmax(axis=1)
c = df.filter(like='Name').values[np.arange(len(df.index)), b]
d = a.max(axis=1)
df = pd.DataFrame({'Name':c, 'Hi_Scr':d}, columns=['Name','Hi_Scr'])
print (df)
Name Hi_Scr
0 CA 45
1 BK 46
Решение Pandas очень похоже - создайте MultiIndex в столбцах extract
затем выберите xs
и для поиска значений использовать lookup
:
a = df.columns.to_series().str.extract('(\D+)(\d+)', expand=False)
df.columns = pd.MultiIndex.from_tuples(a.values.tolist())
a = df.xs('Scr', axis=1)
b = a.idxmax(axis=1)
c = df.xs('Name', axis=1).lookup(df.index, b)
d = a.max(axis=1)
df = pd.DataFrame({'Name':c, 'Hi_Scr':d}, columns=['Name','Hi_Scr'])
print (df)
Name Hi_Scr
0 CA 45
1 BK 46
Сроки:
df = pd.concat([df]*10000).reset_index(drop=True)
def jez2(df):
a = df.columns.to_series().str.extract('(\D+)(\d+)', expand=False)
df.columns = pd.MultiIndex.from_tuples(a.values.tolist())
a = df.xs('Scr', axis=1)
b = a.idxmax(axis=1)
c = df.xs('Name', axis=1).lookup(df.index, b)
d = a.max(axis=1)
return pd.DataFrame({'Name':c, 'Hi_Scr':d}, columns=['Name','Hi_Scr'])
def jez1(df):
a = df.filter(like='Scr').values
b = a.argmax(axis=1)
c = df.filter(like='Name').values[np.arange(len(df.index)), b]
d = a.max(axis=1)
return pd.DataFrame({'Name':c, 'Hi_Scr':d}, columns=['Name','Hi_Scr'])
def dark(df):
df['id'] = df.index
ndf = pd.wide_to_long(df, ["Name", "Scr"], i="id", j="number").reset_index(0).set_index('Name')
return ndf.groupby('id')['Scr'].agg(['max','idxmax']).rename(columns= {'max':'Hi_Scr','idxmax':'Name'})
import time
t0 = time.time()
print (jez1(df).head())
t1 = time.time() - t0
print (t1)
print (dark(df).head())
t2 = time.time() - t1
print (t2)
print (jez2(df).head())
t3 = time.time() - t2
print (t3)
Name Hi_Scr
0 CA 45
1 BK 46
2 CA 45
3 BK 46
4 CA 45
#jez1 solution
0.015599966049194336
Hi_Scr Name
id
0 45 CA
1 46 BK
2 45 CA
3 46 BK
4 45 CA
#dark solution
1515070100.961423
Name Hi_Scr
0 CA 45
1 BK 46
2 CA 45
3 BK 46
4 CA 45
#jez2 solution
0.04679989814758301
Я бы сделал это с pd.wide_to_long
как это:
df['id'] = df.index
ndf = pd.wide_to_long(df, ["Name", "Scr"], i="id", j="number").reset_index(0).set_index('Name')
# id Scr
# Name
# NY 0 21
# AZ 1 31
# CA 0 45
# BK 1 46
# SF 0 37
# AK 1 23
# Thank you @jezrael for the improvement
ndf.groupby('id')['Scr'].agg(['max','idxmax']).rename(columns= {'max':'Hi_Scr','idxmax':'Name'})
Name Hi Scr
id
0 CA 45
1 BK 46
Что-то вроде
df1=df.select_dtypes(include=[object])
df2=df.select_dtypes(exclude=[object])
pd.DataFrame({'Name':df1.values[np.where(df2.eq(df2.max(1),0))],'Scr':df2.max(1)})
Out[342]:
Name Scr
0 CA 45
1 BK 46