Использование Groupby для группировки столбца в таблице Access в Python

#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 сортируется по тому же ключу, по которому вы группируете.