Запись фрейма данных в CSV, где списки преобразуются в массивы JSON
Как будет выводиться список строк в виде массива JSON при записи кадра данных в CSV?
Например ['foo', 'bar']
должно быть ["foo", "bar"]
Фон
Я копирую данные из базы данных PostgreSQL в AWS RDS в AWS Redshift. В качестве промежуточного шага данные должны быть загружены в AWS S3 в файлах CSV.
Но Redshift не поддерживает массивы как тип данных. Массивы необходимо преобразовать в varchar, представляющий массив JSON.
Например, столбец типа character varying(255)[]
на RDS потребуется столбец типа character varying(MAX)
на Redshift и использовать функции JSON для взаимодействия с данными.
Если данные не загружаются в Redshift как массив JSON, они не будут действительными.
json_arrays | is_valid_json_array
------------------------------+---------------------
[] | T
["a","b"] | T
["a",["b",1,["c",2,3,null]]] | T
{"a":1} | F
a | F
{foo, bar} | F
{"one", "two"} | F
[x,y,z] | F
[1,2,] | F
['x','y','z'] | F
Сложность в том, что Python представляет строки внутри одинарных кавычек, поэтому при записи списка строк в CSV этот список будет использовать одинарные кавычки, которые не являются допустимым массивом JSON.
Неудачным подходом было преобразование массива при чтении CSV.
def convert_pg_array_to_json_array(a):
"""
Converts a PG array such as '{foo,bar}' to '["foo", "bar"]'
"""
return json.dumps(a[1:-1].split(','))
# The arrays to convert are in column 20
df = pandas.read_csv(path, converters={20: convert_pg_array_to_json_array})
# Array gets output as "[""foo"", ""bar""]" which is not a valid JSON array
# Desired output is ["foo", "bar"]
df.to_csv(path)
1 ответ
Объедините подход в вопросе с этими изменениями при написании CSV:
Настроить escape-символ (как правило, обратную косую черту \
) и отключить двойные кавычки.
df.to_csv(path, escapechar="\\", doublequote=False)
Строка в CSV будет выглядеть [\"foo\", \"bar\"]
который является допустимым JSON, если вы загружаете данные с экранированием от обратной косой черты. Для красного смещения COPY FROM
вам нужно будет добавить ESCAPE
вариант к запросу.