Pandas.read_csv изменяет значения при импорте

У меня есть файл csv, который выглядит так:

"3040",0.24948,-0.89496
"3041",0.25344,-0.89496
"3042",0.2574,-0.891
"3043",0.2574,-0.89496
"3044",0.26136,-0.89892
"3045",0.2574,-0.891
"3046",0.26532,-0.9108
"3047",0.27324,-0.9306
"3048",0.23424,-0.8910

Эти данные являются «справочными» данными, предназначенными для проверки расчетов, выполняемых с другими данными. Чтение данных дает мне следующее:

In [2]: test = pd.read_csv('test.csv', header=0, names=['lx', 'ly'])

In [3]: test
Out[3]: 
           lx       ly
3041  0.25344 -0.89496
3042  0.25740 -0.89100
3043  0.25740 -0.89496
3044  0.26136 -0.89892
3045  0.25740 -0.89100
3046  0.26532 -0.91080
3047  0.27324 -0.93060
3048  0.23424 -0.89100

Что выглядит так, как и следовало ожидать. Проблема в том, что эти значения не совсем такие, какими они кажутся, и сравнения с ними не работают:

In [4]: test.loc[3042,'ly']
Out[4]: -0.8909999999999999

Почему он делает тот? Кажется, это специфично для значений в csv, которые имеют только 3 разряда справа от десятичной дроби, по крайней мере, пока:

In [5]: test.loc[3048,'ly']
Out[5]: -0.891
In [5]: test.loc[3048,'ly']
Out[5]: -0.891
In [6]: test.loc[3047,'ly']
Out[6]: -0.9306
In [7]: test.loc[3046,'ly']
Out[7]: -0.9108

Мне просто нужны точные значения из csv, а не интерпретация. Идеи?

Обновлять:

Я установил float_precision = 'round_trip' в параметрах read_csv и, похоже, это исправило. Документ здесь. Чего я не понимаю, так это того, почему по умолчанию данные изменяются в том виде, в каком они считываются. Это не кажется хорошим для сравнения наборов данных. Есть ли лучший способ чтения данных для тестирования с другими фреймами данных?

Обновление с ответом:

Я изменил float_precision, хотя до сих пор не понимаю, как панды могут искажать данные таким образом. Я получаю преобразование при импорте, но 0,891 должно быть 0,891.

В моем случае сравнения, а не для проверки эквивалентности, я выбрал кое-что другое:

# rather than
df1 == df2

# I tested as
(df1 / df2) - 1 > 1e-14

Это отлично подходит для моих целей.

быстрый комментарий к вашей части кода test = pd.read_csv('test.csv', header=0, names=['lx', 'ly']): причина, по которой вы видите свой первый вывод 3041, заключается в том, что имена дают вам заголовок, затем вы определяете header = 0, который затем использует строку 3040 в качестве строки заголовка (не считая в df ). Если вы хотите 3040 в качестве первого ряда, возьмите header=0.

d_kennetz 22.08.2018 23:21

Спасибо за объяснение. У меня была конкретная причина для установки header = 0.

schwim 23.08.2018 18:52
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
2
1 052
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

кажется, что это связано с типом данных, который вы загружаете, в вашем случае это float64. Используя float 32, вы получите то, что ожидаете. Так что можно менять dtype, пока загрузка

test = pd.read_csv('test.csv', header=0, names=['lx', 'ly'], 
                   dtype = {'ly': np.float32, 'ly': np.float32})

или позже

print(type(test.loc[3042,'ly']))  # <class 'numpy.float64'>
test[['lx', 'ly']] = test[['lx', 'ly']].astype('float32')
print(test.loc[3042,'ly'])  # -0.891

ну, это может зависеть от версии Python и pandas ... не могли бы вы также распечатать, какой тип конкретной ячейки? type(test.loc[3042,'ly'])

Jirka B. 22.08.2018 23:36

Тип по умолчанию - np.float64. Изменение его на np.float32 действительно работает. Мне действительно интересно, что первоначальная проблема возникает из-за интерпретации данных из CSV по умолчанию.

schwim 23.08.2018 18:42
Ответ принят как подходящий

Для сравнения с другими df вы можете использовать pd.option_context (обратите внимание, что я снял header = 0, потому что он не отображает вашу первую строку в вашем df):

import pandas as pd
test = pd.read_csv('./Desktop/dummy.csv', names=['lx', 'ly'])

test.dtypes

with pd.option_context('display.precision', 5):
    print(test.loc[3042,'ly'])

выход:

-0.891

Это не самое лучшее исправление, но добавление

float_precision='round_trip'

тоже не всегда решает вашу проблему:

import pandas as pd
test = pd.read_csv('./Desktop/dummy.csv', names=['lx', 'ly'], float_precision='round_trip')

test.dtypes

test.loc[3042,'ly']

выход:

-0.89100000000000001

С помощью display.precision вы будете выполнять все блоки кода под этим оператором with с установленной точностью, поэтому вы можете гарантировать, что сравниваемые df будут иметь ожидаемое вами значение.

Изменение float_precsion = 'round_trip' действительно решает проблему, как и изменение dtype = np.float32. Однако, чтобы это работало, Numpy должен быть импортирован как np.

schwim 23.08.2018 18:50

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