Замените значения столбца в группе и условии

У меня есть кадр данных, в котором я хочу найти минимальное значение столбца в группе, а затем на основе этой строки обновить значения некоторых других столбцов.

Следующий код делает то, что я хочу:

import pandas as pd

df = pd.DataFrame({'ID': [1,1,1,2,2,2,],
                   'Albedo': [0.2, 0.4, 0.5, 0.3, 0.5, 0.1],
                   'Temp' : [20, 30, 15, 40, 10, 5],
                   'Precip': [200, 100, 150, 60, 110, 45],
                   'Year': [1950, 2000, 2004, 1999, 1976, 1916]})

#cols to replace values for
cols = ['Temp', 'Precip', 'Year']

final = pd.DataFrame()


for key, grp in df.groupby(['ID']):

    #minimum values based on year
    replace = grp.loc[grp['Year'] == grp['Year'].min()]

    #replace the values
    for col in cols:
        grp[col] = replace[col].unique()[0]  

    #append the values
    final = final.append(grp)
print(final)

который дает:

   Albedo  ID  Precip  Temp  Year
0     0.2   1     200    20  1950
1     0.4   1     200    20  1950
2     0.5   1     200    20  1950
3     0.3   2      45     5  1916
4     0.5   2      45     5  1916
5     0.1   2      45     5  1916

поэтому в каждой группе из ID я нахожу минимум Year, а затем обновляю Temp, Precip и Year других строк. Это похоже на много циклов, и мне интересно, есть ли лучший способ.


person Stefano Potter    schedule 08.01.2018    source источник


Ответы (1)


Используйте groupby на ID + transform + idxmin на Year, чтобы получить ряд индексов. Передайте эти индексы loc, чтобы получить результат.

(df.iloc[df.groupby('ID')['Year'].transform('idxmin')]
   .reset_index(drop=True)
   .assign(Albedo=df['Albedo']))

   Albedo  ID  Precip  Temp  Year
0     0.2   1     200    20  1950
1     0.4   1     200    20  1950
2     0.5   1     200    20  1950
3     0.3   2      45     5  1916
4     0.5   2      45     5  1916
5     0.1   2      45     5  1916
person cs95    schedule 08.01.2018
comment
если я хочу назначить два столбца, как бы я это изменил? например df.iloc[idx].reset_index(drop=True).assign(Albedo=df.Albedo, Temp=df.Temp) - person Stefano Potter; 08.01.2018
comment
@StefanoPotter Вот как бы вы это сделали, да. - person cs95; 08.01.2018
comment
@StefanoPotter В качестве альтернативы передайте dict: .assign(**{'Albedo' : df.Albedo, 'Temp' : df.Temp}) ... весьма полезно, если вам нужно создать композицию dict. - person cs95; 08.01.2018