Как мне записать фрейм данных pandas в двоичный файл с определенным форматированием c для нескольких типов данных? - PullRequest
1 голос
/ 06 мая 2020

Я пытаюсь написать программу для преобразования файла CSV в очень конкретный c двоичный файл вывода. Он должен быть записан в формате big endian с различными типами данных, как целыми числами без знака, так и числами с плавающей запятой. Я успешно импортировал CSV в фрейм данных pandas.

Вот пример данных:

val1,val2,val3,val4
1234567890,10000,1,0.839792631

А вот код, который я использую:

import numpy as np
import pandas as pd

inputfilename = r"test_csv.csv"

df = pd.read_csv(inputfilename)

datatype = np.dtype([
    ('val1', '>u4'),
    ('val2', '>u2'),
    ('val3', 'u1'),
    ('val4', '>f4')])

data = df.to_numpy(dtype=datatype) 

outputfilename = r"output_py_1.dat"
fileobj = open(outputfilename, mode='wb')
data.tofile(fileobj)
fileobj.close()

Я написал код, чтобы сделать то же самое в Matlab и проверил в шестнадцатеричном редакторе. Правильный вывод:

49 96 02 D2 27 10 01 3F 56 FC A6 00

Однако Python выводит много посторонних байтов и повторяет некоторые байты, и я не понимаю, почему.

49 96 02 D2 02 D2 D2 4E 93 2C 06 00 00 27 10 27 10 10 46 1C 40 00 00 00 00 01 00 01 01 3F 80 00 00 00 00 00 00 00 00 00 3F 56 FC A6 F2

Есть ли способ, которым я может получить правильный результат?

Я также думаю, что проблема может иметь какое-то отношение к преобразованию в numpy, учитывая, что выходные данные для данных выглядят так с кучей дополнительных чисел (я не даже не знаю откуда они):

array([[(1234567890,   722, 210, 1.234568e+09),
    (     10000, 10000,  16, 1.000000e+04),
    (         1,     1,   1, 1.000000e+00),
    (         0,     0,   0, 8.397926e-01)]],
  dtype=[('val1', '>u4'), ('val2', '>u2'), ('val3', 'u1'), ('val4', '>f4')])

1 Ответ

0 голосов
/ 07 мая 2020

Оказывается, массивы numpy могут иметь только один тип данных, поэтому он пытался применить каждый тип данных к каждому значению - отсюда и массив 4x4 - когда я сделал .to_ numpy (datatype). Затем был записан этот массив 4x4, что привело к дополнительным байтам.

Поскольку pandas кадры данных в любом случае основаны на numpy массивах, кажется, что ответ - указать тип данных при чтении из CSV, а затем получить записи из фрейма данных и записать их в двоичный.

import numpy as np
import pandas as pd

inputfilename = r"test_csv.csv"

datatype = np.dtype([
    ('val1', '>u4'),
    ('val2', '>u2'),
    ('val3', 'u1'),
    ('val4', '>f4')])

df = pd.read_csv(inputfilename,dtype=datatype)

dataonly = df.to_records(index=False)

outputfilename = r"output_py_1.dat"
fileobj = open(outputfilename, mode='wb')
dataonly.tofile(fileobj)
fileobj.close()

Изменить: еще одно примечание - если данные не будут помечены как big endian:

import sys    
if (sys.byteorder == 'little'):
    dataonly = dataonly.byteswap()
...