#python #pandas #floating-point #precision
#python #pandas #с плавающей запятой #точность
Вопрос:
У меня есть серия pandas со значениями с плавающей запятой, как показано ниже:
s = pd.Series({0: 899.0,
1: 899.0,
2: 1099.0,
3: 279.29998779296875,
4: 2598.833251953125,
5: 499.1666564941406,
6: 1709.050048828125,
7: 279.29998779296875,
8: 999.0,
9: 1498.9949951171875}, name="var")
Я бы хотел получить индексы всех значений, которые не делятся на 0,01, поэтому я попытался определить mask = (100 * s % 1) > 0
, что довольно хорошо работает с предоставленной серией примеров:
s[mask]
3 279.299988
4 2598.833252
5 499.166656
6 1709.050049
7 279.299988
9 1498.994995
Name: var, dtype: float64
s[~mask]
0 899.0
1 899.0
2 1099.0
8 999.0
Name: var, dtype: float64
Однако s
здесь приведен лишь образец гораздо большего набора данных, и когда я делаю то же самое с исходным рядом, значение mask
for 1709.050049
равно False
, что указывает на то, что эти 0049
цифры являются просто проблемой представления с плавающей запятой для числа 1709.05
, которое было извлечено как таковое при создании s
из моих исходных данных с pd.Series.to_dict()
помощью метода. Поэтому мне интересно, верен ли мой способ маскировки чисел, неделимых на 0.01
( mask = (100 * s % 1) > 0
) . Если это не так, что не так с этим решением и как мы можем правильно замаскировать значения?
Комментарии:
1. Это выглядит как сложный способ избежать проблемы, которую следует решать по-другому… Какова ваша конечная цель?
2. Можете ли вы объяснить, что означает «неделимый на .01»?
3. @ThierryLathuille Получить числа, неделимые на 0,01, на самом деле является моей конечной целью. Эти числа представляют цены, и любая цена, которая не является кратностью
0.01
, вызывает подозрение в том смысле, что, возможно, была применена какая-то скидка или что-то в этом роде.4. @SergeyBushmanov неделимый означает, что его нельзя разделить на
0.01
, т.Е. Это не кратность0.01
5. Трудность заключается в том, что величина 0,01 не может быть точно представлена с плавающей запятой, потому что она не кратна степеням 2. Попробуйте умножить на 100 и преобразовать результат в
decimal.Decimal
.
Ответ №1:
Вы можете достичь желаемого с помощью np.isclose, установив параметр rtol
:
s = pd.Series({
0: 898.999998,
1: 899.0,
2: 1099.0,
3: 279.29998779296875,
4: 2598.833251953125,
5: 499.1666564941406,
6: 1709.050048828125,
7: 279.29998779296875,
8: 999.0,
9: 1498.9949951171875,
10: 326.78}
, name="var")
tolerance = 1e-12
mask = np.isclose(s, s.round(2),rtol = tolerance)
s[mask]
1 899.00
2 1099.00
8 999.00
10 326.78
Name: var, dtype: float64
Комментарии:
1. Это очень хорошая идея ( 1), спасибо за это! Однако, как и в одном из моих предыдущих комментариев, когда я умножаю
326.78
на100
, я получаю32677.999999999996
, а оператор modulo возвращает0.999999999996362
значение, близкое к1
, not0
.