Восстановите стандартный фрейм данных с одним индексом после использования pandas groupby + apply - PullRequest
0 голосов
/ 01 марта 2019

Я хочу применить пользовательскую функцию сокращения к каждой группе в кадре данных Python.Функция сводит группу к одной строке, выполняя операции, объединяющие несколько столбцов группы.

Я реализовал это так:

import pandas as pd
import numpy as np

df = pd.DataFrame(data={
  "afac": np.random.random(size=1000),
  "bfac": np.random.random(size=1000),
  "class":np.random.randint(low=0,high=5,size=1000)
})

def f(group):
  total_area = group['afac'].sum()
  per_area   = (group['afac']/total_area).values
  per_pop    = group['bfac'].values
  return pd.DataFrame(data={'per_apop': [np.sum(per_area*per_pop)]})

aggdf = df.groupby('class').apply(f)

Мой кадр входных данных df выглядит так:

>>> df
         afac      bfac  class
0    0.689969  0.992403      0
1    0.688756  0.728763      1
2    0.086045  0.499061      1
3    0.078453  0.198435      2
4    0.621589  0.812233      4

Но мой код дает этот мультииндексированный фрейм данных:

>>> aggdf
         per_apop
class            
0     0  0.553292
1     0  0.503112
2     0  0.444281
3     0  0.517646
4     0  0.503290

Я пробовал разные способы возврата к "нормальному" фрейму данных, но, похоже, ничего не работает.

>>> aggdf.reset_index()
   class  level_1  per_apop
0      0        0  0.553292
1      1        0  0.503112
2      2        0  0.444281
3      3        0  0.517646
4      4        0  0.503290

>>> aggdf.unstack().reset_index()
  class  per_apop
                0
0     0  0.553292
1     1  0.503112
2     2  0.444281
3     3  0.517646
4     4  0.503290

Как я могу выполнить эту операцию и впоследствии получить нормальный фрейм данных?

Обновление: Фрейм выходных данных должен иметьстолбцы для class и per_apop.В идеале функция f может возвращать несколько столбцов и, возможно, несколько строк.Возможно, используя

return pd.DataFrame(data={'per_apop': [np.sum(per_area*per_pop),2], 'sue':[1,3]})

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

Вы можете выбрать уровень для сброса, а также, если хотите сохранить индекс, используя reset_index.В вашем случае вы получили мультииндекс, который имеет 2 уровня: class и один безымянный.reset_index позволяет сбросить весь индекс (по умолчанию) или только те уровни, которые вы хотите.В следующем примере уровень last (-1) извлекается из индекса.При использовании drop=True он удаляется, а не добавляется в виде столбца во фрейме данных.

aggdf.reset_index(level=-1, drop=True)

       per_apop
class
0      0.476184
1      0.476254
2      0.509735
3      0.502444
4      0.525287

РЕДАКТИРОВАТЬ:

Чтобы вернуть уровень class индекса обратно кфрейм данных, вы можете просто позвонить .reset_index() снова.Ужасно, но это работает.

aggdf.reset_index(level=-1, drop=True).reset_index()

   class  per_apop
0      0  0.515733
1      1  0.497349
2      2  0.527063
3      3  0.515476
4      4  0.494530

Кроме того, вы также можете сбросить индекс, а затем просто удалить дополнительный столбец.

aggdf.reset_index().drop('level_1', axis=1)


   class  per_apop
0      0  0.515733
1      1  0.497349
2      2  0.527063
3      3  0.515476
4      4  0.494530
0 голосов
/ 01 марта 2019

Возвращает функция самоопределения Series

def f(group):
  total_area = group['afac'].sum()
  per_area   = (group['afac']/total_area).values
  per_pop    = group['bfac'].values
  return pd.Series(data={'per_apop': np.sum(per_area*per_pop)})
df.groupby('class').apply(f).reset_index()

   class  per_apop
0      0  0.508332
1      1  0.505593
2      2  0.488117
3      3  0.481572
4      4  0.500401
...