Чтение/запись фрейма данных Polars со столбцом списка из/в базу данных

Написание df с таким столбцом списка

df = pl.DataFrame({'a': [1,2,3], 'b':[['A','B'], ['C', 'D'], ['E', 'F']]})
df.write_database(
    "test", "sqlite:///test.db",
    if_table_exists = "replace",
)

работает нормально, но потом работает

pl.read_database_uri(query = "SELECT * FROM test", uri = "sqlite://test.db")

выдает ошибку

RuntimeError: Invalid column type Blob at index: 1, name: b

Кажется, я не могу обойти это, используя engine_options в write_database, чтобы указать, что мне нужно поле списка (а не большой двоичный объект), или используя schema_overrides в read_database_uri. Каков правильный способ записи/чтения такого типа фрейма данных со столбцами списка?

Не могли бы вы запустить DESCRIBE test и распечатать информацию о таблице? Я считаю, что столбец b должен быть BLOB. Это ожидаемо, поскольку SQLite не может хранить массивы (не может их сериализовать). Таким образом, проблема в том, почему вы не можете прочитать объект из «b».

Johnny Cheesecutter 31.07.2024 17:55
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
1
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я считаю, что в вашем случае вам нужно будет сохранить список строк как BLOB в MySQL lite, а затем каким-то образом декодировать байты обратно в список. Однако есть две проблемы:

  1. Стандартный протокол Polars connectorx не может читать столбцы BLOB, поэтому вам нужно переключиться на adbc
  2. Даже после перехода на adbc непонятно, как преобразовать BLOB обратно в байты.

Таким образом, я бы предложил объединить список строк с любым разделителем и сохранить строки как VARCHAR, а затем преобразовать обратно:

import polars as pl

SEP = "\t"

df = pl.DataFrame({'a': [1,2,3], 'b':[['A','B'], ['C', 'D'], ['E', 'F']]})

# mapping: List[str] -> str
df = df.with_columns(b = pl.col('b').list.join(SEP))
df.write_database(
    "test", "sqlite:///test.db",
    if_table_exists = "replace",
)

ff = pl.read_database_uri(query = "SELECT a,b FROM test", 
                          uri = "sqlite://test.db",
                              )

# mapping: str -> List[str]
ff = ff.with_columns(pl.col('b').str.split(SEP))

Альтернативно:
Или сериализуйте столбец в json и снова сохраните его в базе данных как VARCHAR, а затем десериализуйте обратно.

import json
import polars as pl

df = pl.DataFrame({'a': [1,2,3], 'b':[['A','B'], ['C', 'D'], ['E', 'F']]})

# dump to json
f = lambda x: json.dumps(list(x))
df = df.with_columns(b = pl.col('b').apply(f))


df.write_database(
    "test", "sqlite:///test.db",
    if_table_exists = "replace",
)

ff = pl.read_database_uri(query = "SELECT a,b FROM test", 
                          uri = "sqlite://test.db",
                              )


ff = ff.with_columns(pl.col('b').str.json_decode())

Альтернатива 2:
Подготовьте столбец, преобразовав его в двоичный объект, прежде чем сохранять его в базе данных sql. Столбец будет сохранен как BLOB.

import pickle 
import polars as pl

df = pl.DataFrame({'a': [1,2,3], 'b':[['A','B'], ['C', 'D'], ['E', 'F']]})

# dump column to binary object
df = df.with_columns(b = pl.col('b').apply(pickle.dumps))


df.write_database(
    "test", "sqlite:///test.db",
    if_table_exists = "replace",
)

ff = pl.read_database_uri(query = "SELECT a,b FROM test", 
                          uri = "sqlite://test.db",
                          engine='adbc', # need to use adbc engine instead of standard
                              )
ff = ff.with_columns(pl.col('b').apply(pickle.loads))

Другие вопросы по теме