#python #postgresql #numpy #psycopg2
#python #postgresql #numpy #psycopg2
Вопрос:
У меня есть массив numpy, который необходимо вставить в PostgreSQL. Массив numpy — это массив, содержащий подмассив, который уже находится в кортеже. Кортеж выглядит примерно так:
((1,0., -0.5, [0, 0], 1, 5)). — Я сократил массив, чтобы показать подмассив.
Кортеж содержит один элемент для вставки одной строки. Если бы я хотел вставить несколько строк, кортеж содержал бы несколько элементов.
Я зарегистрировал адаптеры PostgreSQL для numpy.uint32, numpy.float32 и numpy.ndarray.:
from psycopg2.extensions import register_adapter, AsIs
def numpy2pyUInt32(self,npUInt32):
return AsIs(npUInt32.item())
def numpy2pyFloat32(self,npFloat32):
return AsIs(npFloat32.item())
def numpy2pyndarray(self,npndarray):
return AsIs(npndarray.tolist())
register_adapter(numpy.uint32, self.numpy2pyUInt32)
register_adapter(numpy.float32, self.numpy2pyFloat32)
register_adapter(numpy.ndarray, self.numpy2pyndarray)
Чтобы вставить данные, я использую execute_values()
следующую команду sql:
INSERT INTO mytable VALUES %s
. Но когда я выполняю это, я получаю сообщение об ошибке от psycopg2 со словами:
Traceback (most recent call last):
File "...", line 132, in <module>
...
File "...", line 113, in ...
psycopg2.extras.execute_values (cur, sql_command, col_values)
File "/.../lib/python3.8/site-packages/psycopg2/extras.py", line 1292, in execute_values
cur.execute(b''.join(parts))
psycopg2.errors.SyntaxError: syntax error at or near "["
LINE 1: ...06346473842859,0.0,0.0,0.0,14.284889221191406,4,0,[0, 0],540...
^
Дополнительная информация:
data = ((1,0., -0.5, ..., [0, 0], 1, 5))
print(type(data)) # <class 'tuple'>
print(type(data[0])) # <class 'numpy.void'>
print(data[0].dtype) #
[('..', '<u4'), ('..', '<f4'), ('..', '<f4'), ('..', '<f4'), ('..', '<f4'),
('..', '<f4'), ('..', '<f4'), ('..', '<f4'), ('..', '<f8'), ('..', '<f4'),
('..', '<f4'), ('..', '<f4'), ('..', 'u1'), ('..', 'u1'),
('..', 'u1',(2,)), # sub-array
('..', '<u4'), ('..', '<u4'), ('..', '<u4'), ('..', '<u4'), ('..', '<u4'),
('..', '<u4')]
print (data[0].shape) # ()
print (type(data[0][0])) # <class 'numpy.uint32'>
...
print (type(data[0][14])) # <class 'numpy.ndarray'>
Комментарии:
1. Отправьте полную трассировку обратно. Сейчас похоже, что ошибка в вашей
AsIs
функции2. (примечание, это список в вашем кортеже. не массив numpy)
3. @PaulH функция AsIs из
psycopg2
:from psycopg2.extensions import register_adapter, AsIs
4. @PaulH Я получил массив numpy из файла HDF5, используя h5py. Я открыл dataset (ds) и вызвал
tuple(ds[0:1])
5. просто чтобы уточнить, что говорил Пол: кортеж, содержащий массив numpy, будет выглядеть следующим образом:
(1,0., -0.5, array([0, 0]), 1, 5)
but((1,0., -0.5, [0, 0], 1, 5))
является кортежем кортежа, содержащего список . это может быть просто обозначение, которое вы написали для представления примера. распечатайте его и, возможно, запроситеtype(list_or_array_element)
Ответ №1:
Определите dtype:
In [16]: dt=np.dtype([('x','f'),('y','i',2)])
и структурированный массив:
In [17]: arr = np.zeros(3,dt)
In [18]: arr
Out[18]:
array([(0., [0, 0]), (0., [0, 0]), (0., [0, 0])],
dtype=[('x', '<f4'), ('y', '<i4', (2,))])
Просмотр одной записи:
In [19]: arr[0]
Out[19]: (0., [0, 0])
перенос этого в кортеж не преобразует этот внутренний массив:
In [20]: tuple(arr[0])
Out[20]: (0.0, array([0, 0], dtype=int32))
In [21]: print(tuple(arr[0]))
(0.0, array([0, 0], dtype=int32))
In [22]: arr[0].tolist()
Out[22]: (0.0, array([0, 0], dtype=int32))
Сосредоточение внимания на этом одном поле:
In [23]: arr['y']
Out[23]:
array([[0, 0],
[0, 0],
[0, 0]], dtype=int32)
In [24]: arr['y'][0]
Out[24]: array([0, 0], dtype=int32)
In [25]: arr['y'].tolist()
Out[25]: [[0, 0], [0, 0], [0, 0]]
Индексирование массива с использованием списка имен полей за вычетом проблемного:
In [26]: arr[['x']]
Out[26]:
array([(0.,), (0.,), (0.,)],
dtype={'names':['x'], 'formats':['<f4'], 'offsets':[0], 'itemsize':12})
In [27]: tuple(arr[['x']][0])
Out[27]: (0.0,)
In [29]: arr[['x']].tolist()
Out[29]: [(0.0,), (0.0,), (0.0,)]
Комментарии:
1. Я вызвал
.tolist()
метод в своем адаптере для PostgreSQL, как указано в коде в вопросе, но, похоже, psycopg2 неправильно его обработал?2. Обратите
OUT[22]
внимание, чтоtolist
он не касается этого внутреннего массива.3. Я смотрел на out
OUT[25]
. Адаптер, зарегистрированный в PostgreSQL, предназначен для типаnumpy.ndarray
. И я помещаю оператор печати в зарегистрированный мной адаптер, и он вызывается с правильными[0, 0]
данными, которые совпадают с данными, на которые указывает сообщение об ошибке PostgreSQL.