Самый быстрый способ загрузки числовых данных в массив python / pandas / numpy из MySQL

Я хочу прочитать некоторые числовые (double, ie float64) данные из таблицы MySQL. Размер данных составляет ~ 200 тыс. Строк.

Ссылка MATLAB:

tic; feature accel off; conn = database(...); c=fetch(exec(conn,'select x,y from TABLENAME')); cell2mat(c.data); toc 

Истекшее время составляет ~ 1 секунду.

Выполняя то же самое в python, используя несколько примеров, найденных здесь (я пробовал их все, то есть используя pandas read_frame, frame_query и функцию __processCursor): Как преобразовать результат SQL Query в структуру данных PANDAS?

Справочный код python:

 import pyodbc import pandas.io.sql as psql import pandas connection_info = "DRIVER={MySQL ODBC 3.51 \ Driver};SERVER=;DATABASE=;USER=;PASSWORD=;OPTION=3;" cnxn = pyodbc.connect(connection_info) cursor = cnxn.cursor() sql = "select x,y from TABLENAME" #cursor.execute(sql) #dataframe = __processCursor(cursor, dataframe=True) #df = psql.frame_query(sql, cnxn, coerce_float=False) df = psql.read_frame(sql, cnxn) cnxn.close() 

Берет ~ 6 секунд. Профилер говорит, что все время проведенное было в read_frame. Мне было интересно, может ли кто-нибудь дать мне несколько советов, как можно ускорить, по крайней мере, совпадение с кодом MATLAB. А если это вообще возможно в питоне.

РЕДАКТИРОВАТЬ:

Узкое место, кажется, находится внутри курсора.execute (в библиотеке pymysql) или cursor.fetchall () в библиотеке pyobbc. Самая медленная часть – это чтение возвращаемого элемента данных MySQL по элементу (строка за строкой, по столбцу) и преобразование его в тип данных, который он ранее вывел той же библиотекой.

До сих пор мне удалось ускорить это, чтобы приблизиться к MATLAB, сделав это действительно грязное решение:

 import pymysql import numpy conn = pymysql.connect(host='', port=, user='', passwd='', db='') cursor = conn.cursor() cursor.execute("select x,y from TABLENAME") rez = cursor.fetchall() resarray = numpy.array(map(float,rez)) finalres = resarray.reshape((resarray.size/2,2)) 

Вышеупомянутый cur.execute НЕ ПЫТЫШКЛ ВЫПОЛНИТЬ! Я изменил его внутри файла «connections.py». Во-первых, функция def _read_rowdata_packet теперь имеет вместо:

 rows.append(self._read_row_from_packet(packet)) 

замещенный

 self._read_string_from_packet(rows,packet) 

Здесь _read_string_from_packet является упрощенной версией _read_row_from_packet с кодом:

 def _read_string_from_packet(self, rows, packet): for field in self.fields: data = packet.read_length_coded_string() rows.append(data) 

Это грязное решение, которое дает ускорение с 6 секунд до 2,5 секунд. Мне было интересно, если бы все это можно было бы избежать, используя другую библиотеку / передав некоторые параметры?

Следовательно, решение будет состоять в том, чтобы перечитать весь ответ MySQL на список строк, а затем преобразовать объемный тип в числовые типы данных вместо того, чтобы делать это поэтапно. Что-то вроде этого уже существует в python?

2 Solutions collect form web for “Самый быстрый способ загрузки числовых данных в массив python / pandas / numpy из MySQL”

«Проблема», по-видимому, была преобразованием типа, которое происходит от десятичного типа MySQL до десятичного десятичного числа. Decimal, что MySQLdb, pymysql и pyodbc делает на данных. Изменив файл converters.py (в последних строках) в MySQLdb, получим:

 conversions[FIELD_TYPE.DECIMAL] = float conversions[FIELD_TYPE.NEWDECIMAL] = float 

вместо decimal.Decimal, кажется, полностью решает проблему и теперь следующий код:

 import MySQLdb import numpy import time t = time.time() conn = MySQLdb.connect(host='',...) curs = conn.cursor() curs.execute("select x,y from TABLENAME") data = numpy.array(curs.fetchall(),dtype=float) print(time.time()-t) 

Работает менее чем за секунду! Что смешно, decimal.Decimal никогда не было проблемой в профилировщике.

Подобное решение должно работать в пакете pymysql. pyodbc более сложный: все написано на C ++, поэтому вам придется перекомпилировать весь пакет.

ОБНОВИТЬ

Вот решение, не требующее изменения исходного кода MySQLdb: Python MySQLdb возвращает datetime.date и decimal Решение затем для загрузки числовых данных в pandas:

 import MySQLdb import pandas.io.sql as psql from MySQLdb.converters import conversions from MySQLdb.constants import FIELD_TYPE conversions[FIELD_TYPE.DECIMAL] = float conversions[FIELD_TYPE.NEWDECIMAL] = float conn = MySQLdb.connect(host='',user='',passwd='',db='') sql = "select * from NUMERICTABLE" df = psql.read_frame(sql, conn) 

Бит MATLAB в 4 раза при загрузке стола 200k x 9!

Также проверьте этот способ выполнения вещей с помощью пакета turbobbc . Чтобы преобразовать ваш результирующий набор в массивы OrderedDict из NumPy, просто выполните следующее:

 import turbodbc connection = turbodbc.connect(dsn="My data source name") cursor = connection.cursor() cursor.execute("SELECT 42") results = cursor.fetchallnumpy() 

Преобразование этих результатов в набор данных должно потребовать несколько дополнительных миллисекунд. Я не знаю ускорение для MySQL, но я видел фактор 10 для других баз данных.

Ускорение в основном достигается за счет использования массовых операций, а не операций по строке.

  • Могу ли я экспортировать фрейм данных Pandon Pandas в MS SQL?
  • создать новый столбец в области данных с помощью fuzzywuzzy
  • Запустите nltk sent_tokenize через рамку данных Pandas
  • лучший способ бросить нанки ряды в пандах
  • Как проверить, пустует ли серия pandas?
  • Получить количество значений по столбцам - Pandas DataFrame
  • Использовать Scikit. Учиться выполнять линейную регрессию в рамке данных панд-кадров временного ряда.
  • NaNs после слияния двух фреймов данных
  • Python - лучший язык программирования в мире.