Internals¶
本节将介绍一些大熊猫内部。
Indexing¶
在大熊猫中有一些实现的对象可以作为轴标签的有效容器:
Index
:通用的“有序集合”对象,对象类型的ndarray,不考虑其内容。标签必须是可哈希的(并且可能是不可变的)和唯一的。在Cython中填充标签的位置以执行O(1)
查找。Int64Index
:针对64位整数数据(例如时间戳)高度优化的Index
版本Float64Index
:针对64位浮点数据进行高度优化的Index
版本MultiIndex
:标准层次索引对象DatetimeIndex
:带有Timestamp
框元素的索引对象(impl是int64值)TimedeltaIndex
:具有Timedelta
框元素的索引对象(impl是in64值)PeriodIndex
:包含Period元素的索引对象
有一些功能使得创建常规索引变得容易:
date_range
:从时间规则或DateOffset生成的固定频率日期范围。Python datetime对象的ndarrayperiod_range
:从时间规则或DateOffset生成的固定频率日期范围。Period
对象的数组,表示时间段
首先具有Index
类的动机是启用不同的索引实现。这意味着,用户可以实现一个自定义Index
子类,它可能更适合于特定应用程序,而不是在pandas中提供的。
从内部实现的角度来看,Index
必须定义的相关方法是以下一个或多个(取决于新对象内部与Index
功能):
get_loc
:为标签返回“indexer”(整数,或在某些情况下为slice对象)slice_locs
:返回“范围”到两个标签之间的切片get_indexer
:计算用于重建索引/数据对齐目的的索引向量。有关更多信息,请参阅source / docstringsget_indexer_non_unique
:当索引非唯一时,计算索引向量以进行重建索引/数据对齐。有关更多信息,请参阅source / docstringsreindex
:输入索引的任何预转换然后调用get_indexer
union
,intersection
:计算两个Index对象的并集或交集insert
:在索引中插入一个新标签,产生一个新对象delete
:删除标签,生成一个新对象drop
:删除一组标签take
:类似于ndarray.take
MultiIndex¶
在内部,MultiIndex
包含以下几项内容:级别,整数标签和级别名称:
In [1]: index = pd.MultiIndex.from_product([range(3), ['one', 'two']], names=['first', 'second'])
In [2]: index
Out[2]:
MultiIndex(levels=[[0, 1, 2], [u'one', u'two']],
labels=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]],
names=[u'first', u'second'])
In [3]: index.levels
Out[3]: FrozenList([[0, 1, 2], [u'one', u'two']])
In [4]: index.labels
Out[4]: FrozenList([[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]])
In [5]: index.names
Out[5]: FrozenList([u'first', u'second'])
您可能猜测标签确定在索引的每个层上用该位置标识哪个唯一元素。It’s important to note that sortedness is determined solely from the integer labels and does not check (or care) whether the levels themselves are sorted. 幸运的是,构造函数from_tuples
和from_arrays
确保这是真的,但如果你自己计算级别和标签,请小心。
Subclassing pandas Data Structures¶
本节介绍如何子类化pandas
数据结构以满足更具体的需求。有2分需要注意:
- 覆盖构造函数属性。
- 定义原始属性
注意
你可以在geopandas项目中找到一个很好的例子。
Override Constructor Properties¶
每个数据结构都具有指定数据构造函数的构造函数属性。通过覆盖这些属性,您可以通过pandas
数据操作来保留定义类。
有3个构造函数要定义:
_constructor
:当操作结果与原始操作结果具有相同的缩放时使用。_constructor_sliced
:当操作结果具有一个较低维度作为原始值时使用,例如DataFrame
单列切片。_constructor_expanddim
:当操作结果具有一个较高维度作为原始值时使用,例如Series.to_frame()
和DataFrame.to_panel()
。
下表显示了默认情况下pandas
数据结构如何定义构造函数属性。
属性属性 | Series |
DataFrame |
Panel |
---|---|---|---|
_constructor |
Series |
DataFrame |
Panel |
_constructor_sliced |
NotImplementedError |
Series |
DataFrame |
_constructor_expanddim |
DataFrame |
Panel |
NotImplementedError |
下面的示例显示如何定义SubclassedSeries
和SubclassedDataFrame
覆盖构造函数属性。
class SubclassedSeries(Series):
@property
def _constructor(self):
return SubclassedSeries
@property
def _constructor_expanddim(self):
return SubclassedDataFrame
class SubclassedDataFrame(DataFrame):
@property
def _constructor(self):
return SubclassedDataFrame
@property
def _constructor_sliced(self):
return SubclassedSeries
>>> s = SubclassedSeries([1, 2, 3])
>>> type(s)
<class '__main__.SubclassedSeries'>
>>> to_framed = s.to_frame()
>>> type(to_framed)
<class '__main__.SubclassedDataFrame'>
>>> df = SubclassedDataFrame({'A', [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9]})
>>> df
A B C
0 1 4 7
1 2 5 8
2 3 6 9
>>> type(df)
<class '__main__.SubclassedDataFrame'>
>>> sliced1 = df[['A', 'B']]
>>> sliced1
A B
0 1 4
1 2 5
2 3 6
>>> type(sliced1)
<class '__main__.SubclassedDataFrame'>
>>> sliced2 = df['A']
>>> sliced2
0 1
1 2
2 3
Name: A, dtype: int64
>>> type(sliced2)
<class '__main__.SubclassedSeries'>
Define Original Properties¶
要让原始数据结构具有其他属性,您应该让pandas
知道添加了什么属性。pandas
将未知属性映射到覆盖__getattribute__
的数据名称。定义原始属性可以通过以下两种方式之一完成:
- 为不会传递到操作结果的临时属性定义
_internal_names
和_internal_names_set
。 - 为将传递到操作结果的正常属性定义
_metadata
。
下面是一个定义2个原始属性的示例,“internal_cache”作为临时属性,“added_property”作为正常属性
class SubclassedDataFrame2(DataFrame):
# temporary properties
_internal_names = pd.DataFrame._internal_names + ['internal_cache']
_internal_names_set = set(_internal_names)
# normal properties
_metadata = ['added_property']
@property
def _constructor(self):
return SubclassedDataFrame2
>>> df = SubclassedDataFrame2({'A', [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9]})
>>> df
A B C
0 1 4 7
1 2 5 8
2 3 6 9
>>> df.internal_cache = 'cached'
>>> df.added_property = 'property'
>>> df.internal_cache
cached
>>> df.added_property
property
# properties defined in _internal_names is reset after manipulation
>>> df[['A', 'B']].internal_cache
AttributeError: 'SubclassedDataFrame2' object has no attribute 'internal_cache'
# properties defined in _metadata are retained
>>> df[['A', 'B']].added_property
property