dataframe logic_and отлично работает с equals и не работает с not equals
Пожалуйста, помогите мне понять, почему условие "не равно" не работает должным образом.
>>>d = {'a' : [1, 2, 3, 3, 1, 4],
>>> 'b' : [4, 3, 2, 1, 2, 2]}
>>>df = pd.DataFrame(d)
a b
0 1 4
1 2 3
2 3 2
3 3 1
4 1 2
5 4 2
Мы получим правильный результат, если я использую равное условие с logical_and
:
>>>df[np.logical_and(df['a']==3, df['b']==2)]
a b
2 3 2
Но если мы изменим условие на не равное, оно перестает работать правильно:
>>>df[np.logical_and(df['a']!=3, df['b']!=2)]
a b
0 1 4
1 2 3
Это работает как условие ИЛИ вместо И.
Но он снова работает нормально, если мы используем ~
до np.logical_and
>>>df[~np.logical_and(df['a']==3, df['b']==2)]
a b
0 1 4
1 2 3
3 3 1
4 1 2
5 4 2
Что я должен знать о логических условиях, чтобы избежать сбоя?
3 ответа
Я думаю, что вы должны понимать законы Де Моргана:
not (A or B) == (not A) and (not B)
not (A and B) == (not A) or (not B)
Это просто логика высказываний, и она не имеет ничего общего с самим Python.
Мы можем проверить это сами с помощью таблицы истинности. Если мы составим таблицу правды для A and B
, мы видим:
|A|a|
-+-+-+
B|T|F|
-+-+-+
b|F|F|
-+-+-+
Вот A
обозначает, что A
это правда, и a
обозначает, что A
ложно (то же самое для B
). Мы обозначаем T
для истинного и F
за ложь. Теперь противоположная таблица выглядит так:
|A|a|
-+-+-+
B|F|T|
-+-+-+
b|T|T|
-+-+-+
Но если мы построим таблицу истинности для (not A) and (not B)
мы получаем:
|A|a|
-+-+-+
B|F|F|
-+-+-+
b|F|T|
-+-+-+
Таким образом, два не эквивалентны.
Посмотрите на это так: если условие:
A должно быть 5, а B должно быть 3.
Тогда противоположность не должна быть 5 и B не должна быть 3. Поскольку теперь случай, когда A равно 5, а B равен 2, не удовлетворяет нашему первому условию, но и не удовлетворяет нашему (ложному) второму утверждению. Противоположность:
A не должно быть 5 или B не должно быть 3 (напротив)
Поскольку с момента, когда один из двух не равен 5 или 3, этого достаточно.
Если вы пытаетесь отфильтровать кадры данных, вы можете попробовать что-то другое. Посмотри на dataframe.loc
Итак, в вашем примере попробуйте:
df.loc[(df['a'] != 3) & (df['b'] != 2)]
это делает вещи немного более читабельными, IMO
Еще один способ Панд сделать это:
df.query("a != 3 or b != 4")