Python: запись списка целых чисел в файл .csv и чтение обратно в тот же формат

У меня типичная путаница в синтаксисе копирования и вставки, вероятно, потому, что я действительно не понимаю, что делаю!

Я пытаюсь сохранить ряд координат facemark_landmark, взятых из библиотеки mediapipe. Я перебираю кадры фильма, и каждый кадр дает мне 468 целочисленных пар, экранных координат каждого ориентира.

В каждом кадре я добавляю список координат в список с именем Stored_Data.

stored_data.append(landmark_coords)

Когда фильм закончен, я записываю данные в файл:

with open("out.csv", "w") as f:
        wr = csv.writer(f)
        wr.writerows(stored_data)

Кажется, это работает нормально, и мой CSV-файл выглядит так: (181, 95), (170, 87), ..... 468 пар в каждой строке, по одной строке на каждый кадр фильма.

Но я запутался, пытаясь преобразовать файл csv обратно в правильный формат.

Мои текущие усилия:

stored_data = []

with open("out.csv", "r") as f:
        rr = csv.reader(f)   
        for row in rr:
            frland=[]
            for l in row:
                coords = [map(float,l.split(',')) for i in l]
                frland.append(coords)
            stored_data.append(frland)

Я получаю сообщение об ошибке: ValueError: установка элемента массива с помощью последовательности. Запрошенный массив имеет неоднородную форму после 1 измерения. Обнаруженная форма была (468,) + неоднородная часть.

Может ли кто-нибудь дать мне руку?

Есть ли причина, по которой вы хотите, чтобы файл был удобочитаемым CSV? Если вы просто ищете очень простое сохранение объектов Python, то это именно то, для чего предназначен pickle? :)

Ari Cooper-Davis 16.03.2022 15:45

Спасибо, это, безусловно, намного лучше подходит для моей проблемы.

user1714819 16.03.2022 19:43
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
41
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

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

И поскольку вам нужно декодировать, это хороший показатель того, что что-то другое может быть лучше, чем CSV. Если вам просто нужно сохранить результаты mediapipe между процессами, я повторю то, что Ари сказал в комментариях, используйте pickle: он там для хранения сложных типов, поэтому вам не нужно думать о кодировании и декодировании и сделать его таким простым, как «сохранить, затем откройте":

import pickle

orig_stored_data = [[(181, 95), (170, 87)], [(20, 40), (30, 50)]]

f_pickle = open("stored_data.pkl", "wb")
pickle.dump(orig_stored_data, f_pickle)

f_pickle = open("stored_data.pkl", "rb")
new_stored_data = pickle.load(f_pickle)

assert new_stored_data == orig_stored_data

Если вам нужно использовать CSV, вам нужно правильно интерпретировать кортежи в каждом столбце. Я думаю, что это неполный:

coords = [map(float,l.split(',')) for i in l]

поскольку вы не удаляете скобки перед разделением запятой.

Более простой подход — использовать функцию literal_eval() в модуле ast:

import ast, csv, io, pprint

f_in = io.StringIO('"(181, 95)","(170, 87)"\n"(  20,   40)","(30,50)"')

stored_data = []

reader = csv.reader(f_in)
for row in reader:
    frland = []
    for col in row:
        coords = ast.literal_eval(col)
        frland.append(coords)
    stored_data.append(frland)

и stored_data выглядит так:

[[(181, 95), (170, 87)],
 [(20, 40), (30, 50)]]

Да, я думаю, что Ари был прав, на этот раз рассол выручит меня из рассолов! Мне не нужно увязнуть в ненужном преобразовании в формат csv и из него. Спасибо за ваш подробный ответ.

user1714819 16.03.2022 19:45

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