2017-02-11 8 views
2

При вызове функции с помощью groupby + apply, я хочу, чтобы перейти от DataFrame к Series объекту GroupBy, применить функцию к каждой группе, которая принимает Series в качестве входных данных и возвращает Series, а затем назначить вывод из groupby + apply вызов в качестве поля в поле DataFrame. По умолчанию используется вывод из groupby + apply, проиндексированный полями группировки, что мешает мне переписать его обратно на DataFrame. Я бы предпочел, чтобы функция, которую я вызываю, применяю, беру Series как входной сигнал и возвращаю Series в качестве вывода; Я думаю, что это немного чище, чем DataFrame до DataFrame. (Это не самый лучший способ добраться до результата для этого примера, реальное применение довольно разные.)Сохранил индекс DataFrame, когда с помощью GroupBy применяется для создания Series

import pandas as pd 
df = pd.DataFrame({ 
'A': [999, 999, 111, 111], 
'B': [1, 2, 3, 4], 
'C': [1, 3, 1, 3] 
}) 
def less_than_two(series): 
    # Intended for series of length 1 in this case 
    # But not intended for many-to-one generally 
    return series.iloc[0] < 2 
output = df.groupby(['A', 'B'])['C'].apply(less_than_two) 

Я хочу индекс output быть такой же, как df, в противном случае я не могу назначить к df (чисто):

df['Less_Than_Two'] = output 

Что-то вроде output.index = df.index кажется слишком уродливым, и используя group_keys аргумент, кажется, не работает:

output = df.groupby(['A', 'B'], group_keys = False)['C'].apply(less_than_two) 
df['Less_Than_Two'] = output 

ответ

1

transform возвращает результаты с оригиналом index, точно так же, как вы просили. Он будет транслировать один и тот же результат по всем элементам группы. Caveat, остерегайтесь того, что dtype может быть выведено как нечто другое. Возможно, вам придется бросить его самостоятельно.

В этом случае для того, чтобы добавить еще один столбец, я бы использовал assign

df.assign(
    Less_Than_Two=df.groupby(['A', 'B'])['C'].transform(less_than_two).astype(bool)) 

    A B C Less_Than_Two 
0 999 1 1   True 
1 999 2 3   False 
2 111 3 1   True 
3 111 4 3   False 
+0

Похоже, что 'transform' сохраняет те же' dtype', что и поле ввода. Мне понравилось, что 'transform' хранит оригинальный' Index', хотя я не обязательно смотрю на трансляцию здесь, что, я думаю, не имеет значения, потому что результаты имеют длину 1. Этот ответ является лучшим по духу, хотя в полная проблема 'transform' преобразует' boolean' в 'datetime', которая не может быть преобразована обратно в' boolean'. Исходя из R, я чувствую, что «Индекс» - это обоюдоострый меч, а «dtypes» - это сложный процесс, но мне нравится многое другое. –

0

Необходимо, чтобы ваш groupby был необходим (и результирующий объект groupby будет иметь меньше строк, чем ваш DataFrame - это не относится к данным примера), тогда назначение столбца столбцу «Is.Even» приведет к NaN (поскольку индекс до output будет короче индекса до df).

Вместо этого на основе, например, данные, самый простой подход будет сливаться output - как DataFrame - с df, например, так:

output = df.groupby(['A','B'])['C'].agg({'C':is_even}).reset_index() # reset_index restores 'A' and 'B' from indices to columns 
output.columns = ['A','B','Is_Even'] #rename target column prior to merging 
df.merge(output, how='left', on=['A','B']) # this will support a many-to-one relationship between combinations of 'A' & 'B' and 'Is_Even' 
# and will thus properly map aggregated values to unaggregated values 

Кроме того, следует отметить, что вы лучше выключение с использованием символов подчеркивания, чем точек в именах переменных; в отличие от R, например, точки действуют как операторы для доступа к свойствам объекта, и поэтому использование их в именах переменных может блокировать функциональность/создавать путаницу.

+0

Благодаря @cmaher. Мой пример был невелик; просто обновлено. Цель использования use dataframe.groupby [имя поля] .apply для серий серии с тем же индексом, где результат будет иметь ту же форму, что и входная серия, для приложений «многие-ко-многим». –

+0

Нет проблем. До сих пор неясно, зачем вам вообще нужна группа; основанный на вашем описании и пример кода, вы можете создать столбец 'Less_Than_Two' с помощью' df.loc [:, 'Less_Than_Two'] = df.C.apply (less_than_two) ' – cmaher

+0

Я большой поклонник сплит- apply-comb, а 'DataFrame' в' DataFrame' в 'pandas' довольно интуитивно понятен.В принципе, мне нравится использовать простейшую структуру данных, которую я могу, поэтому я хочу делать 'Series'' 'Series', но обработка« Index »меня бросает. Если бы этот пример появился в реальном мире, я бы просто сделал 'df.C <2', но проблема, над которой я работаю, немного отличается. –