Почему вы можете сделать df.loc(False) ['значение'] в pandas?
Я не вижу никакой документации по pandas, объясняя параметр False, переданный в loc. Может ли кто-нибудь объяснить, как() и [] отличаются в этом случае?
Ответы
Ответ 1
df.loc
является экземпляром класса _LocIndexer
, который является подклассом _NDFrameIndexer
.
Когда вы выполняете df.loc(...)
, кажется, вызывается метод __call__
, который безобидно возвращает другой экземпляр сам по себе. Например:
In [641]: df.loc
Out[641]: <pandas.core.indexing._LocIndexer at 0x10eb5f240>
In [642]: df.loc()()()()()()
Out[642]: <pandas.core.indexing._LocIndexer at 0x10eb5fe10>
...
И так далее. Значение, переданное в (...)
, каким-либо образом не используется экземпляром.
С другой стороны, атрибуты, переданные в [...]
, отправляются на __getitem__
/__setitem__
, который выполняет поиск/настройку.
Ответ 2
Как уже объясняют другие ответы, скобки ()
вызывает метод __call__
, который определяется как:
def __call__(self, axis=None):
# we need to return a copy of ourselves
new_self = self.__class__(self.obj, self.name)
new_self.axis = axis
return new_self
Он возвращает копию самого себя. Теперь, что передал аргумент между ()
, заключается в создании экземпляра члена axis
вашей новой копии. Таким образом, это может поставить вопрос о том, почему не имеет значения, какое значение вы передаете в качестве аргумента, результирующий индексатор точно такой же. Ответ на этот вопрос заключается в том, что суперкласс _NDFrameIndexer
используется для нескольких дочерних классов.
Для метода .loc
, который вызывает класс _LocIndexer
, этот член не имеет значения. Класс LocIndexer
сам является подклассом _LocationIndexer
, который является подклассом _NDFrameIndexer
.
Каждый раз, когда axis
вызывается _LocationIndexer
, он по умолчанию равен нулю, без возможности его указания самостоятельно. Например, я буду ссылаться на одну из функций внутри класса, а другие следуют примеру:
def __getitem__(self, key):
if type(key) is tuple:
key = tuple(com._apply_if_callable(x, self.obj) for x in key)
try:
if self._is_scalar_access(key):
return self._getitem_scalar(key)
except (KeyError, IndexError):
pass
return self._getitem_tuple(key)
else:
key = com._apply_if_callable(key, self.obj)
return self._getitem_axis(key, axis=0)
Итак, независимо от того, какой аргумент вы передаете в .loc(whatever)
, он будет переопределен значением по умолчанию. Аналогичное поведение вы увидите при вызове .iloc
, который вызывает _iLocIndexer(_LocationIndexer)
и, таким образом, также по умолчанию отменяет этот axis
.
Откуда этот axis
входит в игру? Ответ: в устаревшем методе .ix
. У меня есть dataframe формы (2187, 5)
, и теперь определите:
a = df.ix(0)
b= df.ix(1)
c = df.ix(2)
a[0] == b[0] #True
b[0] == c[0] #True
a[0,1] == b[0,1] #False
Если вы используете простое скалярное индексирование, axis
по-прежнему игнорируется в этом двухмерном примере, так как метод get
возвращается к простому скалярному индексированию на основе целых чисел. Однако a[0,1]
имеет форму (2,5)
< - он принимает первые две записи вдоль axis=0
; b[0,1]
имеет форму (2187, 2)
< - он принимает первые две записи вдоль axis=1
; c[0,1]
возвращает ValueError: No axis named 2 for object type <class 'pandas.core.frame.DataFrame'>
.
Другими словами:
Вы все равно можете вызвать метод вызов класса _NDFrameIndexer, поскольку он используется в подклассе _IXIndexer. Однако: начиная с 0.20.0 индекс индекса .ix устарел, в пользу более строгих индексов .iloc и .loc. Аргумент передан вызов для .iloc и .loc игнорируется.
Ответ 3
Для любого объекта python ()
вызывает метод __call__
, тогда как []
вызывает метод __getitem__
(если вы не устанавливаете значение, и в этом случае он вызывает __setitem__
). Другими словами, ()
и []
вызывают разные методы, так почему вы ожидаете, что они будут действовать одинаково?