#python #group-by
#python #группировка по
Вопрос:
Я уже некоторое время играю с функцией groupby из модуля itertools (например, дни)
for k, g in groupby(data, keyfunc):
У меня действительно проблемы с пониманием синтаксиса. Я перепробовал множество разных вещей, но я действительно не знаю, что вставить для «data» и «keyfunc» и заставить его возвращать группы данных, которые я хочу в инструкции print.
Что я делаю, так это перебираю строки в таблице access.
Я устанавливаю переменную для поиска курсора (который сортируется) в таблице access и извлекаю нужный мне столбец.
for row in cursor:
print row.ROAD_TYPE
Это возвращает:
TRUNK ROAD
TRUNK ROAD
TRUNK ROAD
TRUNK ROAD
COLLECTOR HIGHWAY
COLLECTOR HIGHWAY
ACCESS ROAD
ACCESS ROAD
ACCESS ROAD
ACCESS ROAD
ACCESS ROAD
ACCESS ROAD
ACCESS ROAD
MAJOR ROAD
MAJOR HIGHWAY
Я хочу сгруппировать эти значения вместе и заставить его вернуть строковое значение для меня, чтобы оно печатало что-то вроде этого:
TRUNK ROAD
TRUNK ROAD
TRUNK ROAD
TRUNK ROAD
COLLECTOR HIGHWAY
COLLECTOR HIGHWAY
ACCESS ROAD
ACCESS ROAD
ACCESS ROAD
ACCESS ROAD
ACCESS ROAD
ACCESS ROAD
ACCESS ROAD
MAJOR ROAD
MAJOR HIGHWAY
Наконец, я хочу сгруппировать второй столбец на основе этих новых групп, чтобы получить что-то вроде этого:
TRUNK ROAD M1
TRUNK ROAD M1
TRUNK ROAD M2
TRUNK ROAD M3
COLLECTOR HIGHWAY M1
COLLECTOR HIGHWAY M2
ACCESS ROAD M1
ACCESS ROAD M1
ACCESS ROAD M3
ACCESS ROAD M3
ACCESS ROAD M7
ACCESS ROAD M7
ACCESS ROAD M8
MAJOR ROAD M8
MAJOR HIGHWAY M8
Я знаю, что это, вероятно, намного проще, чем я себе представлял, я чувствую, что есть простой ответ, но я совершенно в тупике, и, похоже, я не могу найти в Интернете пример, который объясняет синтаксис groupby так, как я понимаю. Пожалуйста, почувствуйте
Ответ №1:
import itertools as it
for key, group in it.groupby(cursor, lambda row: row.ROAD_TYPE):
for sec_col,pairs in it.groupby(group, lambda row: row.SECOND_COLUMN):
for row in pairs:
print('{t} {s}'.format(t=row.ROAD_TYPE,s=row.SECOND_COLUMN))
print
print
Вот два примера, которые помогут groupby:
[list(g) for k, g in it.groupby('AAAABBBCCD')]
# [['A', 'A', 'A', 'A'], ['B', 'B', 'B'], ['C', 'C'], ['D']]
Выше все одинаковые элементы сгруппированы вместе.
Теперь мы добавим ключевую функцию, keyfunc
:
keyfunc=lambda x: x//3
data=range(13)
[list(g) for k,g in it.groupby(data,keyfunc)]
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12]]
[k for k,g in it.groupby(data,keyfunc)]
# [0, 1, 2, 3, 4]
Теперь вместо группировки по элементам в data мы группируем в соответствии с keyfunc(x)
для каждого x
in data
.
Ответ №2:
Идея itertools.groupby
заключается в том, чтобы решить основную проблему: «Я хочу перебирать последовательность, анализировать каждую вещь в ней и в зависимости от процесса анализа каждую вещь по-разному». groupby
разделяет последовательность на группы, но сохраняет порядок исходной последовательности.
from itertools import groupby
i = groupby(xrange(12), lambda v: v / 3)
results = [(x[0], list(x[1])) for x in i]
print str(results)
Приведенные выше результаты: [(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9, 10, 11])]
Вы заметите, что для получения results
списка мне пришлось выполнить некоторую дополнительную обработку. То groupby
, что на самом деле дает вам, предназначено для итерации:
i = groupby(xrange(12), lambda v: v / 3)
print str(i.next())
Приведенные выше результаты: (0, <itertools._grouper object at 0x020BF3D0>)
Итак, идея заключается в том, что в вашей программе вы скажете key, valueiter = i.next()
: протестируйте key
, а затем перейдите valueiter
к правильной функции / методу обработки.
Итак, какое значение здесь? Ну, вам не нужно продолжать проверять ключ в ваших функциях обработки, чтобы определить, когда остановиться. groupby
автоматически остановит каждый «под-итератор» для вас.
Чего groupby
не нужно делать, в отличие от GROUP BY
предложения в SQL, так это гарантировать, что все с одинаковым значением ключа из исходного итерируемого обрабатывается одновременно. Значения ключа могут повторяться из groupby
. Это оправдано, поскольку цель состоит в том, чтобы сохранить порядок исходной последовательности, а не накапливать все в памяти. Например:
i = groupby(xrange(6), lambda v: v % 3) # note: modulo division
results = [(x[0], list(x[1])) for x in i]
print str(results)
Приведенные выше результаты: [(0, [0]), (1, [1]), (2, [2]), (0, [3]), (1, [4]), (2, [5])]
. Значения ключа повторяются, и каждый под-итератор выдает только один элемент данных. Это наихудший сценарий с точки зрения производительности для groupby
, и это означает, что вы должны следовать определенной модели при работе с этим инструментом.
Итак, что-то вроде этого:
i = groupby(xrange(12), lambda v: v / 3)
results = dict([(x[0], list(x[1])) for x in i]) # beware of dict() here!
print str(results)
это правильно, только если вы априори знаете, что ваши ключевые значения никогда не будут повторяться.
Ответ №3:
Ваши два groupby
примера выполнены точно так же, за исключением вашего выбора key
from itertools import groupby
from operator import attrgetter
for key, rows in groupby(cursor, key=attrgetter('ROAD_TYPE')):
for row in rows:
print row.ROAD_TYPE
print
for key, rows in groupby(cursor, key=attrgetter('ROAD_TYPE', 'OTHER_COLUMN')):
for row in rows:
print row.ROAD_TYPE, row.OTHER_COLUMN
print
В обоих случаях key
это будет результатом attrgetter() , но на самом деле вам это не понадобится, так как вы будете перебирать строки, сгруппированные по этому ключу. Конечно, все это работает правильно, если cursor
сортируется по тому же ключу, по которому вы группируете.