Как сгруппировать строки панд по функциям из нескольких столбцов - PullRequest
0 голосов
/ 24 октября 2018

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

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' в зависимости от того, какая область имеет наибольшую для этого building_id.

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

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Вы можете использовать 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
0 голосов
/ 24 октября 2018

Мое предложение будет рассчитывать сумму и вызывать функцию 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...