Internals

原文:http://pandas.pydata.org/pandas-docs/stable/internals.html

译者:飞龙 UsyiyiCN

校对:(虚位以待)

本节将介绍一些大熊猫内部。

Indexing

在大熊猫中有一些实现的对象可以作为轴标签的有效容器:

有一些功能使得创建常规索引变得容易:

首先具有Index类的动机是启用不同的索引实现。这意味着,用户可以实现一个自定义Index子类,它可能更适合于特定应用程序,而不是在pandas中提供的。

从内部实现的角度来看,Index必须定义的相关方法是以下一个或多个(取决于新对象内部与Index功能):

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_tuplesfrom_arrays确保这是真的,但如果你自己计算级别和标签,请小心。

Subclassing pandas Data Structures

警告

在考虑子类化pandas数据结构之前,有一些更简单的替代方法。

  1. 具有pipe
  2. 使用组合请参阅此处

本节介绍如何子类化pandas数据结构以满足更具体的需求。有2分需要注意:

  1. 覆盖构造函数属性。
  2. 定义原始属性

注意

你可以在geopandas项目中找到一个很好的例子。

Override Constructor Properties

每个数据结构都具有指定数据构造函数的构造函数属性。通过覆盖这些属性,您可以通过pandas数据操作来保留定义类。

有3个构造函数要定义:

下表显示了默认情况下pandas数据结构如何定义构造函数属性。

属性属性 Series DataFrame Panel
_constructor Series DataFrame Panel
_constructor_sliced NotImplementedError Series DataFrame
_constructor_expanddim DataFrame Panel NotImplementedError

下面的示例显示如何定义SubclassedSeriesSubclassedDataFrame覆盖构造函数属性。

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__的数据名称。定义原始属性可以通过以下两种方式之一完成:

  1. 为不会传递到操作结果的临时属性定义_internal_names_internal_names_set
  2. 为将传递到操作结果的正常属性定义_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