Объединение двух таблиц с миллионами строк в Python
Я использую Python для анализа данных. У меня есть две таблицы, первая (назовем ее "A") имеет 10 миллионов строк и 10 столбцов, а вторая ("B") имеет 73 миллиона строк и 2 столбца. У них есть 1 столбец с общими идентификаторами, и я хочу пересечь две таблицы на основе этого столбца. В частности, я хочу внутреннее соединение таблиц.
Я не мог загрузить таблицу B в память в качестве фрейма данных pandas, чтобы использовать обычную функцию слияния на панд. Я попытался прочитать файл таблица B на кусках, пересекая каждый кусок с A и объединяя эти пересечения (выход из внутренних соединений). Это нормально на скорости, но время от времени это дает мне проблемы и выплевывает ошибку сегментации ... не так здорово. Эту ошибку трудно воспроизвести, но она происходит на двух разных машинах (Mac OS X v10.6 (Snow Leopard) и UNIX, Red Hat Linux).
Я, наконец, попытался с комбинацией панд и PyTables, написав таблицу B на диск, а затем повторяя над таблицей A и выбрать из таблицы B соответствующие строки. Этот последний вариант работает, но он медленный. Таблица B в pytables уже индексирована по умолчанию.
Как мне решить эту проблему?
1 ответов
Это немного псевдо-кодиш, но я думаю, что должно быть довольно быстро.
простое слияние на основе диска со всеми таблицами на диске. Этот ключ в том, что вы не делаете выбор как таковой, просто индексируете в таблицу через start / stop, что довольно быстро.
выбор строк, удовлетворяющих критериям в B (с использованием идентификаторов A), не будет будьте очень быстрыми, потому что я думаю, что это может привести данные в пространство Python вместо поиска в ядре (я не уверен, но вы можете хотеть расследовать дальше pytables.org подробнее в разделе Оптимизация в ядре. Есть способ узнать, будет ли он в ядре или нет).
также, если вы до него, это очень параллельная проблема (просто не пишите результаты одного и того же файла из нескольких процессов. pytables не является безопасным для записи).
посмотреть ответ для комментария о том, как выполнение операции соединения на самом деле будет "внутренним" соединением.
для вашего merge_a_b операция я думаю, вы можете использовать стандартный pandas join что довольно эффективно (когда в памяти).
еще один вариант (в зависимости от того, насколько "большой" A), может заключаться в разделении A на 2 части (которые индексируются одинаково), используя меньший (возможно, один столбец) в первой таблице; вместо хранения результатов слияния как таковых, сохраните индекс строки; позже вы можете вытащить необходимые вам данные (вроде как с помощью индексатора и взять). Видеть http://pandas.pydata.org/pandas-docs/stable/io.html#multiple-table-queries
A = HDFStore('A.h5')
B = HDFStore('B.h5')
nrows_a = A.get_storer('df').nrows
nrows_b = B.get_storer('df').nrows
a_chunk_size = 1000000
b_chunk_size = 1000000
def merge_a_b(a,b):
# Function that returns an operation on passed
# frames, a and b.
# It could be a merge, join, concat, or other operation that
# results in a single frame.
for a in xrange(int(nrows_a / a_chunk_size) + 1):
a_start_i = a * a_chunk_size
a_stop_i = min((a + 1) * a_chunk_size, nrows_a)
a = A.select('df', start = a_start_i, stop = a_stop_i)
for b in xrange(int(nrows_b / b_chunk_size) + 1):
b_start_i = b * b_chunk_size
b_stop_i = min((b + 1) * b_chunk_size, nrows_b)
b = B.select('df', start = b_start_i, stop = b_stop_i)
# This is your result store
m = merge_a_b(a, b)
if len(m):
store.append('df_result', m)