У меня есть такой фрейм данных:
import numpy as np
import pandas as pd
df = pd.DataFrame({'year': [1990,1990,1992,1992,1992],
'value': [100,200,300,400,np.nan],
'rank': [2,1,2,1,3]})
print(df)
year value rank
0 1990 100.0 2
1 1990 200.0 1
2 1992 300.0 2
3 1992 400.0 1
4 1992 NaN 3
Я пытаюсь добиться этого:
# For year 1990, maximum value is 200, rank is 1 and also relative value is 1.
year value rank value_relative
0 1990 100.0 2 0.5
1 1990 200.0 1 1
2 1992 300.0 2 0.75
3 1992 400.0 1 1
4 1992 NaN 3 NaN
Моя попытка:
df['value_relative'] = df.groupby('year')['value'].transform(lambda x: x/x[x.rank == 1]['value'])
Как мы можем выполнить эту операцию, когда мы вычисляем относительную стоимость для каждого года?
IIUC с использованием transform
с first
после sort_values
df['value_relative']=df.value/df.sort_values('rank').groupby('year').value.transform('first')
df
Out[60]:
year value rank value_relative
0 1990 100.0 2 0.50
1 1990 200.0 1 1.00
2 1992 300.0 2 0.75
3 1992 400.0 1 1.00
4 1992 NaN 3 NaN
Или просто сделайте transform
max
df['value_relative']=df.value/df.groupby('year').value.transform('max')
Другой метод
df.value/df.loc[df.groupby('year')['rank'].transform('idxmin'),'value'].values
Out[64]:
0 0.50
1 1.00
2 0.75
3 1.00
4 NaN
Name: value, dtype: float64
Если вам нужен 2-й ранг в качестве знаменателя
df.value/df.year.map(df.loc[df['rank']==2].set_index('year')['value'])
Различие здесь зависит от того, как вы получаете свой ранг, если он основан на максимальном значении, то оба они должны возвращать один и тот же результат, но если это заданный ранг, не связанный со столбцами значений, тогда вы должны использовать first
@astro123, как я уже упоминал, я использую sort_values и первый, также я добавил еще один метод, используя idxmin
Для rank = 2
я пробовал transform('second')
и transform('nth(2))
, но не смог.
@ astro123 это должно быть n-е (1), также, если вы хотите найти 2-е, сделайте это с помощью df.year.map(df.loc[df['rank']==2].set_index('year')['value'])
К сожалению, это не удалось для меня df.value/df.sort_values('rank').groupby('year').value.transform('nth(1)')
@ astro123 нет, индекс должен совпадать
Я сделал это и получил точный ответ, как и вы, я также обновил свой простой ответ.
@ astro123 О, я вижу, вы делаете это в лямбде :-), но просто любезное предложение, лямбда замедлит весь процесс.
Спасибо за ценную информацию, я постараюсь избегать лямбда и обязательно буду следовать вашему подходу, я просто пробовал несколько простых способов делать вещи, не обращая внимания на эффективность.
Мне понравился и я принял ответ Вена, но хотел отдать свои 2 цента:
Самый простой способ - просто разделить значение на максимум, но я пытаюсь научиться делать это, используя отдельный столбец с именем rank:
df.groupby('year')['value'].transform(lambda x: x/x.max())
0 0.50
1 1.00
2 0.75
3 1.00
4 NaN
Еще один простой метод для ранга == 2:
df.groupby('year')['value'].transform(lambda x: x/x.nlargest(2).iloc[-1])
0 1.000000
1 2.000000
2 1.000000
3 1.333333
4 NaN
ПРИМЕЧАНИЕ. Метод Вена:
df.value/df.year.map(df.loc[df['rank']==2].set_index('year')['value'])
0 1.000000
1 2.000000
2 1.000000
3 1.333333
4 NaN
Обобщение, как делать когда
rank = 2
? Я знаю, что когда ранг равен 1, я могу просто разделить на максимальное значение.