Почему идентификатор ячейки данных pandas изменяется с каждым выполнением? - PullRequest
0 голосов
/ 21 мая 2018

Я столкнулся с этой проблемой, когда пытался проверить некоторые свойства представления фрейма данных.

Предположим, у меня есть фрейм данных, определенный как: df = pd.DataFrame(columns=list('abc'), data=np.arange(18).reshape(6, 3)), и вид этого фрейма данных, определенный как: df1 = df.iloc[:3, :].Теперь у нас есть два кадра данных:

print(df)
    a   b   c
0   0   1   2
1   3   4   5
2   6   7   8
3   9  10  11
4  12  13  14
5  15  16  17

print(df1)

   a  b  c
0  0  1  2
1  3  4  5
2  6  7  8

Теперь я хочу вывести идентификатор конкретной ячейки этих двух кадров данных:

print(id(df.loc[0, 'a']))
print(id(df1.loc[0, 'a']))

, и у меня получится вывод:

140114943491408
140114943491408

Странно то, что если я непрерывно выполняю эти две строки кода «print id», идентификаторы также меняются:

140114943491480
140114943491480

Я должен подчеркнуть, что я не сделалвыполнить код «определения df» при выполнении этих двух кодов «print id», чтобы df и df1 не были переопределены.Тогда, по моему мнению, адрес памяти каждого элемента в фрейме данных должен быть фиксированным, так как же может измениться вывод?

Более странная вещь происходит, когда я продолжаю выполнять эти две строки 'print id'коды.В некоторых редких сценариях эти два идентификатора даже не равны друг другу:

140114943181088
140114943181112

Но если я одновременно выполню id(df.loc[0, 'a']) == id(df1.loc[0, 'a']), python все равно выдаст True.Я знаю, что, поскольку df1 является представлением df, их ячейки должны совместно использовать одну память, но почему выходные данные их идентификаторов могут иногда отличаться?

Эти странные поведения делают меня совершенно потерянным.Может ли кто-нибудь объяснить такое поведение?Это связано с характеристиками фрейма данных или функции id в python?Спасибо!

К вашему сведению, я использую Python 3.5.2.

1 Ответ

0 голосов
/ 21 мая 2018

Вы не получаете идентификатор «ячейки», вы получаете id объекта, возвращенного аксессором .loc, который является коробочной версией базовых данных.

Итак,

>>> import pandas as pd
>>> df = pd.DataFrame(columns=list('abc'), data=np.arange(18).reshape(6, 3))
>>> df1 = df.iloc[:3, :]
>>> df.dtypes
a    int64
b    int64
c    int64
dtype: object
>>> df1.dtypes
a    int64
b    int64
c    int64
dtype: object

Но поскольку все в Python является объектом, ваш метод loc должен возвращать объект:

>>> x = df.loc[0, 'a']
>>> x
0
>>> type(x)
<class 'numpy.int64'>
>>> isinstance(x, object)
True

Однако фактический базовый буферпримитивный массив из 64-битных целых чисел со знаком фиксированного размера.Они не являются объектами Python, они «упакованы» для заимствования термина из других языков, которые смешивают примитивные типы с объектами.

Теперь явление, которое вы видите со всеми объектами, имеющими одинаковые id:

>>> id(df.loc[0, 'a']), id(df.loc[0, 'a'])
(4539673432, 4539673432)
>>> id(df.loc[0, 'a']), id(df.loc[0, 'a']), id(df1.loc[0,'a'])
(4539673432, 4539673432, 4539673432)

Происходит потому, что в Python объекты могут повторно использовать адрес памяти недавно восстановленных объектов.Действительно, когда вы создаете свой кортеж из id, объект, возвращенный loc, существует только достаточно долго, чтобы его можно было передать и обработать при первом вызове id, во второй раз, когда вы используете loc, объектуже освобожден, просто повторно использует ту же память.Вы можете увидеть то же поведение с любым объектом Python, например list:

>>> id([]), id([])
(4545276872, 4545276872)

По сути, id гарантированно будут уникальными только для времени жизни объект.Подробнее об этом явлении здесь .Но обратите внимание, что в следующем случае он всегда будет другим:

>>> x = df.loc[0, 'a']
>>> x2 = df.loc[0, 'a']
>>> id(x), id(x2)
(4539673432, 4539673408)

Поскольку вы сохраняете ссылки вокруг, объекты не возвращаются и требуют новой памяти.

Примечание, дляВо многих неизменяемых объектах интерпретатор может оптимизировать и вернуть точно такой же объект .В CPython это относится к «маленьким целым», так называемому кешу small-int:

>>> x = 2
>>> y = 2
>>> id(x), id(y)
(4304820368, 4304820368)

Но это деталь реализации, на которую не следует полагаться.

ЕслиВы хотите доказать себе, что ваши фреймы данных совместно используют один и тот же базовый буфер, просто измените их, и вы увидите одно и то же изменение, отраженное между представлениями:

>>> df
    a   b   c
0   0   1   2
1   3   4   5
2   6   7   8
3   9  10  11
4  12  13  14
5  15  16  17
>>> df1
   a  b  c
0  0  1  2
1  3  4  5
2  6  7  8
>>> df.loc[0, 'a'] = 99
>>> df
    a   b   c
0  99   1   2
1   3   4   5
2   6   7   8
3   9  10  11
4  12  13  14
5  15  16  17
>>> df1
    a  b  c
0  99  1  2
1   3  4  5
2   6  7  8
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...