geekdoc-python-zh/docs/realpython/pandas-dataframe.md

69 KiB
Raw Permalink Blame History

熊猫数据框架:让数据工作变得愉快

原文:https://realpython.com/pandas-dataframe/

*立即观看**本教程有真实 Python 团队创建的相关视频课程。与书面教程一起观看,加深您的理解: 熊猫数据帧:高效处理数据

熊猫数据帧 是一个结构,包含二维数据及其对应的标签。数据帧广泛应用于数据科学机器学习、科学计算以及其他许多数据密集型领域。

数据帧类似于 SQL 表或您在 Excel 或 Calc 中使用的电子表格。在许多情况下,数据帧比表格或电子表格更快、更容易使用、更强大,因为它们是 PythonNumPy 生态系统不可或缺的一部分。

在本教程中,您将学习:

  • 什么是熊猫数据框架以及如何创建一个
  • 如何访问、修改、添加、排序、过滤和删除数据
  • 如何处理缺失值
  • 如何处理时序数据
  • 如何快速可视化数据

是时候开始使用熊猫数据框架了!

免费奖励: 掌握 Python 的 5 个想法,这是一个面向 Python 开发者的免费课程,向您展示将 Python 技能提升到下一个水平所需的路线图和心态。

介绍熊猫数据帧

熊猫数据帧是包含以下内容的数据结构:

  • 数据组织成二维,行和列
  • 标签对应于

您可以通过导入 熊猫来开始处理数据帧:

>>> import pandas as pd

现在您已经导入了熊猫,您可以使用数据框架了。

想象一下,你正在用熊猫来分析一个职位的候选人的数据,这个职位是用 Python 开发 web 应用程序。假设你对候选人的姓名、城市、年龄和 Python 编程测试的分数感兴趣,或者:

name city age py-score
T2101 Xavier Mexico City 41 88.0
T2102 Ann Toronto 28 79.0
T2103 Jana Prague 33 81.0
T2104 Yi Shanghai 34 80.0
T2105 Robin Manchester 38 68.0
T2106 Amal Cairo 31 61.0
T2107 Nori Osaka 37 84.0

在该表中,第一行包含列标签 ( namecityagepy-score)。第一列包含行标签 ( 101102等等)。所有其他单元格用数据值填充。

现在,您已经拥有了创建熊猫数据框架所需的一切。

创建熊猫数据框架有几种方法。在大多数情况下,您将使用 DataFrame构造函数并提供数据、标签和其他信息。您可以将数据作为二维的列表、元组、NumPy 数组来传递。您还可以将它作为一个字典Pandas Series 实例传递,或者作为本教程中未涉及的其他几种数据类型之一传递。

对于这个例子,假设您正在使用一个字典来传递数据:

>>> data = {
...     'name': ['Xavier', 'Ann', 'Jana', 'Yi', 'Robin', 'Amal', 'Nori'],
...     'city': ['Mexico City', 'Toronto', 'Prague', 'Shanghai',
...              'Manchester', 'Cairo', 'Osaka'],
...     'age': [41, 28, 33, 34, 38, 31, 37],
...     'py-score': [88.0, 79.0, 81.0, 80.0, 68.0, 61.0, 84.0]
... }

>>> row_labels = [101, 102, 103, 104, 105, 106, 107]

data是一个 Python 变量,它引用保存候选数据的字典。它还包含列的标签:

  • 'name'
  • 'city'
  • 'age'
  • 'py-score'

最后,row_labels指的是包含行标签的列表,这些标签是从101107的数字。

现在,您已经准备好创建熊猫数据框架了:

>>> df = pd.DataFrame(data=data, index=row_labels)
>>> df
 name         city  age  py-score
101  Xavier  Mexico City   41      88.0
102     Ann      Toronto   28      79.0
103    Jana       Prague   33      81.0
104      Yi     Shanghai   34      80.0
105   Robin   Manchester   38      68.0
106    Amal        Cairo   31      61.0
107    Nori        Osaka   37      84.0

就是这样!df是一个变量,用于保存对熊猫数据帧的引用。这个 Pandas 数据框架看起来就像上面的候选表,具有以下特征:

  • 101107的行标签
  • 列标签,如'name''city''age''py-score'
  • 数据,如考生姓名、城市、年龄和 Python 考试成绩

该图显示了来自df的标签和数据:

mmst-pandas-df-1

行标签用蓝色标出,而列标签用红色标出,数据值用紫色标出。

Pandas 数据帧有时会非常大,一次查看所有行是不切实际的。您可以使用 .head() 显示前几项,使用 .tail() 显示后几项:

>>> df.head(n=2)
 name         city  age  py-score
101  Xavier  Mexico City   41      88.0
102     Ann      Toronto   28      79.0

>>> df.tail(n=2)
 name   city  age  py-score
106  Amal  Cairo   31      61.0
107  Nori  Osaka   37      84.0

这就是如何显示熊猫数据帧的开始或结束。参数n指定要显示的行数。

注意:把 Pandas DataFrame 想象成一个列的字典,或者 Pandas 系列,有很多额外的特性。

您可以像从字典中获取值一样访问 Pandas 数据帧中的列:

>>> cities = df['city']
>>> cities
101    Mexico City
102        Toronto
103         Prague
104       Shanghai
105     Manchester
106          Cairo
107          Osaka
Name: city, dtype: object

这是从熊猫数据框架中获取列的最方便的方法。

如果列名是一个有效的 Python 标识符的字符串,那么您可以使用点符号来访问它。也就是说,您可以像获取类实例的属性一样访问该列:

>>> df.city
101    Mexico City
102        Toronto
103         Prague
104       Shanghai
105     Manchester
106          Cairo
107          Osaka
Name: city, dtype: object

这就是你得到一个特定列的方法。您已经提取了与标签'city'相对应的列,其中包含了所有求职者的位置。

请注意,您已经提取了数据和相应的行标签,这一点很重要:

mmst-pandas-df-2

熊猫数据帧的每一列都是 pandas.Series 的一个实例,这是一个保存一维数据及其标签的结构。您可以像使用字典一样获得一个Series对象的单个项目,方法是使用它的标签作为一个键:

>>> cities[102]
'Toronto'

在这种情况下,'Toronto'是数据值,102是相应的标签。正如你将在后面的章节中看到的,还有其他方法可以在熊猫数据帧中获得特定的项目。

你也可以用访问器 .loc[] 访问一整行:

>>> df.loc[103]
name          Jana
city        Prague
age             33
py-score        81
Name: 103, dtype: object

这一次,您已经提取了对应于标签103的行,其中包含名为Jana的候选人的数据。除了该行中的数据值,您还提取了相应列的标签:

mmst-pandas-df-3

返回的行也是pandas.Series的实例。

Remove ads

创建熊猫数据框架

如前所述,创建熊猫数据框有几种方法。在本节中,您将学习如何使用DataFrame构造函数以及:

  • Python 词典
  • Python 列表
  • 二维 NumPy 阵列
  • 文件

还有其他方法,你可以在官方文档中了解到。

您可以从导入熊猫和 NumPy 开始,您将在下面的例子中使用它们:

>>> import numpy as np
>>> import pandas as pd

就是这样。现在,您已经准备好创建一些数据框架了。

用字典创建熊猫数据框架

正如您已经看到的,您可以使用 Python 字典创建熊猫数据帧:

>>> d = {'x': [1, 2, 3], 'y': np.array([2, 4, 8]), 'z': 100}

>>> pd.DataFrame(d)
 x  y    z
0  1  2  100
1  2  4  100
2  3  8  100

字典的关键字是数据帧的列标签,字典值是相应数据帧列中的数据值。这些值可以包含在一个元组列表、一维 NumPy 数组Pandas Series对象或其他几种数据类型之一中。您还可以提供一个值,该值将沿整列复制。

可以用参数columns控制列的顺序,用参数index控制行标签的顺序:

>>> pd.DataFrame(d, index=[100, 200, 300], columns=['z', 'y', 'x'])
 z  y  x
100  100  2  1
200  100  4  2
300  100  8  3

如您所见,您已经指定了行标签100200300。您还强制了列的顺序:zyx

用列表创建熊猫数据框架

创建熊猫数据框架的另一种方法是使用字典列表:

>>> l = [{'x': 1, 'y': 2, 'z': 100},
...      {'x': 2, 'y': 4, 'z': 100},
...      {'x': 3, 'y': 8, 'z': 100}]

>>> pd.DataFrame(l)
 x  y    z
0  1  2  100
1  2  4  100
2  3  8  100

同样,字典键是列标签,字典值是数据帧中的数据值。

你也可以使用一个嵌套的列表,或者一个列表列表,作为数据值。如果这样做,那么在创建数据帧时,明智的做法是显式指定列和/或行的标签:

>>> l = [[1, 2, 100],
...      [2, 4, 100],
...      [3, 8, 100]]

>>> pd.DataFrame(l, columns=['x', 'y', 'z'])
 x  y    z
0  1  2  100
1  2  4  100
2  3  8  100

这就是如何使用嵌套列表创建熊猫数据框架。也可以用同样的方式使用元组列表。为此,只需用元组替换上例中的嵌套列表。

Remove ads

用 NumPy 数组创建熊猫数据帧

您可以像处理列表一样将二维 NumPy 数组传递给DataFrame构造函数:

>>> arr = np.array([[1, 2, 100],
...                 [2, 4, 100],
...                 [3, 8, 100]])

>>> df_ = pd.DataFrame(arr, columns=['x', 'y', 'z'])
>>> df_
 x  y    z
0  1  2  100
1  2  4  100
2  3  8  100

尽管这个例子看起来与上面的嵌套列表实现几乎一样,但是它有一个优点:您可以指定可选参数copy

copy设置为False(默认设置)时NumPy 数组中的数据不会被复制。这意味着数组中的原始数据被分配给 Pandas 数据帧。如果您修改阵列,那么您的数据帧也会改变:

>>> arr[0, 0] = 1000

>>> df_
 x  y    z
0  1000  2  100
1     2  4  100
2     3  8  100

如你所见,当你改变arr的第一项时,你也修改了df_

**注意:**在处理大型数据集时,不复制数据值可以节省大量时间和处理能力。

如果这种行为不是您想要的,那么您应该在DataFrame构造函数中指定copy=True。这样,df_将被创建为来自arr的值的副本,而不是实际的值。

从文件创建熊猫数据帧

您可以将数据和标签从 Pandas DataFrame 保存和加载到多种文件类型,包括 CSV、Excel、SQL、JSON 等等。这是一个非常强大的功能。

您可以使用 .to_csv() 将您的求职者数据框架保存到 CSV 文件:

>>> df.to_csv('data.csv')

上面的语句将在您的工作目录中生成一个名为data.csvCSV 文件:

,name,city,age,py-score
101,Xavier,Mexico City,41,88.0
102,Ann,Toronto,28,79.0
103,Jana,Prague,33,81.0
104,Yi,Shanghai,34,80.0
105,Robin,Manchester,38,68.0
106,Amal,Cairo,31,61.0
107,Nori,Osaka,37,84.0

现在你已经有了一个包含数据的 CSV 文件,你可以用 read_csv() 加载它:

>>> pd.read_csv('data.csv', index_col=0)
 name         city  age  py-score
101  Xavier  Mexico City   41      88.0
102     Ann      Toronto   28      79.0
103    Jana       Prague   33      81.0
104      Yi     Shanghai   34      80.0
105   Robin   Manchester   38      68.0
106    Amal        Cairo   31      61.0
107    Nori        Osaka   37      84.0

这就是如何从文件中获取熊猫数据帧的方法。在这种情况下,index_col=0指定行标签位于 CSV 文件的第一列。

检索标签和数据

既然已经创建了数据框架,就可以开始从中检索信息了。使用 Pandas您可以执行以下操作:

  • 以序列形式检索和修改行和列标签
  • 将数据表示为 NumPy 数组
  • 检查并调整数据类型
  • 分析DataFrame物体的大小

Remove ads

作为序列的熊猫数据帧标签

可以用 .index 得到数据帧的行标签,用 .columns 得到数据帧的列标签:

>>> df.index
Int64Index([1, 2, 3, 4, 5, 6, 7], dtype='int64')

>>> df.columns
Index(['name', 'city', 'age', 'py-score'], dtype='object')

现在,行和列标签作为特殊类型的序列。与处理任何其他 Python 序列一样,您可以获得单个项目:

>>> df.columns[1]
'city'

除了提取特定的项,您还可以应用其他序列操作,包括遍历行或列的标签。然而,这很少是必要的,因为 Pandas 提供了其他方法来迭代数据帧,这将在后面的章节中看到。

您也可以使用这种方法来修改标签:

>>> df.index = np.arange(10, 17)

>>> df.index
Int64Index([10, 11, 12, 13, 14, 15, 16], dtype='int64')

>>> df
 name         city  age  py-score
10  Xavier  Mexico City   41      88.0
11     Ann      Toronto   28      79.0
12    Jana       Prague   33      81.0
13      Yi     Shanghai   34      80.0
14   Robin   Manchester   38      68.0
15    Amal        Cairo   31      61.0
16    Nori        Osaka   37      84.0

在本例中,您使用 numpy.arange() 来生成一个新的行标签序列,其中包含从1016的整数。要了解更多关于arange()的内容,请查看 NumPy arange():如何使用 np.arange()

请记住,如果你试图修改.index.columns的某一项,那么你将得到一个 TypeError

作为 NumPy 数组的数据

有时,您可能想从没有标签的熊猫数据帧中提取数据。要获得带有未标记数据的 NumPy 数组,可以使用 .to_numpy().values :

>>> df.to_numpy()
array([['Xavier', 'Mexico City', 41, 88.0],
 ['Ann', 'Toronto', 28, 79.0],
 ['Jana', 'Prague', 33, 81.0],
 ['Yi', 'Shanghai', 34, 80.0],
 ['Robin', 'Manchester', 38, 68.0],
 ['Amal', 'Cairo', 31, 61.0],
 ['Nori', 'Osaka', 37, 84.0]], dtype=object)

.to_numpy().values的工作方式类似,它们都返回一个 NumPy 数组,其中包含来自 Pandas DataFrame 的数据:

mmst-pandas-df-4

Pandas 文档建议使用.to_numpy(),因为两个可选参数提供了灵活性:

  1. dtype : 使用该参数指定结果数组的数据类型。默认设置为None
  2. copy : 如果想使用数据帧中的原始数据,将该参数设置为False。如果你想复制数据,将其设置为True

不过.values.to_numpy()存在的时间要长得多,后者是在熊猫 0.24.0 版本中引入的。这意味着你可能会更频繁地看到.values,尤其是在旧代码中。

数据类型

数据值的类型,也称为数据类型数据类型**,非常重要,因为它们决定了数据帧使用的内存量,以及它的计算速度和精度水平。**

Pandas 非常依赖于 NumPy 数据类型。然而,熊猫 1.0 引入了一些额外的类型:

.dtypes 可以得到熊猫数据帧每一列的数据类型:

>>> df.dtypes
name         object
city         object
age           int64
py-score    float64
dtype: object

如您所见,.dtypes返回一个Series对象,以列名作为标签,以相应的数据类型作为值。

如果要修改一列或多列的数据类型,那么可以使用 .astype() :

>>> df_ = df.astype(dtype={'age': np.int32, 'py-score': np.float32})
>>> df_.dtypes
name         object
city         object
age           int32
py-score    float32
dtype: object

.astype()最重要也是唯一强制的参数是dtype。它需要数据类型或字典。如果传递一个字典,那么键就是列名,值就是所需的相应数据类型。

如您所见,数据帧df中的列agepy-score的数据类型都是int64,表示 64 位(或 8 字节)整数。然而,df_也提供了一种更小的 32 位(4 字节)整数数据类型,称为int32

Remove ads

熊猫数据帧大小

属性 .ndim.size.shape 分别返回维度数、跨每个维度的数据值数以及数据值总数:

>>> df_.ndim
2

>>> df_.shape
(7, 4)

>>> df_.size
28

DataFrame实例有两个维度(行和列),所以.ndim返回2。另一方面,Series对象只有一个维度,所以在这种情况下,.ndim将返回1

.shape属性返回一个包含行数(在本例中为7)和列数(4)的元组。最后,.size返回一个等于 DataFrame 中值的个数的整数(28)。

你甚至可以用 .memory_usage() 检查每一列使用的内存量:

>>> df_.memory_usage()
Index       56
name        56
city        56
age         28
py-score    28
dtype: int64

如您所见,.memory_usage()返回一个以列名作为标签、以字节为单位的内存使用量作为数据值的序列。如果您想排除保存行标签的列的内存使用,那么传递可选参数index=False

在上面的例子中,最后两列agepy-score各使用 28 字节的内存。这是因为这些列有七个值,每个值都是一个 32 位或 4 字节的整数。7 个整数乘以 4 个字节各等于 28 个字节的内存使用量。

访问和修改数据

您已经学习了如何将 Pandas 数据帧的特定行或列作为Series对象:

>>> df['name']
10    Xavier
11       Ann
12      Jana
13        Yi
14     Robin
15      Amal
16      Nori
Name: name, dtype: object

>>> df.loc[10]
name             Xavier
city        Mexico City
age                  41
py-score             88
Name: 10, dtype: object

在第一个例子中,通过使用标签作为键,像访问字典中的元素一样访问列name。如果列标签是有效的 Python 标识符,那么您也可以使用点符号来访问该列。在第二个例子中,您使用 .loc[] 来获取标签为10的行。

用存取器获取数据

除了可以通过标签获取行或列的访问器.loc[]之外Pandas 还提供了访问器 .iloc[] ,可以通过整数索引来检索行或列。在大多数情况下,您可以使用这两种方法中的任何一种:

>>> df.loc[10]
name             Xavier
city        Mexico City
age                  41
py-score             88
Name: 10, dtype: object

>>> df.iloc[0]
name             Xavier
city        Mexico City
age                  41
py-score             88
Name: 10, dtype: object

df.loc[10]返回带有标签10的行。类似地,df.iloc[0]返回具有从零开始的索引0的行,这是第一行。正如您所看到的,两条语句都返回相同的行作为一个Series对象。

熊猫总共有四个访问者:

  1. .loc[] 接受行和列的标签并返回系列或数据帧。您可以使用它来获取整行或整列,以及它们的各个部分。

  2. .iloc[] 接受行和列的从零开始的索引,并返回系列或数据帧。您可以使用它来获取整行或整列,或者它们的一部分。

  3. .at[] 接受行和列的标签并返回单个数据值。

  4. .iat[] 接受行和列的从零开始的索引,并返回单个数据值。

其中,.loc[].iloc[]特别厉害。它们支持切片NumPy 式索引。您可以使用它们来访问列:

>>> df.loc[:, 'city']
10    Mexico City
11        Toronto
12         Prague
13       Shanghai
14     Manchester
15          Cairo
16          Osaka
Name: city, dtype: object

>>> df.iloc[:, 1]
10    Mexico City
11        Toronto
12         Prague
13       Shanghai
14     Manchester
15          Cairo
16          Osaka
Name: city, dtype: object

df.loc[:, 'city']返回列city。行标签 place 中的 slice 构造(:)意味着应该包含所有的行。df.iloc[:, 1]返回同一列,因为从零开始的索引1引用第二列city

就像使用 NumPy 一样,您可以提供切片以及列表或数组,而不是索引来获得多行或多列:

>>> df.loc[11:15, ['name', 'city']]
 name        city
11    Ann     Toronto
12   Jana      Prague
13     Yi    Shanghai
14  Robin  Manchester
15   Amal       Cairo

>>> df.iloc[1:6, [0, 1]]
 name        city
11    Ann     Toronto
12   Jana      Prague
13     Yi    Shanghai
14  Robin  Manchester
15   Amal       Cairo

**注意:**不要用元组代替列表或整数数组来获取普通的行或列。元组被保留用于在 NumPy 和 Pandas中表示多维度,以及在 Pandas 中的分级或多级索引。

在本例中,您使用:

  • 切片得到标签为1115的行,相当于索引15
  • 列出得到列namecity,相当于索引01

两条语句都返回一个 Pandas 数据帧,该数据帧具有所需的五行和两列的交集。

这就引出了.loc[].iloc[]之间一个非常重要的区别。正如您在前面的例子中看到的,当您将行标签11:15传递给.loc[]时,您得到了从1115的行。然而,当您传递行索引1:6.iloc[]时,您只获得索引为15的行。

只获得索引15的原因是,对于.iloc[],切片的停止索引独占的,这意味着它被排除在返回值之外。这与 Python 序列和 NumPy 数组一致。然而,使用.loc[],开始和停止索引都包含在中,这意味着它们包含在返回值中。

使用.iloc[]可以跳过行和列,就像对元组、列表和 NumPy 数组进行切片一样:

>>> df.iloc[1:6:2, 0]
11     Ann
13      Yi
15    Amal
Name: name, dtype: object

在本例中,您用片1:6:2指定所需的行索引。这意味着从索引为1的行(第二行)开始,在索引为6的行(第七行)之前停止,然后每隔一行跳过一行。

除了使用切片构造,您还可以使用内置的 Python 类 slice() ,以及 numpy.s_[]pd.IndexSlice[] :

>>> df.iloc[slice(1, 6, 2), 0]
11     Ann
13      Yi
15    Amal
Name: name, dtype: object

>>> df.iloc[np.s_[1:6:2], 0]
11     Ann
13      Yi
15    Amal
Name: name, dtype: object

>>> df.iloc[pd.IndexSlice[1:6:2], 0]
11     Ann
13      Yi
15    Amal
Name: name, dtype: object

根据您的情况,您可能会发现其中一种方法比其他方法更方便。

可以使用.loc[].iloc[]来获得特定的数据值。然而当您只需要一个值时Pandas 推荐使用专门的访问器.at[].iat[]:

>>> df.at[12, 'name']
'Jana'

>>> df.iat[2, 0]
'Jana'

在这里,您使用了.at[]来获得一个候选人的名字,该候选人使用了相应的列和行标签。您还使用了.iat[]来使用它的列和行索引检索相同的名称。

Remove ads

用存取器设置数据

您可以使用访问器通过传递 Python 序列、NumPy 数组或单个值来修改 Pandas 数据帧的各个部分:

>>> df.loc[:, 'py-score']
10    88.0
11    79.0
12    81.0
13    80.0
14    68.0
15    61.0
16    84.0
Name: py-score, dtype: float64

>>> df.loc[:13, 'py-score'] = [40, 50, 60, 70]
>>> df.loc[14:, 'py-score'] = 0

>>> df['py-score']
10    40.0
11    50.0
12    60.0
13    70.0
14     0.0
15     0.0
16     0.0
Name: py-score, dtype: float64

语句df.loc[:13, 'py-score'] = [40, 50, 60, 70]使用您提供的列表中的值修改列py-score中的前四项(行1013)。使用df.loc[14:, 'py-score'] = 0将该列中的剩余值设置为0

以下示例显示了您可以使用负索引和.iloc[]来访问或修改数据:

>>> df.iloc[:, -1] = np.array([88.0, 79.0, 81.0, 80.0, 68.0, 61.0, 84.0])

>>> df['py-score']
10    88.0
11    79.0
12    81.0
13    80.0
14    68.0
15    61.0
16    84.0
Name: py-score, dtype: float64

在本例中,您已经访问并修改了最后一列('py-score'),它对应于整数列索引-1。这种行为与 Python 序列和 NumPy 数组是一致的。

插入和删除数据

Pandas 提供了几种方便的插入和删除行或列的技术。你可以根据自己的情况和需求来选择。

插入和删除行

假设您想在求职者列表中添加一个新人。你可以通过创建一个新的Series对象来代表这个新的候选对象:

>>> john = pd.Series(data=['John', 'Boston', 34, 79],
...                  index=df.columns, name=17)
>>> john
name          John
city        Boston
age             34
py-score        79
Name: 17, dtype: object

>>> john.name
17

新对象的标签对应于来自df的列标签。所以才需要index=df.columns

您可以用 .append()john作为新的一行添加到df的末尾:

>>> df = df.append(john)
>>> df
 name         city  age  py-score
10  Xavier  Mexico City   41      88.0
11     Ann      Toronto   28      79.0
12    Jana       Prague   33      81.0
13      Yi     Shanghai   34      80.0
14   Robin   Manchester   38      68.0
15    Amal        Cairo   31      61.0
16    Nori        Osaka   37      84.0
17    John       Boston   34      79.0

这里,.append()返回附加了新行的熊猫数据帧。注意 Pandas 如何使用属性john.name,即值17,来指定新行的标签。

您已经通过对.append()的一次调用附加了一个新行,并且您可以通过对 .drop() 的一次调用删除它:

>>> df = df.drop(labels=[17])
>>> df
 name         city  age  py-score
10  Xavier  Mexico City   41      88.0
11     Ann      Toronto   28      79.0
12    Jana       Prague   33      81.0
13      Yi     Shanghai   34      80.0
14   Robin   Manchester   38      68.0
15    Amal        Cairo   31      61.0
16    Nori        Osaka   37      84.0

这里,.drop()删除由参数labels指定的行。默认情况下,它返回删除了指定行的 Pandas 数据帧。如果您通过了inplace=True,那么原始数据帧将被修改,您将得到 None 作为返回值。

插入和删除列

在 Pandas 数据帧中插入一列的最直接的方法是遵循当您向字典添加一个条目时所使用的相同过程。下面是如何在一个 JavaScript 测试中添加包含候选人分数的列:

>>> df['js-score'] = np.array([71.0, 95.0, 88.0, 79.0, 91.0, 91.0, 80.0])
>>> df
 name         city  age  py-score  js-score
10  Xavier  Mexico City   41      88.0      71.0
11     Ann      Toronto   28      79.0      95.0
12    Jana       Prague   33      81.0      88.0
13      Yi     Shanghai   34      80.0      79.0
14   Robin   Manchester   38      68.0      91.0
15    Amal        Cairo   31      61.0      91.0
16    Nori        Osaka   37      84.0      80.0

现在原始数据帧的末尾多了一列js-score

您不必提供完整的值序列。您可以添加具有单个值的新列:

>>> df['total-score'] = 0.0
>>> df
 name         city  age  py-score  js-score  total-score
10  Xavier  Mexico City   41      88.0      71.0          0.0
11     Ann      Toronto   28      79.0      95.0          0.0
12    Jana       Prague   33      81.0      88.0          0.0
13      Yi     Shanghai   34      80.0      79.0          0.0
14   Robin   Manchester   38      68.0      91.0          0.0
15    Amal        Cairo   31      61.0      91.0          0.0
16    Nori        Osaka   37      84.0      80.0          0.0

数据帧df现在有一个用零填充的附加列。

如果您过去使用过字典,那么这种插入列的方式可能对您来说很熟悉。但是,它不允许您指定新列的位置。如果新列的位置很重要,那么可以用 .insert() 来代替:

>>> df.insert(loc=4, column='django-score',
...           value=np.array([86.0, 81.0, 78.0, 88.0, 74.0, 70.0, 81.0]))
>>> df
 name         city  age  py-score  django-score  js-score  total-score
10  Xavier  Mexico City   41      88.0          86.0      71.0          0.0
11     Ann      Toronto   28      79.0          81.0      95.0          0.0
12    Jana       Prague   33      81.0          78.0      88.0          0.0
13      Yi     Shanghai   34      80.0          88.0      79.0          0.0
14   Robin   Manchester   38      68.0          74.0      91.0          0.0
15    Amal        Cairo   31      61.0          70.0      91.0          0.0
16    Nori        Osaka   37      84.0          81.0      80.0          0.0

您刚刚插入了另一列,其中包含了 Django 测试的分数。参数loc确定 Pandas 数据帧中新列的位置,或从零开始的索引。column设置新列的标签,value指定要插入的数据值。

通过使用 del语句,可以从 Pandas 数据帧中删除一列或多列,就像使用常规 Python 字典一样:

>>> del df['total-score']
>>> df
 name         city  age  py-score  django-score  js-score
10  Xavier  Mexico City   41      88.0          86.0      71.0
11     Ann      Toronto   28      79.0          81.0      95.0
12    Jana       Prague   33      81.0          78.0      88.0
13      Yi     Shanghai   34      80.0          88.0      79.0
14   Robin   Manchester   38      68.0          74.0      91.0
15    Amal        Cairo   31      61.0          70.0      91.0
16    Nori        Osaka   37      84.0          81.0      80.0

现在你有了没有列total-scoredf。与字典的另一个相似之处是能够使用 .pop() ,删除指定的列并返回它。这意味着你可以做类似于df.pop('total-score')的事情,而不是使用del

您也可以像之前对行所做的那样,用.drop()删除一个或多个列。同样,您需要用labels指定所需列的标签。另外,当你想删除列时,你需要提供参数axis=1:

>>> df = df.drop(labels='age', axis=1)
>>> df
 name         city  py-score  django-score  js-score
10  Xavier  Mexico City      88.0          86.0      71.0
11     Ann      Toronto      79.0          81.0      95.0
12    Jana       Prague      81.0          78.0      88.0
13      Yi     Shanghai      80.0          88.0      79.0
14   Robin   Manchester      68.0          74.0      91.0
15    Amal        Cairo      61.0          70.0      91.0
16    Nori        Osaka      84.0          81.0      80.0

您已经从数据框架中删除了列age

默认情况下,.drop()返回没有指定列的数据帧,除非您通过了inplace=True

Remove ads

应用算术运算

您可以对熊猫SeriesDataFrame对象应用基本的算术运算,例如加、减、乘、除,就像您对 NumPy 数组所做的一样:

>>> df['py-score'] + df['js-score']
10    159.0
11    174.0
12    169.0
13    159.0
14    159.0
15    152.0
16    164.0
dtype: float64

>>> df['py-score'] / 100
10    0.88
11    0.79
12    0.81
13    0.80
14    0.68
15    0.61
16    0.84
Name: py-score, dtype: float64

您可以使用这种技术向 Pandas 数据框架中插入一个新列。例如,尝试将total分数计算为候选人的 Python、Django 和 JavaScript 分数的线性组合:

>>> df['total'] =\
...     0.4 * df['py-score'] + 0.3 * df['django-score'] + 0.3 * df['js-score']
>>> df
 name         city  py-score  django-score  js-score  total
10  Xavier  Mexico City      88.0          86.0      71.0   82.3
11     Ann      Toronto      79.0          81.0      95.0   84.4
12    Jana       Prague      81.0          78.0      88.0   82.2
13      Yi     Shanghai      80.0          88.0      79.0   82.1
14   Robin   Manchester      68.0          74.0      91.0   76.7
15    Amal        Cairo      61.0          70.0      91.0   72.7
16    Nori        Osaka      84.0          81.0      80.0   81.9

现在,您的数据框架中有一列是根据您的考生个人考试成绩计算的total分数。更棒的是,你只用一句话就做到了!

应用 NumPy 和 SciPy 函数

大多数 NumPy 和 SciPy 例程可以作为参数而不是 NumPy 数组应用于 Pandas SeriesDataFrame对象。为了说明这一点,您可以使用 NumPy 例程 numpy.average() 计算考生的总成绩。

您将传递您的熊猫数据帧的一部分,而不是传递一个 NumPy 数组给numpy.average():

>>> import numpy as np

>>> score = df.iloc[:, 2:5]
>>> score
 py-score  django-score  js-score
10      88.0          86.0      71.0
11      79.0          81.0      95.0
12      81.0          78.0      88.0
13      80.0          88.0      79.0
14      68.0          74.0      91.0
15      61.0          70.0      91.0
16      84.0          81.0      80.0

>>> np.average(score, axis=1,
...            weights=[0.4, 0.3, 0.3])
array([82.3, 84.4, 82.2, 82.1, 76.7, 72.7, 81.9])

变量score现在指的是带有 Python、Django 和 JavaScript 分数的数据帧。您可以使用score作为numpy.average()的参数,并获得具有指定权重的列的线性组合。

但这还不是全部!可以使用average()返回的 NumPy 数组作为df的新列。首先,从df中删除现有的列total,然后使用average()添加新列:

>>> del df['total']
>>> df
 name         city  py-score  django-score  js-score
10  Xavier  Mexico City      88.0          86.0      71.0
11     Ann      Toronto      79.0          81.0      95.0
12    Jana       Prague      81.0          78.0      88.0
13      Yi     Shanghai      80.0          88.0      79.0
14   Robin   Manchester      68.0          74.0      91.0
15    Amal        Cairo      61.0          70.0      91.0
16    Nori        Osaka      84.0          81.0      80.0

>>> df['total'] = np.average(df.iloc[:, 2:5], axis=1,
...                          weights=[0.4, 0.3, 0.3])
>>> df
 name         city  py-score  django-score  js-score  total
10  Xavier  Mexico City      88.0          86.0      71.0   82.3
11     Ann      Toronto      79.0          81.0      95.0   84.4
12    Jana       Prague      81.0          78.0      88.0   82.2
13      Yi     Shanghai      80.0          88.0      79.0   82.1
14   Robin   Manchester      68.0          74.0      91.0   76.7
15    Amal        Cairo      61.0          70.0      91.0   72.7
16    Nori        Osaka      84.0          81.0      80.0   81.9

结果与上一个示例相同,但是这里使用了现有的 NumPy 函数,而不是编写自己的代码。

排序熊猫数据帧

可以用 .sort_values() 对熊猫数据帧进行排序:

>>> df.sort_values(by='js-score', ascending=False)
 name         city  py-score  django-score  js-score  total
11     Ann      Toronto      79.0          81.0      95.0   84.4
14   Robin   Manchester      68.0          74.0      91.0   76.7
15    Amal        Cairo      61.0          70.0      91.0   72.7
12    Jana       Prague      81.0          78.0      88.0   82.2
16    Nori        Osaka      84.0          81.0      80.0   81.9
13      Yi     Shanghai      80.0          88.0      79.0   82.1
10  Xavier  Mexico City      88.0          86.0      71.0   82.3

此示例根据列js-score中的值对数据帧进行排序。参数by设置排序所依据的行或列的标签。ascending指定是要按升序(True)还是降序(False)排序,后者是默认设置。您可以通过axis来选择是要对行(axis=0)还是列(axis=1)进行排序。

如果您想按多列排序,那么只需将列表作为参数传递给byascending:

>>> df.sort_values(by=['total', 'py-score'], ascending=[False, False])
 name         city  py-score  django-score  js-score  total
11     Ann      Toronto      79.0          81.0      95.0   84.4
10  Xavier  Mexico City      88.0          86.0      71.0   82.3
12    Jana       Prague      81.0          78.0      88.0   82.2
13      Yi     Shanghai      80.0          88.0      79.0   82.1
16    Nori        Osaka      84.0          81.0      80.0   81.9
14   Robin   Manchester      68.0          74.0      91.0   76.7
15    Amal        Cairo      61.0          70.0      91.0   72.7

在这种情况下DataFrame 按列total排序,但如果两个值相同,则它们的顺序由列py-score中的值决定。

可选参数inplace也可以和.sort_values()一起使用。它默认设置为False,确保.sort_values()返回一个新的熊猫数据帧。当您设置inplace=True时,现有的数据帧将被修改,并且.sort_values()将返回None

如果您曾经尝试过在 Excel 中对值进行排序,那么您可能会发现 Pandas 方法更加高效和方便。当你有大量的数据时,熊猫可以明显胜过 Excel。

有关 Pandas 中排序的更多信息,请查看 Pandas Sort:您的 Python 数据排序指南

Remove ads

过滤数据

数据过滤是熊猫的另一个强大功能。它的工作方式类似于 NumPy 中使用布尔数组的索引。

如果你在一个Series对象上应用一些逻辑运算,那么你将得到另一个具有布尔值TrueFalse的序列:

>>> filter_ = df['django-score'] >= 80
>>> filter_
10     True
11     True
12    False
13     True
14    False
15    False
16     True
Name: django-score, dtype: bool

在这种情况下,df['django-score'] >= 80为 Django 得分大于或等于 80 的那些行返回True。对于 Django 得分小于 80 的行,它返回False

现在,您已经用布尔数据填充了序列filter_。表达式df[filter_]返回一个熊猫数据帧,其中来自df的行对应于filter_中的True:

>>> df[filter_]
 name         city  py-score  django-score  js-score  total
10  Xavier  Mexico City      88.0          86.0      71.0   82.3
11     Ann      Toronto      79.0          81.0      95.0   84.4
13      Yi     Shanghai      80.0          88.0      79.0   82.1
16    Nori        Osaka      84.0          81.0      80.0   81.9

如您所见,filter_[10]filter_[11]filter_[13]filter_[16]True,因此df[filter_]包含带有这些标签的行。另一方面,filter_[12]filter_[14]filter_[15]False,所以相应的行不会出现在df[filter_]中。

通过将逻辑运算与以下运算符相结合,可以创建非常强大和复杂的表达式:

  • NOT ( ~
  • AND ( &
  • OR ( |
  • XOR ( ^

例如,您可以得到一个候选数据帧,其py-scorejs-score大于或等于 80:

>>> df[(df['py-score'] >= 80) & (df['js-score'] >= 80)]
 name    city  py-score  django-score  js-score  total
12  Jana  Prague      81.0          78.0      88.0   82.2
16  Nori   Osaka      84.0          81.0      80.0   81.9

表达式(df['py-score'] >= 80) & (df['js-score'] >= 80)返回一个序列,其中py-scorejs-score都大于或等于 80False在其他行中。在这种情况下,只有带有标签1216的行满足这两个条件。

也可以应用 NumPy 逻辑例程来代替运算符。

对于一些需要数据过滤的操作,使用 .where() 更方便。它会替换不满足所提供条件的位置中的值:

>>> df['django-score'].where(cond=df['django-score'] >= 80, other=0.0)
10    86.0
11    81.0
12     0.0
13    88.0
14     0.0
15     0.0
16    81.0
Name: django-score, dtype: float64

在这个例子中,条件是df['django-score'] >= 80。当条件为True时,调用.where()的数据帧或序列的值将保持不变,当条件为False时,将被替换为other(在本例中为0.0)的值。

确定数据统计

Pandas 为数据框提供了许多统计方法。通过 .describe() 可以得到熊猫数据帧数值列的基本统计数据:

>>> df.describe()
 py-score  django-score   js-score      total
count   7.000000      7.000000   7.000000   7.000000
mean   77.285714     79.714286  85.000000  80.328571
std     9.446592      6.343350   8.544004   4.101510
min    61.000000     70.000000  71.000000  72.700000
25%    73.500000     76.000000  79.500000  79.300000
50%    80.000000     81.000000  88.000000  82.100000
75%    82.500000     83.500000  91.000000  82.250000
max    88.000000     88.000000  95.000000  84.400000

这里,.describe()返回一个新的 DataFrame其行数由count表示,还包括列的平均值、标准差、最小值、最大值和四分位数。

如果您想要获得某些或所有列的特定统计信息,那么您可以调用诸如 .mean().std() 之类的方法:

>>> df.mean()
py-score        77.285714
django-score    79.714286
js-score        85.000000
total           80.328571
dtype: float64

>>> df['py-score'].mean()
77.28571428571429

>>> df.std()
py-score        9.446592
django-score    6.343350
js-score        8.544004
total           4.101510
dtype: float64

>>> df['py-score'].std()
9.446591726019244

当应用于 Pandas 数据框架时,这些方法返回包含每列结果的序列。当应用于一个Series对象或数据帧的一列时,这些方法返回标量

要了解关于熊猫的统计计算的更多信息,请查看使用 Python 的描述性统计NumPy、SciPy 和 Pandas:与 Python 的相关性

Remove ads

处理缺失数据

缺失数据在数据科学和机器学习中非常普遍。但是不要害怕Pandas 拥有非常强大的处理缺失数据的功能。事实上,它的文档中有整整一节专门用来处理丢失的数据。

Pandas 通常用 NaN(非数字)值 表示缺失数据。在 Python 中,可以用 float('nan')math.nan ,或者 numpy.nan 得到 NaN。从熊猫 1.0 开始,较新的类型如 BooleanDtypeInt8DtypeInt16DtypeInt32DtypeInt64Dtype 使用pandas.NA作为缺失值。

以下是一个缺失值的熊猫数据帧示例:

>>> df_ = pd.DataFrame({'x': [1, 2, np.nan, 4]})
>>> df_
 x
0  1.0
1  2.0
2  NaN
3  4.0

变量df_是指具有一列、x和四个值的数据帧。第三个值是nan,默认情况下被认为是缺失的。

用缺失数据计算

许多熊猫方法在执行计算时省略了nan值,除非它们被明确指示而不是去:

>>> df_.mean()
x    2.333333
dtype: float64

>>> df_.mean(skipna=False)
x   NaN
dtype: float64

在第一个示例中,df_.mean()计算平均值时不考虑NaN(第三个值)。它只取1.02.04.0并返回它们的平均值,即 2.33。

但是,如果您使用skipna=False指示.mean()不要跳过nan值,那么它会考虑这些值,如果数据中有任何丢失的值,它会返回nan

填充缺失数据

Pandas 有几个选项可以用其他值来填充或替换缺失的值。最方便的方法是 .fillna() 。您可以用它来替换缺少的值:

  • 指定值
  • 缺失值以上的值
  • 低于缺失值的值

以下是如何应用上述选项的方法:

>>> df_.fillna(value=0)
 x
0  1.0
1  2.0
2  0.0
3  4.0

>>> df_.fillna(method='ffill')
 x
0  1.0
1  2.0
2  2.0
3  4.0

>>> df_.fillna(method='bfill')
 x
0  1.0
1  2.0
2  4.0
3  4.0

在第一个例子中,.fillna(value=0)0.0替换丢失的值T1 是用value指定的。在第二个例子中,.fillna(method='ffill')用它上面的值替换丢失的值,这个值就是2.0。在第三个示例中,.fillna(method='bfill')使用的值低于缺失值,即4.0

另一个流行的选项是应用 插值 ,用插值替换缺失值。你可以用 .interpolate() 来做这件事:

>>> df_.interpolate()
 x
0  1.0
1  2.0
2  3.0
3  4.0

如您所见,.interpolate()用插值替换了缺失的值。

您也可以将可选参数inplace.fillna()一起使用。这样做将:

  • inplace=False时创建并返回一个新的数据帧
  • 修改现有数据帧并在inplace=True时返回None

inplace的默认设置是False。然而,当您处理大量数据并希望防止不必要的低效复制时,inplace=True会非常有用。

Remove ads

删除丢失数据的行和列

在某些情况下,您可能希望删除缺少值的行甚至列。你可以用 .dropna() 来做这件事:

>>> df_.dropna()
 x
0  1.0
1  2.0
3  4.0

在这种情况下,.dropna()只是删除带有nan的行,包括它的标签。它还有可选参数inplace,其行为与.fillna().interpolate()相同。

迭代熊猫数据帧

正如您之前所学的,数据帧的行和列标签可以作为带有.index.columns的序列来检索。您可以使用此功能迭代标签并获取或设置数据值。然而Pandas 提供了几种更方便的迭代方法:

使用.items().iteritems(),您可以迭代熊猫数据帧的列。每次迭代都会产生一个元组,其中列名和列数据作为一个Series对象:

>>> for col_label, col in df.iteritems():
...     print(col_label, col, sep='\n', end='\n\n')
...
name
10    Xavier
11       Ann
12      Jana
13        Yi
14     Robin
15      Amal
16      Nori
Name: name, dtype: object

city
10    Mexico City
11        Toronto
12         Prague
13       Shanghai
14     Manchester
15          Cairo
16          Osaka
Name: city, dtype: object

py-score
10    88.0
11    79.0
12    81.0
13    80.0
14    68.0
15    61.0
16    84.0
Name: py-score, dtype: float64

django-score
10    86.0
11    81.0
12    78.0
13    88.0
14    74.0
15    70.0
16    81.0
Name: django-score, dtype: float64

js-score
10    71.0
11    95.0
12    88.0
13    79.0
14    91.0
15    91.0
16    80.0
Name: js-score, dtype: float64

total
10    82.3
11    84.4
12    82.2
13    82.1
14    76.7
15    72.7
16    81.9
Name: total, dtype: float64

.items().iteritems()就是这么用的。

使用.iterrows(),您可以迭代熊猫数据帧的行。每次迭代都会产生一个元组,其中包含行名和行数据,作为一个Series对象:

>>> for row_label, row in df.iterrows():
...     print(row_label, row, sep='\n', end='\n\n')
...
10
name                 Xavier
city            Mexico City
py-score                 88
django-score             86
js-score                 71
total                  82.3
Name: 10, dtype: object

11
name                Ann
city            Toronto
py-score             79
django-score         81
js-score             95
total              84.4
Name: 11, dtype: object

12
name              Jana
city            Prague
py-score            81
django-score        78
js-score            88
total             82.2
Name: 12, dtype: object

13
name                  Yi
city            Shanghai
py-score              80
django-score          88
js-score              79
total               82.1
Name: 13, dtype: object

14
name                 Robin
city            Manchester
py-score                68
django-score            74
js-score                91
total                 76.7
Name: 14, dtype: object

15
name             Amal
city            Cairo
py-score           61
django-score       70
js-score           91
total            72.7
Name: 15, dtype: object

16
name             Nori
city            Osaka
py-score           84
django-score       81
js-score           80
total            81.9
Name: 16, dtype: object

.iterrows()就是这么用的。

类似地,.itertuples()对行进行迭代,并且在每次迭代中产生一个命名元组,该元组具有(可选的)索引和数据:

>>> for row in df.loc[:, ['name', 'city', 'total']].itertuples():
...     print(row)
...
Pandas(Index=10, name='Xavier', city='Mexico City', total=82.3)
Pandas(Index=11, name='Ann', city='Toronto', total=84.4)
Pandas(Index=12, name='Jana', city='Prague', total=82.19999999999999)
Pandas(Index=13, name='Yi', city='Shanghai', total=82.1)
Pandas(Index=14, name='Robin', city='Manchester', total=76.7)
Pandas(Index=15, name='Amal', city='Cairo', total=72.7)
Pandas(Index=16, name='Nori', city='Osaka', total=81.9)

可以用参数name指定命名元组的名称,默认设置为'Pandas'。您还可以指定是否包含带有index的行标签,默认设置为True

使用时间序列

熊猫擅长处理时间序列。尽管这个功能部分基于 NumPy 日期时间和时间增量Pandas 提供了更多的灵活性。

创建带有时间序列标签的数据帧

在本节中,您将使用一天中每小时的温度数据创建一个熊猫数据帧。

您可以首先创建一个包含数据值的列表(或元组、NumPy 数组或其他数据类型),这些数据值将是以摄氏度给出的每小时温度:

>>> temp_c = [ 8.0,  7.1,  6.8,  6.4,  6.0,  5.4,  4.8,  5.0,
...            9.1, 12.8, 15.3, 19.1, 21.2, 22.1, 22.4, 23.1,
...           21.0, 17.9, 15.5, 14.4, 11.9, 11.0, 10.2,  9.1]

现在您有了变量temp_c,它引用了温度值的列表。

下一步是创建一个日期和时间序列。熊猫提供了一个非常方便的功能, date_range() ,为此:

>>> dt = pd.date_range(start='2019-10-27 00:00:00.0', periods=24,
...                    freq='H')
>>> dt
DatetimeIndex(['2019-10-27 00:00:00', '2019-10-27 01:00:00',
 '2019-10-27 02:00:00', '2019-10-27 03:00:00',
 '2019-10-27 04:00:00', '2019-10-27 05:00:00',
 '2019-10-27 06:00:00', '2019-10-27 07:00:00',
 '2019-10-27 08:00:00', '2019-10-27 09:00:00',
 '2019-10-27 10:00:00', '2019-10-27 11:00:00',
 '2019-10-27 12:00:00', '2019-10-27 13:00:00',
 '2019-10-27 14:00:00', '2019-10-27 15:00:00',
 '2019-10-27 16:00:00', '2019-10-27 17:00:00',
 '2019-10-27 18:00:00', '2019-10-27 19:00:00',
 '2019-10-27 20:00:00', '2019-10-27 21:00:00',
 '2019-10-27 22:00:00', '2019-10-27 23:00:00'],
 dtype='datetime64[ns]', freq='H')

date_range()接受您用来指定范围的开始或结束、周期数、频率、时区等等的参数。

**注:**虽然也有其他选项,但熊猫默认大多使用 ISO 8601 日期和时间格式

现在您已经有了温度值以及相应的日期和时间,您可以创建数据帧了。在许多情况下,使用日期时间值作为行标签很方便:

>>> temp = pd.DataFrame(data={'temp_c': temp_c}, index=dt)
>>> temp
 temp_c
2019-10-27 00:00:00     8.0
2019-10-27 01:00:00     7.1
2019-10-27 02:00:00     6.8
2019-10-27 03:00:00     6.4
2019-10-27 04:00:00     6.0
2019-10-27 05:00:00     5.4
2019-10-27 06:00:00     4.8
2019-10-27 07:00:00     5.0
2019-10-27 08:00:00     9.1
2019-10-27 09:00:00    12.8
2019-10-27 10:00:00    15.3
2019-10-27 11:00:00    19.1
2019-10-27 12:00:00    21.2
2019-10-27 13:00:00    22.1
2019-10-27 14:00:00    22.4
2019-10-27 15:00:00    23.1
2019-10-27 16:00:00    21.0
2019-10-27 17:00:00    17.9
2019-10-27 18:00:00    15.5
2019-10-27 19:00:00    14.4
2019-10-27 20:00:00    11.9
2019-10-27 21:00:00    11.0
2019-10-27 22:00:00    10.2
2019-10-27 23:00:00     9.1

就是这样!您已经创建了一个包含时间序列数据和日期时间行索引的数据框架。

Remove ads

分度和切片

一旦有了包含时间序列数据的 Pandas 数据框架,您就可以方便地应用切片来获得部分信息:

>>> temp['2019-10-27 05':'2019-10-27 14']
 temp_c
2019-10-27 05:00:00     5.4
2019-10-27 06:00:00     4.8
2019-10-27 07:00:00     5.0
2019-10-27 08:00:00     9.1
2019-10-27 09:00:00    12.8
2019-10-27 10:00:00    15.3
2019-10-27 11:00:00    19.1
2019-10-27 12:00:00    21.2
2019-10-27 13:00:00    22.1
2019-10-27 14:00:00    22.4

此示例显示了如何提取 05:00 和 14:00(上午 5 点和下午 2 点)之间的温度。尽管您已经提供了字符串,但 Pandas 知道您的行标签是日期-时间值,并将字符串解释为日期和时间。

重采样和滚动

您已经看到了如何组合日期-时间行标签,并使用切片从时间序列数据中获取您需要的信息。这只是开始。越来越好了!

如果您想将一天分成四个六小时的间隔并获得每个间隔的平均温度那么您只需要一个语句就可以做到。Pandas 提供了 .resample() 的方法,可以和其他方法结合使用,比如.mean():

>>> temp.resample(rule='6h').mean()
 temp_c
2019-10-27 00:00:00   6.616667
2019-10-27 06:00:00  11.016667
2019-10-27 12:00:00  21.283333
2019-10-27 18:00:00  12.016667

您现在有了一个新的包含四行的 Pandas 数据框架。每一行对应一个六小时的时间间隔。例如,数值6.616667是数据帧temp中前六个温度的平均值,而12.016667是后六个温度的平均值。

代替.mean(),您可以应用.min().max()来获得每个间隔的最低和最高温度。您还可以使用.sum()来获得数据值的总和,尽管在处理温度时这些信息可能没有用。

你可能还需要做一些滚动窗口分析。这包括计算指定数量的相邻行的统计数据,这些相邻行构成了您的数据窗口。您可以通过选择一组不同的相邻行来执行计算,从而“滚动”窗口。

第一个窗口从数据帧中的第一行开始,包括指定数量的相邻行。然后将窗口向下移动一行,删除第一行并添加紧接在最后一行之后的一行,并再次计算相同的统计数据。重复这个过程,直到到达数据帧的最后一行。

熊猫为此提供了方法 .rolling() :

>>> temp.rolling(window=3).mean()
 temp_c
2019-10-27 00:00:00        NaN
2019-10-27 01:00:00        NaN
2019-10-27 02:00:00   7.300000
2019-10-27 03:00:00   6.766667
2019-10-27 04:00:00   6.400000
2019-10-27 05:00:00   5.933333
2019-10-27 06:00:00   5.400000
2019-10-27 07:00:00   5.066667
2019-10-27 08:00:00   6.300000
2019-10-27 09:00:00   8.966667
2019-10-27 10:00:00  12.400000
2019-10-27 11:00:00  15.733333
2019-10-27 12:00:00  18.533333
2019-10-27 13:00:00  20.800000
2019-10-27 14:00:00  21.900000
2019-10-27 15:00:00  22.533333
2019-10-27 16:00:00  22.166667
2019-10-27 17:00:00  20.666667
2019-10-27 18:00:00  18.133333
2019-10-27 19:00:00  15.933333
2019-10-27 20:00:00  13.933333
2019-10-27 21:00:00  12.433333
2019-10-27 22:00:00  11.033333
2019-10-27 23:00:00  10.100000

现在,您有了一个数据框架,其中包含为几个三小时窗口计算的平均温度。参数window指定移动时间窗口的大小。

在上例中,第三个值(7.3)是前三个小时的平均温度(00:00:0001:00:0002:00:00)。第四个值是02:00:0003:00:0004:00:00小时的平均温度。最后一个值是最近三个小时的平均温度,21:00:0022:00:0023:00:00。前两个值丢失了,因为没有足够的数据来计算它们。

用熊猫绘制数据帧

Pandas 允许你可视化数据基于数据帧创建图表。它在后台使用 Matplotlib ,因此开发 Pandas 的绘图功能与使用 Matplotlib 非常相似。

如果你想显示这些图,那么你首先需要导入matplotlib.pyplot:

>>> import matplotlib.pyplot as plt

现在您可以使用 pandas.DataFrame.plot() 来创建情节,使用 plt.show() 来显示情节:

>>> temp.plot()
<matplotlib.axes._subplots.AxesSubplot object at 0x7f070cd9d950>
>>> plt.show()

现在.plot()返回一个plot对象,如下所示:

mmst-pandas-df-5

你也可以应用 .plot.line() ,得到同样的结果。.plot().plot.line()都有许多可选参数,您可以使用它们来指定您的绘图外观。其中一些被直接传递给底层的 Matplotlib 方法。

您可以通过链接方法.get_figure().savefig() 来保存您的体形:

>>> temp.plot().get_figure().savefig('temperatures.png')

该语句创建绘图,并将其保存为工作目录中名为'temperatures.png'的文件。

你可以用熊猫数据框得到其他类型的图。例如,您可以将之前的求职者数据可视化为带有 .plot.hist()直方图:

>>> df.loc[:, ['py-score', 'total']].plot.hist(bins=5, alpha=0.4)
<matplotlib.axes._subplots.AxesSubplot object at 0x7f070c69edd0>
>>> plt.show()

在本例中,您将提取 Python 测试分数和总分数据,并使用直方图对其进行可视化。结果图如下所示:

mmst-pandas-df-6

这只是基本的样子。您可以使用可选参数调整细节,包括.plot.hist()Matplotlib 的plt.rcParams等。你可以在 Matplotlib 的剖析中找到详细的解释。

延伸阅读

Pandas 数据帧是非常全面的对象,支持本教程中没有提到的许多操作。其中包括:

官方熊猫教程很好地总结了一些可用的选项。如果你想了解更多关于熊猫和数据框,那么你可以看看这些教程:

你已经知道熊猫数据帧处理二维数据。如果您需要处理二维以上的标注数据,可以查看另一个强大的数据科学 Python 库【xarray】,它的功能与 Pandas 非常相似。

如果你在处理大数据,想要一个类似数据框架的体验,那么你可以给 Dask 一个机会,使用它的数据框架 API 。一个 Dask 数据帧包含许多 Pandas 数据帧,并以一种懒惰的方式执行计算。

结论

现在你知道了什么是 Pandas DataFrame ,它的一些特性是什么,以及如何使用它来有效地处理数据。熊猫数据框架是功能强大、用户友好的数据结构,您可以使用它来更深入地了解您的数据集!

在本教程中,您已经学习了:

  • 什么是熊猫数据框架以及如何创建一个
  • 如何访问、修改、添加、排序、过滤和删除数据
  • 如何对数据帧使用 NumPy 例程
  • 如何处理缺失值
  • 如何处理时序数据
  • 如何可视化包含在数据帧中的数据

您已经学习了足够多的知识来涵盖数据框架的基础知识。如果你想更深入地了解如何使用 Python 中的数据,那么请查看的熊猫教程

如果你有任何问题或意见,请写在下面的评论区。

立即观看本教程有真实 Python 团队创建的相关视频课程。与书面教程一起观看,加深您的理解: 熊猫数据帧:高效处理数据*********