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")
Другие вопросы по тегам