Python Pandas: сохраняется ли порядок при использовании groupby() и agg()?

python #pandas

#python #pandas #агрегировать

Вопрос:

Я часто использовал agg() функцию pandas для запуска сводной статистики по каждому столбцу data.frame. Например, вот как вы могли бы получить среднее и стандартное отклонение:

 df = pd.DataFrame({'A': ['group1', 'group1', 'group2', 'group2', 'group3', 'group3'],
                   'B': [10, 12, 10, 25, 10, 12],
                   'C': [100, 102, 100, 250, 100, 102]})

>>> df
[output]
        A   B    C
0  group1  10  100
1  group1  12  102
2  group2  10  100
3  group2  25  250
4  group3  10  100
5  group3  12  102
 

В обоих этих случаях порядок отправки отдельных строк в функцию agg не имеет значения. Но рассмотрим следующий пример, который:

 df.groupby('A').agg([np.mean, lambda x: x.iloc[1] ])

[output]

        mean  <lambda>  mean  <lambda>
A                                     
group1  11.0        12   101       102
group2  17.5        25   175       250
group3  11.0        12   101       102
 

В этом случае лямбда-выражение функционирует по назначению, выводя вторую строку в каждой группе. Однако я не смог найти ничего в документации pandas, что подразумевает, что это гарантированно будет верно во всех случаях. Я хочу использовать agg() вместе с функцией средневзвешенного значения, поэтому я хочу быть уверенным, что строки, входящие в функцию, будут в том же порядке, в каком они отображаются в исходном фрейме данных.

Кто-нибудь знает, в идеале, где-нибудь в документации или исходном коде pandas, если это гарантированно так?

Комментарии:

1. Да, я не вижу никаких гарантий, что порядок сохраняется в документах, поэтому полагаться на него немного неразумно. Если порядок отражается в вашем B столбце, вы можете отсортировать каждую группу B по лямбде, чтобы убедиться.

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

Ответ №1:

См. Эту проблему с улучшением

Короткий ответ — да, groupby сохранит порядок, переданный. Вы можете доказать это, используя свой пример следующим образом:

 In [20]: df.sort_index(ascending=False).groupby('A').agg([np.mean, lambda x: x.iloc[1] ])
Out[20]: 
           B             C         
        mean <lambda> mean <lambda>
A                                  
group1  11.0       10  101      100
group2  17.5       10  175      100
group3  11.0       10  101      100
 

Однако это НЕВЕРНО для повторной выборки, поскольку для этого требуется монотонный индекс (он БУДЕТ работать с немонотонным индексом, но сначала отсортирует его).

Это sort= флаг для groupby, но это относится к сортировке самих групп, а не к наблюдениям внутри группы.

К вашему сведению: df.groupby('A').nth(1) это безопасный способ получить 2-е значение группы (поскольку ваш метод, описанный выше, завершится неудачей, если в группе <2 элементов)

Комментарии:

1. Спасибо за разъяснения и ссылку на проблему! Первоначально я использовал iloc в качестве примера, потому что не мог понять, как перейти nth() к agg() вызову (потому что в этот момент x это серия). Есть ли какой-либо способ вызова nth() , отличный от функции-члена DataFrame?

2. nth определяется только для groupby. Что вы имеете в виду «кроме функции-члена DataFrame»?

3. Я имел в виду, что не мог понять, как передать nth() в качестве одной из функций, отправленных в списке agg() . Вы не можете сделать .agg([np.mean, nth]) , или DataFrame.nth() или lambda x: x.nth(2) . Это то, что привело меня к iloc, хотя это приведет к ошибкам индекса. Вероятно, лучший способ — не пытаться сделать все это за один шаг; сначала используйте nth() , затем используйте agg() , затем объедините их.

Ответ №2:

В документе Panda 0.19.1 говорится, что «groupby сохраняет порядок строк в каждой группе», так что это гарантированное поведение.

http://pandas.pydata.org/pandas-docs/stable/generated/pandas .DataFrame.groupby.html

Ответ №3:

Чтобы сохранить порядок, вам нужно пройти .groupby(..., sort=False) . В вашем случае столбец группировки уже отсортирован, поэтому это не имеет значения, но обычно необходимо использовать sort=False флаг:

  df.groupby('A', sort=False).agg([np.mean, lambda x: x.iloc[1] ])
 

Комментарии:

1. Для groupby есть флаг sort= , но это относится к сортировке самих групп, а не к наблюдениям внутри группы.

2. они должны были сделать это параметром по умолчанию, учитывая, что очень часто это используется

3. По иронии судьбы, в документации также говорится: «Повысьте производительность, отключив это». Ну, еще одна причина, по которой это должно было быть необязательной функцией, а не функцией по умолчанию. Самое главное, что он вносит изменения в данные, которых вызывающий абонент может и не ожидать.

Ответ №4:

Ссылка: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas .DataFrame.groupby.html

API принимает «СОРТИРОВКУ» в качестве аргумента.

Описание для аргумента СОРТИРОВКИ выглядит следующим образом:

сортировка: bool, по умолчанию Истинные ключи группы сортировки. Повысьте производительность, отключив эту функцию. Обратите внимание, что это не влияет на порядок наблюдений внутри каждой группы. Groupby сохраняет порядок строк внутри каждой группы.

Таким образом, ясно, что «Groupby» сохраняет порядок строк внутри каждой группы.

Ответ №5:

К сожалению, ответ на этот вопрос ОТРИЦАТЕЛЬНЫЙ. За последние несколько дней я создал алгоритм для неравномерного разбиения на фрагменты и обнаружил, что он не может сохранить порядок, потому что groupby вводит подкадры, где ключом к каждому кадру является ввод groupby. Итак, вы получаете:

 allSubFrames = df.groupby("myColumnToOrderBy")
for orderKey, individualSubFrame in allSubFrames:
     do something...
 

Поскольку он использует словари, вы теряете порядок.

Если после этого вы выполните сортировку, как упоминалось выше, которую я только что протестировал для большого набора данных, вы получите вычисление O (n log n) .

Однако я обнаружил, что если у вас, например, упорядочены данные временных рядов по порядку, где вы хотите сохранить порядок, лучше изменить столбец упорядочения в список, а затем создать счетчик, который записывает первый элемент в каждом временном ряду. Это приводит к вычислению O (n) .

Итак, по сути, если вы используете относительно небольшой набор данных, предложенные выше ответы являются разумными, но при использовании большого набора данных вам необходимо рассмотреть возможность отказа от groupby и сортировки. Вместо этого используйте: list(df['myColumnToOrderBy']) и итератор над ним.

Комментарии:

1. Не могли бы вы, пожалуйста, добавить простой пример рабочего кода к своему ответу?

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

Ответ №6:

Еще проще:

   import pandas as pd
  pd.pivot_table(df,index='A',aggfunc=(np.mean))
 

вывод:

             B    C
     A                
   group1  11.0  101
   group2  17.5  175
   group3  11.0  101