Pandas Функция isin () неправильно определяет числовые совпадения - PullRequest
2 голосов
/ 24 апреля 2020

isin() дает мне странные результаты. Я создаю следующий DataFrame:

import pandas as pd
import numpy as np

test=pd.DataFrame({'1': np.linspace(0.0, 1.0, 11)})

>>> test['1']
0     0.0
1     0.1
2     0.2
3     0.3
4     0.4
5     0.5
6     0.6
7     0.7
8     0.8
9     0.9
10    1.0
Name: 1, dtype: float64

Использование (очевидно) того же массива isin() дает мне теперь что-то странное.

>>> test['1'].isin([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ])
0      True
1      True
2      True
3     False
4      True
5      True
6     False
7     False
8      True
9      True
10     True
Name: 1, dtype: bool

Я подозреваю, что есть некоторые проблемы с числовыми данными или что-то, что связано с типом данных. Может кто-нибудь объяснить это и сказать мне, как это предотвратить?

Ответы [ 4 ]

1 голос
/ 24 апреля 2020

Используйте np.isclose, если хотите выполнить проверки на равенство для чисел с плавающей точкой. Используйте широковещание, чтобы выполнить все сравнения, и np.logical_or.reduce, чтобы объединить результаты в одну маску, указывая, что она «равна» любому элементу.

import numpy as np
import pandas as pd

test = pd.DataFrame({'1': np.linspace(0.0, 1.1, 12)})
l = [0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.]
arr = np.array(l)  # So we can broadcast

test['in_l_close'] = np.logical_or.reduce(np.isclose(test['1'].to_numpy()[None, :], arr[:, None]))
test['in_l_naive'] = test['1'].isin(l)  #For comparision to show flaws.

print(test)

      1  in_l_close  in_l_naive
0   0.0        True        True
1   0.1        True        True
2   0.2        True        True
3   0.3        True       False
4   0.4        True        True
5   0.5        True        True
6   0.6        True       False
7   0.7        True       False
8   0.8        True        True
9   0.9        True        True
10  1.0        True        True
11  1.1       False       False
1 голос
/ 24 апреля 2020

Нет, на самом деле это правильно идентифицирует их. Это больше связано с физикой на более низком уровне внутри процессора (см. здесь ), поэтому вы должны быть осторожны с этими вещами:

print(test["1"].array)
<PandasArray>
[                0.0,                 0.1,                 0.2,
 0.30000000000000004,                 0.4,                 0.5,
  0.6000000000000001,  0.7000000000000001,                 0.8,
                 0.9,                 1.0]
Length: 11, dtype: float64

Однако.

print(test['1'].isin(np.linspace(0.0,1.0,11)))
0     True
1     True
2     True
3     True
4     True
5     True
6     True
7     True
8     True
9     True
10    True
Name: 1, dtype: bool
1 голос
/ 24 апреля 2020

Это будет работать, только если вы сделаете это:

test['1'] = test['1'].map(lambda x: '%.1f' % x)
print(test['1'].astype(np.float).isin([0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 ]))

0     True
1     True
2     True
3     True
4     True
5     True
6     True
7     True
8     True
9     True
10    True
1 голос
/ 24 апреля 2020

isin сравнивает точные значения, поэтому использование его с плавающими значениями почти никогда не является хорошей идеей. Может быть ошибка с плавающей запятой, которая не видна. Например,

for x in np.linspace(0.0,1.0,11): print(x)

дает вам:

0.0
0.1
0.2
0.30000000000000004
0.4
0.5
0.6000000000000001
0.7000000000000001
0.8
0.9
1.0

То есть 0.3, который вы видите в test, на самом деле не 0.3.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...