Pandas .DataFrame.GroupBy.agg, независимый столбец, необходимый для функции агрегирования. Как получить это в агг? - PullRequest
0 голосов
/ 29 апреля 2020

У меня есть Pandas объект DataFrame с двухуровневым MultiIndex. Кроме того, он, очевидно, содержит ряд дополнительных столбцов (например, «A», «B», «C», «D», «E»). Я хочу выполнить некоторую функцию агрегирования для отдельных мультииндексов в DataFrame для каждого отдельного столбца из подмножества доступных столбцов (скажем, «C», «D», «E»). Для этого я выбираю только подмножество столбцов, использую GroupBy, чтобы сгруппировать таким образом отрезанный кадр данных по levels=[0,1], и выполняю agg со словарем, конфигурирующим функцию агрегирования для каждого из выбранных столбцов из упомянутого подмножества.

df[['C', 'D', 'E']].groupby(level=[0, 1]).agg({'C': aggfunc, 'D': aggfunc, 'E': aggfunc})

Моя проблема сейчас заключается в том, что в дополнение к агрегированному в данный момент столбцу, который передается в функцию агрегирования, мне нужен второй столбец, например «B», в функции агрегирования. Таким образом, это в основном агрегация двух столбцов, один из которых ['C', 'D', 'E'] плюс 'B'.

Что я мог сделать, так это заменить aggfunc закрытием, которое знает «B». Это единственный способ? Или есть способ заставить Pandas также передать 'B' в функцию агрегации в дополнение к 'C', 'D', 'E'?

Пример ноутбука

Я создал блокнот Jupyter для создания примеров данных. В этом примере вы можете видеть столбцы serial и turn, которые образуют MultiIndex, и столбец milage, который является независимым столбцом, который мне нужен в функции агрегации в дополнение к столбцам m1 до * 1017. * каждый. Поэтому в функции мне нужно m<n> (в зависимости от того, что обрабатывается в данный момент) плюс milage. Поскольку milage также является значением с плавающей точкой, я не могу использовать его в качестве индекса.

Блокнот можно найти здесь: https://github.com/HWiese1980/public_notebooks/blob/master/example.ipynb

1 Ответ

0 голосов
/ 29 апреля 2020

Проблема в agg функция 'see' только обработка столбцов, а не других.

Так что это возможно, но не выполняется, потому что необходима фильтрация по группам:

np.random.seed(2020)
cols = ["serial", "turn", "milage", "m1", "m2", "m3", "m4"]
df = pd.DataFrame(columns=cols).set_index("serial", "turn")

serials = ["11111", "11222", "12345"]

data = []
end = 0.0
for s in serials:
    for t in range(np.random.randint(6)):
        start = end + np.random.rand() * 1000.
        end = start + np.random.rand() * 1000.
        run_point_count = np.random.randint(high=10, low=5)
        milages = np.linspace(start, end, run_point_count)
        for entry in range(run_point_count):
            d = np.hstack((np.array([s, t]), [milages[entry]], np.random.rand(4)))
            _df = {}
            for i, c in enumerate(cols): 
                _df[c] = d[i]
            data.append(_df)

df_out = df.append(data, ignore_index=True, sort=True).set_index(["serial", "turn"])
df_out = df_out.astype(float)
#print (df_out)

def aggfunc(x):
    return x.sum() + df_out.loc[x.index, "milage"].mean()

#need unique MultiIndex
df_out = df_out.set_index(df_out.groupby(level=[0, 1]).cumcount(), append=True)
df = (df_out.groupby(level=[0, 1])
           .agg({'m1': aggfunc, 'm2': aggfunc, 'm3': aggfunc, 'm4': aggfunc}))
print (df)
                      m1           m2           m3           m4
serial turn                                                    
12345  0      735.612167   734.425345   733.988098   736.534878
       1     1763.739719  1762.587273  1763.196721  1763.929828
       2     2582.773092  2583.585509  2582.582403  2582.121202

Второе решение - преобразовать столбец в FloatIndex:

def aggfunc(x):
    return x.sum() + np.mean(x.index.get_level_values(3))


df = (df_out.set_index('milage', append=True)
           .groupby(level=[0, 1])
           .agg({'m1': aggfunc, 'm2': aggfunc, 'm3': aggfunc, 'm4': aggfunc}))
print (df)
                      m1           m2           m3           m4
serial turn                                                    
12345  0      735.612167   734.425345   733.988098   736.534878
       1     1763.739719  1762.587273  1763.196721  1763.929828
       2     2582.773092  2583.585509  2582.582403  2582.121202

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

Если возможно, использовать некоторые функции, работающие со всеми столбцами DataFrame use GroupBy.apply:

def f(x):
       return x[['m1','m2','m3','m4']].sum() + x['milage'].mean()

df = df_out.groupby(level=[0, 1]).apply(f)
print (df)
                      m1           m2           m3           m4
serial turn                                                    
12345  0      735.612167   734.425345   733.988098   736.534878
       1     1763.739719  1762.587273  1763.196721  1763.929828
       2     2582.773092  2583.585509  2582.582403  2582.121202
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...