Как сравнить фреймы данных, которые слишком велики, чтобы поместиться в памяти, с помощью Python?

#python #pandas #dataframe #python-xarray

Вопрос:

У меня потенциально большие фреймы данных, порядка 10 столбцов и 1e6 строк, с разными размерами. Предположим, что строки уникальны в обоих кадрах данных. Поскольку эти кадры данных не могут быть загружены в память, как мне найти все строки в одном кадре данных, которые существуют в другом? В настоящее время я работаю только с меньшими кадрами данных, но мне скоро придется это выяснить.

Я настоятельно предпочитаю использовать pandas, но я готов использовать другой пакет (xarray?), если есть значительные преимущества. Если вы рекомендуете другой пакет, пожалуйста, предоставьте какой-нибудь код для сравнения.

Вот как я провожу сравнение с кадрами данных pandas, которые помещаются в памяти:

 import pandas as pd

def row_intersection(df1, df2):
    noNA = df2.fillna(0)
    return df1.fillna(0).apply(lambda x: (noNA==x).all(axis=1).any(), axis=1)

a = DataFrame({'a':[ 1, 2, 3, 4],
               'b':[ 1, pd.NA, 13, 14],
               'c':['w', 'x', 'y', 'z']})
b = DataFrame({'a':[3, 2, 4],
               'b':[1, pd.NA, 14],
               'c':['y', 'x', 'z']})

# there are equivalent rows in both dataframes:
print('row comparison:',(b.fillna(0).loc[[1,2]].values == a.fillna(0).loc[[1,3]].values).all())


print(row_intersection(a, b))
 

выход:

 row comparison: True
0    False
1     True
2    False
3     True
dtype: bool
 

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

 a_in_b = row_intersection(a, b)
b_in_a = row_intersection(b, a)
 

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

1. можете ли вы просто разделить фрейм данных на более мелкие части и повторить их?

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

Ответ №1:

Более простым способом было бы объединение, и карта -> слияние имеет indicator параметр>, чтобы определить, какие строки совпадают:

 (a.merge(b, indicator = True, how = 'left')['_merge']
  .map(lambda x: True if x == 'both' else False)
 )

0    False
1     True
2    False
3     True
Name: _merge, dtype: object
 

Это должно быть быстрее, чем итерация, которую вы используете в своей функции; для данных, которые не помещаются в память; Я мог бы подумать о mmap; однако я сам его не использовал, поэтому не могу дать вам никакой информации об этом. данные доступны, и даск может помочь.

Другой вариант-взять данные и сбросить их в sqlite; запустите там слияние.

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

1. отлично, спасибо за совет о слиянии. можете ли вы сказать больше об использовании панд с sqlite? как это решает проблему?

2. База данных оборудована для хранения больших данных; с помощью sqlite вы можете выполнить слияние, чтобы получить пересечение и вывести конечный результат bck в pandas, возвращаемые данные должны быть значительно меньше и помещаться в память. Sqlite прост в установке. Предположение здесь состоит в том, что вы знаете какой-то sql

3. хорошо, значит, для этого потребуется обработка данных с помощью внешних инструментов sql, а затем обработка в панд? Я знаю, что у панд есть интерфейсы sql; справились бы они с этим, не написав код где-нибудь еще?

4. Панды работают как инструмент в памяти. Да, вам придется написать sql. Однако есть писпарк и Даск; вы также можете исследовать их.