Чтение десятичного представления с плавающей запятой из CSV с pandas - PullRequest
2 голосов
/ 01 августа 2020

Я пытаюсь прочитать содержимое CSV-файла, содержащего, как мне кажется, числа с плавающей запятой одинарной точности IEEE 754 в десятичном формате.

По умолчанию они читаются как int64. Если я укажу тип данных с чем-то вроде dtype = {'col1' : np.float32}, dtype будет правильно отображаться как float32, но это будут те же значения, что и float, а не int, ie. 1079762502 становится 1.079763e+09 вместо 3.435441493988037.

Мне удалось выполнить преобразование отдельных значений одним из следующих способов:

from struct import unpack

v = 1079762502

print(unpack('>f', v.to_bytes(4, byteorder="big")))
print(unpack('>f', bytes.fromhex(str(hex(v)).split('0x')[1])))

Что дает

(3.435441493988037,)
(3.435441493988037,)

Однако я не могу реализовать это векторизованным способом с помощью pandas:

import pandas as pd
from struct import unpack

df = pd.read_csv('experiments/test.csv')

print(df.dtypes)
print(df)

df['col1'] = unpack('>f', df['col1'].to_bytes(4, byteorder="big"))
#df['col1'] = unpack('>f', bytes.fromhex(str(hex(df['col1'])).split('0x')[1]))

print(df)

Выдает следующую ошибку

col1    int64
dtype: object
         col1
0  1079762502
1  1079345162
2  1078565306
3  1078738012
4  1078635652

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-c06d0986cc96> in <module>
      7 print(df)
      8 
----> 9 df['col1'] = unpack('>f', df['col1'].to_bytes(4, byteorder="big"))
     10 #df['col1'] = unpack('>f', bytes.fromhex(str(hex(df['col1'])).split('0x')[1]))
     11 

~/anaconda3/envs/test/lib/python3.7/site-packages/pandas/core/generic.py in __getattr__(self, name)
   5177             if self._info_axis._can_hold_identifiers_and_holds_name(name):
   5178                 return self[name]
-> 5179             return object.__getattribute__(self, name)
   5180 
   5181     def __setattr__(self, name, value):

AttributeError: 'Series' object has no attribute 'to_bytes'

Или, если я попробую второй способ, TypeError: 'Series' object cannot be interpreted as an integer

Я нахожусь в пределах моих Python знаний здесь, я полагаю, я мог бы перебирать каждую отдельную строку, преобразовывать в шестнадцатеричный, затем в строку, затем удалять 0x, распаковывать и хранить. Но это кажется очень запутанным и уже занимает несколько секунд для небольших наборов данных, не говоря уже о сотнях тысяч записей. Мне здесь не хватает чего-то простого, есть ли лучший способ сделать это?

1 Ответ

2 голосов
/ 01 августа 2020

CSV - это текстовый формат, числа с плавающей запятой одинарной точности IEEE 754 - это двоичный формат c. Если у вас есть CSV, у вас есть текст, это совсем не тот формат. Если я вас правильно понял, я думаю, вы имеете в виду, что у вас есть текст, который представляет собой целые числа (в десятичном формате), который соответствует 32-битной целочисленной интерпретации ваших 32-битных чисел с плавающей запятой.

Итак, для начала, когда вы читаете данные из a csv, pandas по умолчанию использует 64-битные целые числа. Поэтому преобразуйте в 32-битные целые числа, а затем повторно интерпретируйте байты, используя .view:

In [8]: df
Out[8]:
         col1
0  1079762502
1  1079345162
2  1078565306
3  1078738012
4  1078635652

In [9]: df.col1.astype(np.int32).view('f')
Out[9]:
0    3.435441
1    3.335940
2    3.150008
3    3.191184
4    3.166780
Name: col1, dtype: float32

Разложено на шаги, чтобы помочь понять:

In [10]: import numpy as np

In [11]: arr = df.col1.values

In [12]: arr
Out[12]: array([1079762502, 1079345162, 1078565306, 1078738012, 1078635652])

In [13]: arr.dtype
Out[13]: dtype('int64')

In [14]: arr_32 = arr.astype(np.int32)

In [15]: arr_32
Out[15]:
array([1079762502, 1079345162, 1078565306, 1078738012, 1078635652],
      dtype=int32)

In [16]: arr_32.view('f')
Out[16]:
array([3.4354415, 3.33594  , 3.1500077, 3.191184 , 3.1667795],
      dtype=float32)
...