Pandas: примените пользовательскую функцию к группам и сохраните результат в новых столбцах в каждой группе.

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

Я пробовал это:

# Returns True if all values in Column1 is different.
def is_unique(x):
    status = True
    if len(x) > 1:
        a = x.to_numpy() 
        if (a[0] == a).all():
            status = False
    return status

# Finds difference of the column values and returns the value with a message.
def func(x):
    d  = (x['Column3'].diff()).dropna()).iloc[0]
    return d, "Calculated!"

# is_unique() is another custom function used to filter unique groups.
df[['Difference', 'Message']] = df.filter(lambda x: is_unique(x['Column1'])).groupby(['Column2']).apply(lambda s: func(s))

Но я получаю сообщение об ошибке: 'DataFrameGroupBy' object does not support item assignment

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

df.get_group('XYZ')


   -----------------------------------------------------------------
   |   Column1 | Column2 | Column3  |  Difference   |    Message   |
   -----------------------------------------------------------------
   | 0   A     |   XYZ   |   100    |               |              |
   ----------------------------------               |              |
   | 1   B     |   XYZ   |    20    |      70       |  Calculated! |
   ----------------------------------               |              |
   | 2   C     |   XYZ   |    10    |               |              |
   -----------------------------------------------------------------

Как наиболее эффективно достичь этого результата?


person Animeartist    schedule 06.04.2021    source источник


Ответы (1)


Я думаю, вам нужно:

def func(x):
    d  = (x['Column3'].diff()).dropna()).iloc[0]
    last = x.index[-1]
    x.loc[last, 'Difference'] = d
    x.loc[last, 'Message'] = "Calculated!"
    return x

df1 = df.filter(lambda x: is_unique(x['Column1']))

df1 = df1.groupby(['Column2']).apply(func)
person jezrael    schedule 06.04.2021
comment
Однако я получаю эту ошибку: TypeError: объект «функция» не является итерируемым - person Animeartist; 06.04.2021
comment
@Animeartist - Хм, причина в том, что вывод - это DataFrame с тем же индексом, что и исходный df, кажется, в вашем решении Column2 преобразуется в индекс. Так что, возможно, нужно df = df.filter(lambda x: is_unique(x['Column1'])).groupby(['Column2']).apply(func).set_index('Column2') - person jezrael; 06.04.2021
comment
Спасибо, что ответили мне, но, к сожалению, я все еще получаю ту же ошибку. - person Animeartist; 06.04.2021
comment
@Animeartist - Какая ошибка возврата кода? - person jezrael; 06.04.2021
comment
df = df.filter(lambda x: is_unique(x['Column1'])).groupby(['Column2']).apply(func).set_index('Column2'). Эта строка возвращает ошибку. - person Animeartist; 06.04.2021
comment
@Animeartist - Трудно понять, в чем ошибка, потому что не удается запустить ваши образцы данных. Итак, вы можете опубликовать is_unique для возможного тестирования? - person jezrael; 06.04.2021
comment
Пожалуйста, смотрите правки, спасибо. - person Animeartist; 06.04.2021
comment
@Animeartist - также, если проверить print (type(df)) перед df.filter(lambda x: is_unique(x['Column1'])), будет DataFrame? - person jezrael; 06.04.2021
comment
@Animeartist - Если я использую print (df.filter(lambda x: is_unique(x['Column1']))), он возвращает TypeError: 'function' object is not iterable - person jezrael; 06.04.2021
comment
@Animeartist - ответ был отредактирован, как он должен работать, но не уверен на 100%, если понял. - person jezrael; 06.04.2021
comment
Привет, да df - это DataFrame. Я проверил код, и теперь я получаю эту ошибку: AttributeError: 'SeriesGroupBy' object has no attribute 'duplicated' - person Animeartist; 06.04.2021
comment
@Animeartist - Не понимаю, если print (type(df)) - это DataFrame, как может возвращаться ошибка SeriesGroupBy? Для этой ошибки это должен быть объект groupby, а не Dataframe. - person jezrael; 06.04.2021
comment
Привет, извиняюсь за ошибку. df на самом деле <class 'pandas.core.groupby.generic.DataFrameGroupBy'>. - person Animeartist; 06.04.2021
comment
Я делаю весь процесс на df, который представляет собой одну группу из другого объекта groupby. - person Animeartist; 06.04.2021
comment
@Animeartist - Да, можно опубликовать некоторые образцы данных и ожидаемый результат после запуска обеих функций? Потому что я что-то пробовал и потерпел неудачу. И почему это groupby объект? - person jezrael; 06.04.2021
comment
@Animeartist - ответ был отредактирован, я создал 2 строки - первая для is_unique (это не понятно), а затем решение для новых столбцов для каждой группы. - person jezrael; 06.04.2021
comment
Привет, спасибо, все работает правильно, но теперь сообщение и значение разницы повторяются для каждой строки группы, а не только один раз, как указано в вопросе. - person Animeartist; 06.04.2021
comment
@Animeartist - да, так что логика заключается в добавлении вывода для второй строки для каждой группы? А если не существует второго ряда? - person jezrael; 06.04.2021
comment
Можно ли объединить значения разницы и сообщения в одну ячейку соответственно? - person Animeartist; 06.04.2021
comment
@Animeartist - я потерялся, пожалуйста, измените данные, чтобы увидеть это. объединить означает объединить оба значения, преобразованные в строки? Или кортежи? Или что-то еще? - person jezrael; 06.04.2021
comment
@Animeartist - почему назначается только вторая строка на 70 и Calculated!? - person jezrael; 06.04.2021
comment
Привет, пожалуйста, ознакомьтесь с изменениями. Прямо сейчас 70 и Calculated повторяются трижды для каждой строки. Но я хочу объединить их только в одну запись, как показано в вопросе. - person Animeartist; 06.04.2021
comment
Давайте продолжим обсуждение в чате. - person jezrael; 06.04.2021