У меня есть файл 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
Это отлично подходит для моих целей.
Спасибо за объяснение. У меня была конкретная причина для установки header = 0.






кажется, что это связано с типом данных, который вы загружаете, в вашем случае это 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'])
Тип по умолчанию - np.float64. Изменение его на np.float32 действительно работает. Мне действительно интересно, что первоначальная проблема возникает из-за интерпретации данных из CSV по умолчанию.
Для сравнения с другими 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.
быстрый комментарий к вашей части кода
test = pd.read_csv('test.csv', header=0, names=['lx', 'ly']): причина, по которой вы видите свой первый вывод 3041, заключается в том, что имена дают вам заголовок, затем вы определяете header = 0, который затем использует строку 3040 в качестве строки заголовка (не считая в df ). Если вы хотите 3040 в качестве первого ряда, возьмитеheader=0.