Pandas中.loc/.iloc返回副本而非视图的原因及视图获取方法
Pandas DataFrame列子集返回视图而非副本的问题
问题描述
我有一个包含pandas.DataFrame的类,其中的方法用于返回该DataFrame的列子集,希望获取视图而非副本。代码示例如下:
import pandas as pd import numpy as np class Data: def __init__(self, path, selected_features): df = pd.read_excel(path) self._features = df[selected_features].astype("float64") # 原数据仅包含int64和float64类型 def features(self): return self._features.iloc[:, 0:2] # 仅返回前2列作为示例
通过np.shares_memory()验证发现返回的是副本:
data = Data(path, selected_features) print(np.shares_memory(data._features, data.features())) # 输出: False print(np.shares_memory(data._features, data._features.iloc[:,0:2])) # 输出: False
使用.loc也得到相同结果。请问为何返回副本,如何让它返回视图?
原因分析
1. astype操作强制生成副本
初始化时执行的.astype("float64")是核心原因之一:即使原数据包含float64类型,只要存在int64列,转换为统一float64类型时必须创建新内存块——int和float的存储格式完全不同,无法在原内存空间直接修改,因此self._features本身就是原DataFrame的副本。
2. 列子集的内存布局限制
通过iloc或loc选取列子集时,Pandas是否返回视图取决于底层数据的内存连续性。即使self._features的所有列都是float64,由于它来自之前的副本操作,Pandas无法确保其内存布局的连续性,因此默认生成副本以保证后续操作的稳定性。
解决方案
方法1:直接操作底层numpy数组
既然self._features的所有列都是float64类型,其底层存储为连续的numpy数组,直接对数组进行切片(numpy切片默认返回视图),再封装为DataFrame即可:
def features(self): # 获取原DataFrame底层数组的列切片视图 arr_view = self._features.values[:, 0:2] # 用原列名和索引创建新DataFrame,共享内存 return pd.DataFrame(arr_view, columns=self._features.columns[:2], index=self._features.index)
验证:
data = Data(path, selected_features) print(np.shares_memory(data._features.values, data.features().values)) # 输出: True
方法2:使用pd.DataFrame.view()
利用Pandas的view方法创建共享内存的视图,前提是子集数据类型与原DataFrame一致:
def features(self): subset = self._features.iloc[:, 0:2] # 创建同类型的视图 return subset.view(dtype='float64')
注意:此方法要求子集的数据类型必须与原DataFrame完全一致,否则会抛出类型不匹配的错误。
内容的提问来源于stack exchange,提问作者Artur Stopa
相关产品推荐
相关产品推荐

