Разница между & и && при работе в Python Pandas
Допустим есть задача найти максимальное время звонков среди мужчин не пользующихся неким тарифным планом (вся информация хранится в DataFrame). Обратившись к нужным столбцам, получаем решение
df[(df['Gender'] == 'Man') & (df['Tariff plan'] == 'No')]['Total intl minutes'].max()
Почему в условиях стоит знак &, а не && или and?
Ответы (2 шт):
Потому что это "побитовое и" &, а не "логическое и" and (в других языках, например C#, "логическое и" это &&).
(df['Gender'] == 'Man') & (df['Tariff plan'] == 'No')
В этом выражении и слева и справа участвуют вектора, между которыми производится "побитовая" операция, то есть делается "логическое и" между соответствующими элементами двух (или более) векторов, вернее между булевыми элементами объектов типа Pandas.Series. И на выходе у этой операции получается не просто одиночное значение True или False, как у оператора and, а вектор Pandas.Series из булевых значений.
На аглийской части Stackoverflow можно найти более подробное объяснение, но суть там та же.
P.S. Можно задаться вопросом: а почему в случае оператора == не сделали отдельные "побитовую" и "логическую" версию, но тут я так сходу не смогу подсказать. Но, вероятно, именно этот факт вас несколько и озадачил в данном случае - почему тут так, а тут эдак. Ведь тут тоже производится именно поэлементное сравнение, результатом которого является вектор:
df['Gender'] == 'Man'
Потому, что оператора && в python нет, а выражение
x and y
приблизительно соответствует выражению
y if bool(x) else x
Это поведение зашито на уровне синтаксиса, переопределению не подлежит, и явно не соответствует тому результату, которого вы ожидаете от поэлементного логического И двух векторов.
Реализация оператора & таких ограничений не имеет, более того, для логических значений он работает и в ванильном python
(True & False) is False
Единственным принципиальным различием между операциями & и and над логическими значениями, является отсутствие (или наличие) отложенного вычисления правой части выражения
>>> False and (0/0 != 0)
False
>>> False & (0/0 != 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
Но в данном случае это роли не играет.