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

df=pd.DataFrame([[1000, 12, 'slope'],
                [1000, 10, 'flat'],
                [1001, 10, 'slope'],
                [1001, 15, 'flat'],
                [1001, 7, 'slope']],
               index = [1,2,3,4,5],
               columns=['building_id', 'area', 'form'],
               )
df
building_id     area    form
1   1000    12  slope
2   1000    10  flat
3   1001    10  slope
4   1001    15  flat
5   1001    7   slope

Я хочу объединить ряды, чтобы у меня было по одному для каждого здания, с общей площадью крыши и преобладающей формой крыши - то есть формой, которая имеет наибольшую площадь для этого здания, а не формой, которая появляется чаще всего:

df_out
building_id     area    form
    1   1000    22  slope
    2   1001    32  slope

Мне нужно что-то вроде этого:

group_functions={'area' : ['sum'],
                 'form' : lambda x: find_predominant(x)}
df_out = df.groupby('building_id').agg(group_functions)

Но find_predominant должен быть функцией area так же, как и form: он возвращает строку 'flat' или 'slope' в зависимости от того, какая из них имеет наибольшую площадь для этого { { X5 } } .

Что такое функция find_predominant? Или какой сценарий будет иметь такой же эффект?

4
doctorer 24 Окт 2018 в 06:43

2 ответа

Лучший ответ

Вы можете использовать sort_values и назначить значение после agg

(df.groupby(['building_id','form'])['area']
   .sum()
   .sort_values()
   .reset_index(level=1)
   .groupby(level=0)
   .agg({'form':'last','area':'sum'}))

              form  area
building_id             
1000         slope    22
1001         slope    32
2
doctorer 24 Окт 2018 в 10:43

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

g = df.groupby('building_id')
area = g['area'].sum()
form = g.apply(find_predominant) 

df_out = pd.concat([area, form], axis=1)

Теперь, чтобы это сработало, обратите внимание, что find_predominant должен принять DataFrame и получить доступ к столбцам "area" и "form" соответствующим образом.

def find_predominant(df):
    ar = df['area']
    fm = df['form']
    ... # Do something with ar and fm

    return result

Это может или не может потребовать рефакторинга с вашей стороны.


Редактировать: Хорошо, так что вы не знаете, что это за функция. В таком случае, давайте избавимся от этого.

Попробуй это.

area = df.groupby('building_id')['area'].sum()
form = (df.groupby(['building_id', 'form'])['area']
          .sum()
          .groupby(level=0)
          .idxmax()
          .str[1])
form.name = 'form'

df_out = pd.concat([area, form], axis=1).reset_index()
print(df_out)
   building_id  area   form
0         1000    22  slope
1         1001    32  slope

Это выберет форму, соответствующую той, которая содержит максимальную площадь (по сумме) на building_id.

Если форма по максимальной сумме не требуется, и вы просто хотите форму по максимальной площади, тогда решение упрощается.

g = df.groupby('building_id')['area']
area = g.sum()
form = (df.set_index('building_id')
          .iloc[g.idxmax(), df.columns.get_loc('form') - 1])

df_out = pd.concat([area, form], axis=1).reset_index()
print(df_out)
   building_id  area   form
0         1000    22   flat
1         1001    32  slope
3
cs95 24 Окт 2018 в 04:15
52960783