python - 为什么 pandas dataframe 单元格的 id 会随着每次执行而变化?

标签 python python-3.x pandas dataframe

我在尝试确定数据框 View 的某些属性时遇到了这个问题。

假设我有一个数据框定义为:df = pd.DataFrame(columns=list('abc'), data=np.arange(18).reshape(6, 3)) 和此数据帧的 View 定义为: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

现在我想输出这两个数据帧的特定单元格的 id:

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

我的输出是:

140114943491408
140114943491408

奇怪的是,如果我连续执行这两行“print id”代码,id 也会改变:

140114943491480
140114943491480

我必须强调的是,我在执行那两个'print id'代码时并没有执行'df definition'代码,所以df和df1没有被重新定义。那么在我看来,数据帧中每个元素的内存地址应该是固定的,那么输出怎么会变化呢?

当我继续执行这两行“print id”代码时,会发生更奇怪的事情。在极少数情况下,这两个 id 甚至不相等:

140114943181088
140114943181112

但是如果我同时执行id(df.loc[0, 'a']) == id(df1.loc[0, 'a']),python还是会输出。我知道因为 df1 是 df 的 View ,所以它们的单元格应该共享一个内存,但是它们的 id 的输出为什么偶尔会不同?

那些奇怪的行为让我完全不知所措。谁能解释这些行为?它们是由于数据框的特性还是python中的id函数?谢谢!

仅供引用,我使用的是 Python 3.5.2

最佳答案

您没有获取“单元格”的 ID,您获取的是 .loc 访问器返回的对象的 id,它是基础数据。

所以,

>>> 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

但是,实际的底层缓冲区是 C 固定大小的 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 只能保证在对象的生命周期 内是唯一的。阅读有关此现象的更多信息 here .但是,请注意,在以下情况下,它总是不同的:

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

由于您维护引用,对象不会被回收,并且需要新的内存。

请注意,对于许多不可变对象(immutable对象),解释器可以自由优化并返回<​​em>完全相同的对象。在 CPython 中,“小整数”即所谓的小整数缓存就是这种情况:

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

但这是不应依赖的实现细节。

如果您想向自己证明您的数据帧共享相同的底层缓冲区,只需改变它们,您就会看到相同的变化反射(reflect)在各个 View 中:

>>> 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

关于python - 为什么 pandas dataframe 单元格的 id 会随着每次执行而变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50441576/

相关文章:

python - 如何在 Pandas Groupby 中仅显示具有值的列

python - 如何根据加权概率从 python 字典中选择键?

python - ValueError:输入包含 NaN、无穷大或对于 dtype ('float64' 来说太大的值),即使 isnan 和 isinf 为 false 且 dtype=float64 时也是如此

Python Heroku 应用程序失败并出现 "Address in use"错误

python - 使用 python 的 SQL Server 查询

python - 查找数据帧的列中的元素数量

python - 将数据框传递给 pandas 中的 SQL 时,如何检查记录是否存在?

python - 如何替换列中的重复值以使其基于 Pandas 中的另一列是唯一的?

python-3.x - 如何使包含 numpy 数组的元组可散列?

python - 使用 to_sql 和 sqlalchemy 将 pandas 数据框转换为 mariadb 数据库