数据结构简介#

我们将从对 pandas 基本数据结构进行一个快速、非详尽的概述开始,以便您入门。数据类型、索引、轴标签和对齐的基本行为适用于所有对象。开始之前,请导入 NumPy 并将 pandas 加载到您的命名空间:

从根本上讲,数据对齐是内在的。标签和数据之间的链接不会断开,除非您显式地断开它。

我们将简要介绍数据结构,然后将在单独的章节中考虑所有广泛的功能和方法类别。

Series#

Series 是一个一维的带标签数组,能够容纳任何数据类型(整数、字符串、浮点数、Python 对象等)。轴标签统称为 索引。创建 Series 的基本方法是调用:

s = pd.Series(data, index=index)

其中,data 可以是许多不同的东西:

  • Python dict

  • ndarray

  • 标量值(例如 5)

传入的 index 是轴标签列表。因此,这会根据 data 的类型分为几种情况:

从 ndarray 创建

如果 data 是 ndarray,index 的长度必须与 data 相同。如果未传入 index,则会自动创建一个值从 [0, ..., len(data) - 1] 开始的 index。

备注

pandas 支持非唯一的索引值。如果尝试执行不支持重复索引值 O 的操作,届时将引发异常。

从 dict 创建

Series 可以从 dict 实例化:

如果传入了 index,则将提取数据中与 index 中的标签对应的那些值。

备注

NaN(非数字)是 pandas 中使用的标准缺失数据标记。

从标量值创建

如果 data 是标量值,则必须提供 index。该值将重复以匹配 index 的长度。

Series 类似 ndarray#

Series 的行为非常类似于 ndarray,并且是大多数 NumPy 函数的有效参数。但是,切片等操作也会对索引进行切片。

备注

我们将在 section on indexing 中介绍像 s.iloc[[4, 3, 1]] 这样的基于数组的索引。

与 NumPy 数组一样,pandas Series 具有一个单一的 dtype

这通常是 NumPy 的 dtype。然而,pandas 和第三方库在某些地方扩展了 NumPy 的类型系统,在这种情况下,dtype 将是一个 ExtensionDtype 。pandas 内部的一些例子是 类别数据可空整数数据类型 。更多信息请参阅 dtypes

如果您需要 Series 的实际底层数组,请使用 Series.array

访问数组在您需要执行一些不带索引的操作时(例如,禁用 automatic alignment )会很有用。

Series.array 始终是 ExtensionArray 。简而言之,ExtensionArray 是一个围绕一个或多个*具体*数组(如 numpy.ndarray )的轻量级包装器。pandas 知道如何接收一个 ExtensionArray 并将其存储在 SeriesDataFrame 的列中。更多信息请参阅 dtypes

虽然 Series 类似 ndarray,但如果您需要一个*实际*的 ndarray,请使用 Series.to_numpy()

即使 SeriesExtensionArray 支持,Series.to_numpy() 仍会返回一个 NumPy ndarray。

Series 类似 dict#

Series 也类似于固定大小的 dict,因为您可以通过索引标签获取和设置值:

如果标签不包含在索引中,则会引发异常:

使用 Series.get() 方法,缺失的标签将返回 None 或指定的默认值:

这些标签也可以通过 attribute 访问。

向量化操作和 Series 的标签对齐#

在使用原始 NumPy 数组时,通常不需要逐个值进行循环。当在 pandas 中使用 Series 时,情况也是如此。Series 也可以被传递给大多数期望 ndarray 的 NumPy 方法。

Series 和 ndarray 之间的关键区别在于,Series 之间的操作会自动基于标签对齐数据。因此,您可以编写计算而无需考虑所涉及的 Series 是否具有相同的标签。

The result of an operation between unaligned Series will have the union of the indexes involved. If a label is not found in one Series or the other, the result will be marked as missing NaN. Being able to write code without doing any explicit data alignment grants immense freedom and flexibility in interactive data analysis and research. The integrated data alignment features of the pandas data structures set pandas apart from the majority of related tools for working with labeled data.

备注

一般来说,我们选择让不同索引对象之间的操作默认产生索引的**并集**,以避免信息丢失。拥有一个索引标签,即使数据缺失,通常也是计算中重要的信息。当然,您也可以选择通过 dropna 函数删除带有缺失数据的标签。

name 属性#

Series 还有一个 name 属性:

Seriesname 可以在许多情况下自动分配,尤其是在从 DataFrame 中选择单列时,name 将被分配为列标签。

您可以使用 Series 方法重命名 pandas.Series.rename()

请注意,ss2 指的是不同的对象。

DataFrame#

DataFrame 是一个二维标记数据结构,其列可能为不同类型。您可以将其视为电子表格或 SQL 表,或 Series 对象的字典。它通常是pandas中最常用的对象。像Series一样,DataFrame接受许多不同类型的数据:

除了数据,您还可以选择性地传递 **index**(行标签)和 **columns**(列标签)参数。如果您传递了 index 和/或 columns,您就保证了结果 DataFrame 的 index 和/或 columns。因此,Series 的字典加上一个特定的 index 将会丢弃所有与传入的 index 不匹配的数据。

如果未传递轴标签,它们将根据常识规则从输入数据中构建。

来自 Series 或字典的字典#

结果的 index 将是各个 Series 的索引的**并集**。如果有任何嵌套字典,它们将首先被转换为 Series。如果没有传递 columns,columns 将是有序的字典键列表。

行和列标签可以分别通过访问 indexcolumns 属性来访问:

备注

当与数据字典一起传递一组特定的列时,传递的列将覆盖字典中的键。

来自 ndarrays / 列表的字典#

所有 ndarrays 必须共享相同的长度。如果传递了 index,它也必须与数组的长度相同。如果没有传递 index,结果将是 range(n),其中 n 是数组的长度。

来自结构化或记录式数组#

这种情况与包含数组的字典的处理方式相同。

备注

DataFrame 的设计目的不是完全像二维 NumPy ndarray 那样工作。

来自字典列表#

来自元组字典#

通过传递一个元组字典,您可以自动创建一个 MultiIndexed frame。

来自 Series#

结果将是一个 DataFrame,其索引与输入 Series 相同,并且只有一列,其名称是原始 Series 的名称(仅当未提供其他列名时)。

来自命名元组列表#

列表中第一个 namedtuple 的字段名决定了 DataFrame 的列。其余的命名元组(或元组)将被简单地解包,其值将被填充到 DataFrame 的行中。如果其中任何元组比第一个 namedtuple 短,则相应行中的较后几列将被标记为缺失值。如果其中任何元组比第一个 namedtuple 长,则会引发 ValueError

来自数据类列表#

可以在 DataFrame 构造函数中传递 PEP557 中引入的数据类。传递数据类列表等同于传递字典列表。

请注意,列表中的所有值都应该是数据类,混合列表中的类型会导致 TypeError

缺失数据

为了构建包含缺失数据的 DataFrame,我们使用 np.nan 来表示缺失值。或者,您也可以将 numpy.MaskedArray 作为数据参数传递给 DataFrame 构造函数,其掩码条目将被视为缺失。更多信息请参见 Missing data

备选构造函数#

DataFrame.from_dict

DataFrame.from_dict() 接收一个字典的字典或一个字典的类数组序列,并返回一个 DataFrame。它的工作方式类似于 DataFrame 构造函数,只是 orient 参数默认为 'columns',但可以设置为 'index' 以使用字典键作为行标签。

如果传递 orient='index',键将是行标签。在这种情况下,你也可以传递所需的列名:

DataFrame.from_records

DataFrame.from_records() 接收一个元组列表或一个具有结构化 dtype 的 ndarray。它的工作方式类似于普通的 DataFrame 构造函数,只是生成的 DataFrame 索引可以是结构化 dtype 的特定字段。

列选择、添加、删除#

你可以将 DataFrame 在语义上视为一组相同索引的 Series 对象的字典。列的获取、设置和删除操作与字典操作使用相同的语法:

列可以像字典一样被删除或弹出:

插入标量值时,它将自然地传播以填充列:

插入一个与 Series 索引不同的 DataFrame 时,它将被调整以适应 DataFrame 的索引:

你可以插入原始 ndarray,但它们的长度必须与 DataFrame 的索引长度匹配。

默认情况下,列会插入到末尾。 DataFrame.insert() 在列中的特定位置插入:

在方法链中分配新列#

dplyr’s mutate 动词的启发,DataFrame 有一个 assign() 方法,可以让你轻松创建可能派生自现有列的新列。

在上面的示例中,我们插入了一个预先计算好的值。我们还可以传递一个接受一个参数的函数,该函数将被评估在被赋值的 DataFrame 上。

assign() 始终 返回数据的副本,而不会修改原始 DataFrame。

传递一个可调用对象(与要插入的实际值相对)在没有 DataFrame 引用时很有用。当在操作链中使用 assign() 时,这很常见。例如,我们可以将 DataFrame 限制为仅包含花萼长度大于 5 的观测值,计算比率,然后绘制:

由于传递的是一个函数,该函数将在被赋值的 DataFrame 上计算。重要的是,这是已过滤到花萼长度大于 5 的那些行的 DataFrame。过滤先发生,然后计算比率。这是一个我们没有 过滤后 的 DataFrame 引用的示例。

assign() 的函数签名很简单 **kwargs。键是新字段的列名,值是要插入的值(例如,一个 Series 或 NumPy 数组),或者是一个接受一个参数并在 DataFrame 上调用的函数。返回原始 DataFrame副本,并插入新值。

**kwargs 的顺序被保留。这允许 依赖 赋值,其中 **kwargs 中后面的表达式可以引用同一 assign() 中前面创建的列。

在第二个表达式中,x['C'] 将引用新创建的列,该列等于 dfa['A'] + dfa['B']

索引 / 选择#

索引的基本操作如下:

操作

语法

结果

选择列

df[col]

Series

按标签选择行

df.loc[label]

Series

按整数位置选择行

df.iloc[loc]

Series

切片行

df[5:10]

DataFrame

按布尔向量选择行

df[bool_vec]

DataFrame

行选择,例如,返回一个 Series ,其索引是 DataFrame 的列:

有关更全面的关于复杂的基于标签的索引和切片处理,请参阅 section on indexing 。我们将在 section on reindexing 中介绍重新索引/适应新标签集的基础知识。

数据对齐和算术#

DataFrame 对象之间的数据对齐会自动在**列和索引(行标签)**上进行。同样,结果对象将包含列和行标签的并集。

当在 DataFrameSeries 之间执行操作时,默认行为是将 Series索引DataFrame 对齐,从而逐行进行 broadcasting 。例如:

有关匹配和广播行为的显式控制,请参阅 flexible binary operations 部分。

与标量进行算术运算是逐元素进行的:

布尔运算也是逐元素进行的:

转置#

要进行转置,可以访问 T 属性或 DataFrame.transpose() ,这类似于 ndarray:

DataFrame 与 NumPy 函数的互操作性#

大多数 NumPy 函数可以直接在 SeriesDataFrame 上调用。

DataFrame 并非旨在成为 ndarray 的直接替代品,因为其索引语义和数据模型在某些方面与 n 维数组非常不同。

Series 实现了 __array_ufunc__,这使得它可以与 NumPy 的 universal functions 一起工作。

ufunc 应用于 Series 的底层数组。

当多个 Series 被传递给 ufunc 时,它们会在执行操作之前对齐。

与库的其他部分一样,pandas 会自动对齐带有标签的输入作为多输入 ufunc 的一部分。例如,在两个具有不同顺序标签的 numpy.remainder() 上使用 Series ,它们会在操作前对齐。

和往常一样,会取两个索引的并集,并且不重叠的值将被填充为缺失值。

当二元 ufunc 应用于 SeriesIndex 时,Series 的实现优先,并返回一个 Series

NumPy ufuncs 可以安全地应用于由非 ndarray 数组支持的 Series ,例如 arrays.SparseArray (参见 稀疏计算 。如果可能,ufunc 会在不将底层数据转换为 ndarray 的情况下应用。

控制台显示#

一个非常大的 DataFrame 将被截断以在控制台中显示。您也可以使用 info() 获取摘要。( baseball 数据集来自 plyr R 包):

但是,使用 DataFrame.to_string() 会返回 DataFrame 的表格形式的字符串表示,尽管它不一定总是适合控制台宽度:

DataFrame 默认会跨越多行打印:

您可以通过设置 display.width 选项来更改单行上打印的内容:

您可以通过设置 display.max_colwidth 来调整单个列的最大宽度

您也可以通过 expand_frame_repr 选项禁用此功能。这将在一块中打印表格。

DataFrame 列属性访问和 IPython 自动补全#

如果 DataFrame 列标签是有效的 Python 变量名,则可以通过属性访问该列:

列也与 IPython 指令补全机制相关联,因此可以通过 Tab 键补全:

In [5]: df.foo<TAB>  # noqa: E225, E999
df.foo1  df.foo2