Оптимизированные операции ввода-вывода в Python |

Хаки ввода-вывода для ускорения аналитики с использованием стека обработки данных Python

При работе с приложениями, интенсивно использующими данные, я часто сталкиваюсь с проблемами ввода-вывода (I/O), которые являются узким местом для каждого приложения, критичного к производительности. С увеличением объема хранимых данных возникает необходимость хранения данных на дисках, чтобы компенсировать нехватку оперативной памяти путем загрузки данных с диска в оперативную память и наоборот. Таким образом, операции ввода-вывода являются очень важными задачами, когда речь идет об обработке финансовых данных или любых научных данных.

В этом посте я пытаюсь пролить свет на несколько библиотек и их хитрости. Python имеет встроенные возможности, которые можно использовать для хранения объекта на диске и для его чтения с диска в ОЗУ. Кроме того, Python хорошо справляется с обработкой текстовых файлов и баз данных SQL. Библиотека Pandas предоставляет множество классов и методов для чтения и записи файлов в широком диапазоне форматов.

Здесь мы собираемся изучить следующие области методов хранения и извлечения данных:

  1. Сериализованное хранилище с использованием модуля Pickle
  2. Операции ввода/вывода с текстовыми данными
  3. Базы данных SQL
  4. Ввод-вывод с PyTables

При оптимизации операций ввода-вывода в языке Python учитываются два основных фактора: эффективность (производительность) и гибкость. Давайте погрузимся прямо в него:

Сериализованное хранилище с использованием модуля Pickle

В языке Python есть множество модулей, которые можно легко использовать в условиях крупномасштабного развертывания.

Использование модуля pickle для чтения и записи файлов

Вам необходимо хранить данные на диске, чтобы делиться ими, документировать или использовать их позже. У нас есть модуль pickle, который сериализует объект Python, чтобы быстро выполнять операции чтения и записи.

# On running the above code snippet, you'll see:

CPU times: user 40.9 ms, sys: 14 ms, total: 54.9 ms
Wall time: 54.5 ms

Случайные числа с плавающей запятой создают файл размером 9 МБ, который сериализуется в поток байтов и записывается на диск за 54,9 мс. Вы будете использовать свалка а также нагрузка функция модуля pickle для записи и чтения файла соответственно. Чтобы утвердить сериализованные и десериализованные данные, вы можете использовать Numpy’s всезакрыть метод. Вот как вы можете это сделать:

np.allclose(np.array(a1), np.array(a2))

# here a2 is the deserialized object after reading the same file
# using the load function.

Таким образом, модуль pickle сохраняет список python, dict и т. д. после преобразования их в поток символов на диске. Суть здесь в том, что этот поток байтов содержит информацию, необходимую для восстановления объекта в другом скрипте Python.

Операции ввода/вывода с текстовыми данными

Python был популярным языком, особенно при работе с текстовыми файлами из-за надежности и простоты обработки текстовых данных. Существует несколько вариантов работы со строковыми объектами и с текстовыми файлами в целом.

Чтобы написать CSV (значения, разделенные запятыми), мы можем использовать методы записи и чтения:

csv_file.write(header)

# time is time array and data is the dummy numpy array
for time, (a, b, c, d, e) in zip(time, data): 
  s="%s,%f,%f,%f,%f,%f\n" % (time, a, b, c, d, e) csv_file.write(s)

csv_file.close()

# to read the file, we can use readlines function
content = csv_file.readlines()

Хотя python предоставляет методы для обработки текстовых файлов, у нас есть библиотека pandas, которая может читать и записывать различные форматы данных, и она намного лучше и проще в использовании.

Будь то CSV (значения, разделенные запятыми), SQL (язык структурированных запросов), XLS/XLSX (файлы Microsoft Excel), JSON (нотация объектов JavaScript) или HTML (язык гипертекстовой разметки).

Pandas делает весь процесс чтения и записи файлов CSV более удобным, лаконичным и быстрым.

%time data.to_csv(filename + '.csv')

# CPU times: user 5.59 s, sys: 137 ms, total: 5.69 s

# And to read the files back from the disk

pd.read_csv(<path to the CSV file>)

Базы данных SQL

Python поставляется с поддержкой базы данных SQL, которая называется SQLite3. Мы можем работать практически с любой базой данных (SQL или NoSQL) с помощью Python.

SQL-запросы записываются в виде строковых объектов, где синтаксис и типы данных зависят от используемой базы данных. Иллюстрация создания таблицы Todo с помощью python в базе данных SQLite:

import sqlite3 as sq

# query string to create the table

query = 'CREATE TABLE TODO_NUMBER (Num1 real, Num2 real, Num3 real)'
con = sq.connect(path + 'todo.db')
con.execute(query)
con.commit()

Попробуем вставить некоторые данные в созданную базу данных,

data = np.random.standard_normal((1000000, 3))
%%time
con.executemany('INSERT INTO TODO_NUMBER VALUES (?, ?, ?, ?, ?)', data)
con.commit()

# Time taken: CPU times: user 10.3 s, sys: 316 ms, total: 10.6 s
Wall time: 11 s

Запись 1 миллиона строк в базу данных — немного тяжелая и трудоемкая задача. Чтение базы данных происходит намного быстрее:

con.execute('SELECT * FROM TODO_NUMBER').fetchall()

Если вы имеете дело с большим количеством чисел и массивов в своей базе данных, вы можете использовать массивы Numpy для чтения данных непосредственно в numpy ndarray.

np_query = 'SELECT * FROM TODO_NUMBER WHERE Num1 > 0 AND Num2 < 0'
res = np.array(con.execute(np_query).fetchall()).round(3)

Это очень хороший прием для чтения и построения результатов запроса без лишней суеты. Чтобы сделать чтение более эффективным и оптимизированным, мы должны читать целые таблицы и запрашивать результаты с помощью pandas. Аналитика и обработка становятся намного быстрее, когда вся таблица загружается в память. Это достигается с помощью подбиблиотеки pandas.io.sql

import pandas.io.sql as pds
data_df = pds.read_sql('SELECT * FROM TODO_NUMBERS', con)

Теперь таблица загружается в память, что позволяет выполнять обработку намного быстрее. SQL-запрос, который занимает несколько секунд с SQLite3, завершается за миллисекунды с pandas в памяти:

%time data_df[(data_df['Num1'] > 0) & (data_df['Num2'] < 0)].head()

# CPU times: user 50 ms, sys: 0 ns, total: 50 ms

# Wall time: 49.9 ms

Мы можем справиться с гораздо более сложными запросами с пандами, которые дадут результат намного быстрее, чем SQL, но не могут заменить SQL. Учитывая, что pandas может реплицировать SQL-запрос, мы можем значительно ускорить аналитику, используя обработку в памяти pandas.

Здесь следует отметить, что панды не были созданы для замены базы данных SQL и не могут сделать то же самое в данный момент. Pandas не поддерживает реляционные структуры данных.

Ввод-вывод с PyTables

PyTables — это привязка Python к стандарту базы данных/файла HDF5. Он специально спроектирован и разработан для повышения производительности операций ввода-вывода и максимально эффективного использования доступного оборудования. Он очень хорошо ускоряет аналитику и быстрее генерирует результаты. База данных PyTables может содержать множество таблиц и поддерживает сжатие и индексирование, а также нетривиальные запросы к таблицам.

PyTables имеет файловый формат базы данных. Пройдемся по работе столов,

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

Но опять же, у нас есть еще один оптимизированный и Pythonic способ добиться того же результата, используя структурированные массивы NumPy:

dty = np.dtype([('Num1', 'i4'), ('Num2', '<i4')])

sarray = np.zeros(len(ran_int), dtype=dty)

Теперь, когда у нас есть полные данные в нашей таблице, все сводится к созданию таблицы следующим образом:

%%time
h5.create_table('/', 'ints_from_array', sarray,

title="Integers", expectedrows=rows, filters=filters)

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

h5.remove_node(‘/’, ‘ints_from_array’)

И pandas, и PyTables имеют возможность обрабатывать сложные SQL-подобные запросы, индексировать и выбирать. Они спроектированы и оптимизированы по скорости операций ввода-вывода.

Основным преимуществом использования PyTables является его способ сжатия. Он использует сжатие не только для экономии места на диске, но и для повышения производительности операций ввода-вывода.

Выводы

Многие области приложений корпоративного уровня в области финансов или науки в целом могут быть успешными только с помощью моделирования данных на основе массивов. В большинстве этих случаев заметные улучшения производительности могут быть достигнуты с помощью комбинации возможностей ввода-вывода NumPy и PyTables. Магазины на основе HDF5 оказались отличительным дополнением ко всем подходам.

У реляционных баз данных есть свои плюсы, если у вас есть сложные структуры данных, которые демонстрируют ряд отношений между отдельными объектами/таблицами. Это может оказаться оправданным в определенных обстоятельствах, когда существует недостаток производительности по сравнению с чистыми подходами на основе NumPy ndarray или pandas на основе DataFrame.

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *