2016-01-26 6 views
0

у меня есть набор данных, как следующее:Применение агрегации с несколькими аргументами

df = pd.DataFrame({ 
         "person":[i for i in range(5)]*2, 
         "val_1":np.random.randn(10), 
         "val_1_entry": ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'], 
         "val_2":np.random.randn(10), 
         "val_2_entry": ['b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'] 
         }).sort_values('person') 

    person  val_1 val_1_entry  val_2 val_2_entry 
0  0 -0.174681   a 0.464660   b 
5  0 0.049361   f 1.332204   g 
1  1 1.113805   b 0.261678   c 
6  1 -0.847422   g -0.272731   h 
2  2 -0.583784   c 1.815190   d 
7  2 -1.101540   h -1.660562   i 
3  3 0.919850   d 0.651178   e 
8  3 1.309287   i 0.776856   j 
4  4 1.395888   e 0.180980   f 
9  4 0.699365   j -1.108057   k 

Для каждого человека, я хочу, чтобы агрегировать данные, принимая минимальное и максимальное (и, возможно, некоторое произвольное значение), и принять соответствующее значение. Если я простая агрегация, где я беру мин и макс, что работает отлично ...

df_proc = (df 
      .groupby('person') 
      .agg({'val_1': ['max', 'min'], 
       'val_2': ['max', 'min']})) 

      val_1    val_2   
      max  min  max  min 
person           
0  0.049361 -0.174681 1.332204 0.464660 
1  1.113805 -0.847422 0.261678 -0.272731 
2  -0.583784 -1.101540 1.815190 -1.660562 
3  1.309287 0.919850 0.776856 0.651178 
4  1.395888 0.699365 0.180980 -1.108057 

, но что я хотел бы это иметь на соответствующие записи в той же строке, что и их собственных переменный.

  val_1    val_2   val_1_entry val_2_entry 
      max  min  max  min   max   min 
person           
0  0.049361 -0.174681 1.332204 0.464660   f   a 
1  1.113805 -0.847422 0.261678 -0.272731   b   g 
2  -0.583784 -1.101540 1.815190 -1.660562   c   h 
3  1.309287 0.919850 0.776856 0.651178   i   d 
4  1.395888 0.699365 0.180980 -1.108057   e   j 

и так далее.

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

Другим подходом может быть применение фильтров к данным для каждой группы, выбор строк с max и min, а затем распространение данных, но я не совсем уверен, как это сделать; query не работает с сгруппированными объектами, а фильтр дает мне df.groupby('person').filter(lambda x: x['val_1'] == x['val_1']min()), давая мне ошибку о получении серии, ожидая логического.

ответ

1

Вы можете добиться этого, используя apply() для групп. Предполагая, что df определяется, как указано выше, это выплюнет указанный желаемый результат:

val_cols = ['val_1', 'val_2'] 
def minmax(data): 
    mins, maxs = [], [] 
    for vc in val_cols: 
     data= data.sort(vc) # use sort_values() with newer Pandas version 
     mins.append(pd.Series(data.iloc[0][[vc, '%s_entry' % vc]], name='min')) 
     maxs.append(pd.Series(data.iloc[-1][[vc, '%s_entry' % vc]], name='max')) 
    min = pd.concat(mins) 
    max = pd.concat(maxs) 
    return pd.DataFrame([min, max]) 
df.groupby('person').apply(minmax).unstack(-1) 
+0

Это отличный ответ. К сожалению, я понял, что сделал ошибку в своем описании, поскольку выбранное поле ввода значения должно быть одинаковым как для min, так и для max (то есть, например, 'val_2_entry' не должно быть, и я должен выбрать из' val_1_entry' для min/max 'val_1' и' val_2'. Прямое применение вашего решения дает мне немного головную боль (из-за повторяющихся индексов), но это намного дальше, чем я сам, так что, надеюсь, я смогу адаптировать ваше решение. – goodtimeslim

+0

Хорошо, это было не сложно, просто примените переименование, когда была создана серия. Еще раз спасибо. – goodtimeslim

Смежные вопросы