Кросс-табуляция (таблица сопряженности) с использованием Python ORM? - PullRequest
3 голосов
/ 11 марта 2011

Любой, кто проводит очень простые статистические исследования данных, живущих в реляционной базе данных, должен был вычислять перекрестные таблицы, также известные как таблицы непредвиденных обстоятельств ( страница википедии ). они незаменимы, когда вам нужно посчитать, сколько предметов попадают в несколько категорий одновременно. Например: сколько клиентов составляют женщины и любят шоколад?

У Сципи есть способы сделать это для матриц, используя вариацию гистограммы2d. Но для полноценного статистического анализа у вас должна быть возможность иметь таблицу (с именами переменных), из которой вы можете указать, какие переменные вы хотите табулировать. Более того, он должен работать для других типов переменных, а не только для числовых. На самом деле, числовая табуляция является более сложной, поскольку она требует биннинга. R, естественно, имеет такую ​​функцию, которая называется table, которая может быть легко перенесена в Python. Однако, помните, я упомянул в заголовке, что я хотел бы использовать ORM, почему? Поскольку кросс-таблицы намного меньше, чем данные, используемые для их генерации, вы можете получить таблицу 2х2, рассчитанную на основе миллиардов записей в базе данных. Моя точка зрения такова: в серьезных приложениях вы не можете позволить себе переносить все данные в память и проходить через них. Таким образом, вам нужно преобразовать дизайн таблицы в SQL-запрос, чтобы подсчет выполнялся механизмом базы данных. И ORM позаботится о необходимых корректировках диалекта SQL, необходимых для того, чтобы вы могли запускать свой код с любым бэкэндом базы данных. Пример SQL (на диалекте MySQL) для простой кросс-табуляции можно найти здесь .

Итак, теперь, когда я думаю, что мотивировал вас на проблему, вот вопросы: Реализована ли эта функциональность в любом Python ORM? Как бы вы реализовали это, используя, скажем, SQLAlchemy или Django ORM?

1 Ответ

2 голосов
/ 11 марта 2011

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

table = self.session.query(Table.var1, Table.var2, func.count(Table)).group_by(Table.var1, Table.var2).all()

Это вернет список таких кортежей, как (строка, столбец, количество). Из этого списка вы можете собрать свою таблицу непредвиденных расходов и рассчитать итоговую маржу, если хотите. Стоит упомянуть, что для расчета этого кабеля потребовалось .28 секунд для таблицы с 296110 записями, а var1 и var2 имели уровни 5 и 90 соответственно.

теперь небольшая функция для сборки и печати (2d) таблицы:

def pprint_table():
    colnames = list(set([i[1] for i in table]))
    rows = defaultdict(lambda:[0]*len(colnames))
    for r in table:
        rows[r[0]][colnames.index(r[1])] = r[2]
    print colnames, 'total'
    for rn, r in rows.items():
        print rn, r, sum(r)
...