Чтение / запись CSV Array of Dicts, содержащий список произвольной длины - PullRequest
0 голосов
/ 06 ноября 2018

В настоящее время я пишу массив словарей, как показано ниже, в файл CSV:

tmp_res = [{"val1": 1.0, "val2": 2, "ar_1": [[65.41156005859375, 53.709598541259766], [251.97698974609375, 153.14926147460938]] },....]

ar1 представляет *ndarray* произвольной длины [-1,2], а -1 не является постоянной величиной в Dicts.

После прочтения я получаю единичные значения val1 и val2, как предполагается, однако массив не легко читается.

"[[65.41156005859375, 53.709598541259766], [251.97698974609375, 153.14926147460938]]"

Я знаю, что мог бы обработать эту строку и отделить ее некоторыми символами. Однако кажется, что для решения этой проблемы должно быть лучшее и более элегантное решение.

Каков наилучший способ сохранить такие данные в файл и восстановить его?

EDIT: Чтобы уточнить мое сохранение и чтение файла. Я сохраняю свой файл через csv.DictWriter следующим образом:


# Exemplary Data:
results = [{'mean_iou': 0.3319194248978337, 'num_boxes': 1, 'centroids': [[101.21826171875, 72.79462432861328]]}, {'mean_iou': 0.4617333142965009, 'num_boxes': 2, 'centroids': [[65.41156005859375, 53.709598541259766], [251.97698974609375, 153.14926147460938]]}, {'mean_iou': 0.537150158582514, 'num_boxes': 3, 'centroids': [[50.82071304321289, 42.616580963134766], [304.91583251953125, 176.09994506835938], [140.43699645996094, 104.00206756591797]]}]

# The given results data is basically tmp_res after the for loop.
tmp_res = []
for i in range(0, len(results):
    res_dict = {}
    res_dict["centroids"] = results[i]["centroids"]
    res_dict["mean_iou"] = results[i]["mean_iou"]
    res_dict["num_boxes"] = results[i]["num_boxes"]
    tmp_res.append(res_dict)

# Writing to File
keys = tmp_res[0].keys()
with open('anchor.csv','w+') as output_file:
    dict_writer = csv.DictWriter(output_file, keys)
    dict_writer.writeheader()
    dict_writer.writerows(tmp_res)

# Reading from File

  num_centroids = []
  mean_ious = []
  centroids = []
  reader = csv.DictReader(csvfile,
                          fieldnames=["mean_iou",
                                      "num_boxes",
                                      "centroids"])
        # Skipping line of the header
        next(reader, None)
        for row in reader:
            centroids.append(row["centroids"])
            num_centroids.append(row["num_boxes"])
            mean_ious.append(row["mean_iou"])

Выдержка из файла выглядит следующим образом:

mean_iou,num_boxes,centroids

0.3319194248978337,1,"[[101.21826171875, 72.79462432861328]]"

0.4617333142965009,2,"[[65.41156005859375, 53.709598541259766], [251.97698974609375, 153.14926147460938]]"

0.537150158582514,3,"[[50.82071304321289, 42.616580963134766],  [304.91583251953125, 176.09994506835938], [140.43699645996094, 104.00206756591797]]"

0.5602804262309611,4,"[[49.9361572265625, 41.09553146362305], [306.10711669921875, 177.09762573242188], [88.86656188964844, 167.8087921142578], [151.82627868652344, 81.80717468261719]]"

Я подозреваю, что csv.DictWriter не знает, как обрабатывать массив из нескольких значений, поскольку он содержит запятую , которая нарушает формат значений, разделенных запятыми. Поэтому он оборачивает данные в строку, чтобы избежать конфликта в структуре.


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

Однако я подумал, что csv.dictWriter сможет справиться с каким-то видом развёртывания своих собственных данных «в строку».

Также извините за задержку.


Решение: Решение от Сержа, примененное в коде:

#Added Json
import json
# Reading from File

num_centroids = []
mean_ious = []
centroids = []
reader = csv.DictReader(csvfile,fieldnames=["mean_iou",
                                            "num_boxes",
                                            "centroids"])

# Skipping line of the header
next(reader, None)
for row in reader:
    centroids.append(json.loads(row["centroids"]))
    num_centroids.append(row["num_boxes"])
    mean_ious.append(row["mean_iou"])

1 Ответ

0 голосов
/ 06 ноября 2018

Ваш файл не в формате CSV, это просто словарь Python. Просто прочитайте файл в строку и используйте оператор eval (опасно, но легко) или напишите собственный анализатор, скажем, разбейте строку на массив, удалите запятые и скобки, примените np.fromstring, затем измените форму.

Любопытно "[[65.41156005859375, 53.709598541259766], ..." похоже на действительный JSON, так np.array( json.loads ( "[[65.41156005859375, 53.709598541259766], [251.97698974609375, 153.14926147460938]]" )) должно привести к ndarray. Имейте в виду, что tmp_res = не является действительным JSON, поэтому json.load('myfile') не удастся

PS. CSV предназначен только для табличных данных, а не для многомерных данных. Если вам нужно, вы можете сделать двойной CSV со стандартным CSV и разделить

s = "[[76 ... "
lines = s.split(']], [[')

reader = csv.reader(lines, delimiter=', ')

or use panda from_csv you can define ]], [[ as lineseparator in C mode.

Полагаю, лучшим решением будет сохранение данных в допустимом формате json (без каких-либо назначений). Или вы можете попробовать использовать обозначенный numpy.save numpy.load для хранения двоичных данных для большей масштабируемости.

Для других жизнеспособных альтернатив читайте

Как я могу сериализовать массив numpy при сохранении размеров матрицы?

PS. CSV предназначен для использования в табличных данных, а не в произвольных многомерных данных, так что это просто плохой выбор. Тем не менее, если вам нужно, вы можете использовать двойной CSV-ридер, хотя это выглядит некрасиво

text = "[[6... 
lines = text.split("]], [[")
reader2 = csv.reader(lines, delimiter=', ')
...

или вы можете повозиться с pandas csv reader, у него даже есть собственный разделитель строк. Возможно, некоторые более мощные библиотеки CSV будут работать лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...