69 KiB
熊猫数据框架:让数据工作变得愉快
*立即观看**本教程有真实 Python 团队创建的相关视频课程。与书面教程一起观看,加深您的理解: 熊猫数据帧:高效处理数据
熊猫数据帧 是一个结构,包含二维数据及其对应的标签。数据帧广泛应用于数据科学、机器学习、科学计算以及其他许多数据密集型领域。
数据帧类似于 SQL 表或您在 Excel 或 Calc 中使用的电子表格。在许多情况下,数据帧比表格或电子表格更快、更容易使用、更强大,因为它们是 Python 和 NumPy 生态系统不可或缺的一部分。
在本教程中,您将学习:
- 什么是熊猫数据框架以及如何创建一个
- 如何访问、修改、添加、排序、过滤和删除数据
- 如何处理缺失值
- 如何处理时序数据
- 如何快速可视化数据
是时候开始使用熊猫数据框架了!
免费奖励: 掌握 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 |
在该表中,第一行包含列标签 ( name、city、age和py-score)。第一列包含行标签 ( 101、102等等)。所有其他单元格用数据值填充。
现在,您已经拥有了创建熊猫数据框架所需的一切。
创建熊猫数据框架有几种方法。在大多数情况下,您将使用 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指的是包含行标签的列表,这些标签是从101到107的数字。
现在,您已经准备好创建熊猫数据框架了:
>>> 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 数据框架看起来就像上面的候选表,具有以下特征:
- 从
101到107的行标签 - 列标签,如
'name'、'city'、'age'、'py-score' - 数据,如考生姓名、城市、年龄和 Python 考试成绩
该图显示了来自df的标签和数据:
行标签用蓝色标出,而列标签用红色标出,数据值用紫色标出。
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'相对应的列,其中包含了所有求职者的位置。
请注意,您已经提取了数据和相应的行标签,这一点很重要:
熊猫数据帧的每一列都是 pandas.Series 的一个实例,这是一个保存一维数据及其标签的结构。您可以像使用字典一样获得一个Series对象的单个项目,方法是使用它的标签作为一个键:
>>> cities[102]
'Toronto'
在这种情况下,'Toronto'是数据值,102是相应的标签。正如你将在后面的章节中看到的,还有其他方法可以在熊猫数据帧中获得特定的项目。
>>> df.loc[103]
name Jana
city Prague
age 33
py-score 81
Name: 103, dtype: object
这一次,您已经提取了对应于标签103的行,其中包含名为Jana的候选人的数据。除了该行中的数据值,您还提取了相应列的标签:
返回的行也是pandas.Series的实例。
创建熊猫数据框架
如前所述,创建熊猫数据框有几种方法。在本节中,您将学习如何使用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
如您所见,您已经指定了行标签100、200和300。您还强制了列的顺序:z、y、x。
用列表创建熊猫数据框架
创建熊猫数据框架的另一种方法是使用字典列表:
>>> 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
这就是如何使用嵌套列表创建熊猫数据框架。也可以用同样的方式使用元组列表。为此,只需用元组替换上例中的嵌套列表。
用 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.csv的 CSV 文件:
,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物体的大小
作为序列的熊猫数据帧标签
可以用 .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() 来生成一个新的行标签序列,其中包含从10到16的整数。要了解更多关于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 的数据:
Pandas 文档建议使用.to_numpy(),因为两个可选参数提供了灵活性:
dtype: 使用该参数指定结果数组的数据类型。默认设置为None。copy: 如果想使用数据帧中的原始数据,将该参数设置为False。如果你想复制数据,将其设置为True。
不过.values比.to_numpy()存在的时间要长得多,后者是在熊猫 0.24.0 版本中引入的。这意味着你可能会更频繁地看到.values,尤其是在旧代码中。
数据类型
数据值的类型,也称为数据类型或数据类型**,非常重要,因为它们决定了数据帧使用的内存量,以及它的计算速度和精度水平。**
Pandas 非常依赖于 NumPy 数据类型。然而,熊猫 1.0 引入了一些额外的类型:
- **
BooleanDtype****BooleanArray**支持缺失布尔值和克莱尼三值逻辑。 StringDtype和StringArray代表一个专用的字符串类型。
用 .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中的列age和py-score的数据类型都是int64,表示 64 位(或 8 字节)整数。然而,df_也提供了一种更小的 32 位(4 字节)整数数据类型,称为int32。
熊猫数据帧大小
属性 .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。
在上面的例子中,最后两列age和py-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对象。
熊猫总共有四个访问者:
-
.loc[]接受行和列的标签并返回系列或数据帧。您可以使用它来获取整行或整列,以及它们的各个部分。 -
.iloc[]接受行和列的从零开始的索引,并返回系列或数据帧。您可以使用它来获取整行或整列,或者它们的一部分。 -
.at[]接受行和列的标签并返回单个数据值。 -
.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 中的分级或多级索引。
在本例中,您使用:
- 切片得到标签为
11到15的行,相当于索引1到5 - 列出得到列
name和city,相当于索引0和1
两条语句都返回一个 Pandas 数据帧,该数据帧具有所需的五行和两列的交集。
这就引出了.loc[]和.iloc[]之间一个非常重要的区别。正如您在前面的例子中看到的,当您将行标签11:15传递给.loc[]时,您得到了从11到15的行。然而,当您传递行索引1:6到.iloc[]时,您只获得索引为1到5的行。
只获得索引1到5的原因是,对于.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[]来使用它的列和行索引检索相同的名称。
用存取器设置数据
您可以使用访问器通过传递 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中的前四项(行10到13)。使用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-score的df。与字典的另一个相似之处是能够使用 .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。
应用算术运算
您可以对熊猫Series和DataFrame对象应用基本的算术运算,例如加、减、乘、除,就像您对 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 Series或DataFrame对象。为了说明这一点,您可以使用 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)进行排序。
如果您想按多列排序,那么只需将列表作为参数传递给by和ascending:
>>> 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 数据排序指南。
过滤数据
数据过滤是熊猫的另一个强大功能。它的工作方式类似于 NumPy 中使用布尔数组的索引。
如果你在一个Series对象上应用一些逻辑运算,那么你将得到另一个具有布尔值True和False的序列:
>>> 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-score和js-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-score和js-score都大于或等于 80,而False在其他行中。在这种情况下,只有带有标签12和16的行满足这两个条件。
也可以应用 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 的相关性。
处理缺失数据
缺失数据在数据科学和机器学习中非常普遍。但是不要害怕!Pandas 拥有非常强大的处理缺失数据的功能。事实上,它的文档中有整整一节专门用来处理丢失的数据。
Pandas 通常用 NaN(非数字)值 表示缺失数据。在 Python 中,可以用 float('nan') 、 math.nan ,或者 numpy.nan 得到 NaN。从熊猫 1.0 开始,较新的类型如 BooleanDtype 、 Int8Dtype 、 Int16Dtype 、 Int32Dtype 、 Int64Dtype 使用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.0、2.0和4.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会非常有用。
删除丢失数据的行和列
在某些情况下,您可能希望删除缺少值的行甚至列。你可以用 .dropna() 来做这件事:
>>> df_.dropna()
x
0 1.0
1 2.0
3 4.0
在这种情况下,.dropna()只是删除带有nan的行,包括它的标签。它还有可选参数inplace,其行为与.fillna()和.interpolate()相同。
迭代熊猫数据帧
正如您之前所学的,数据帧的行和列标签可以作为带有.index和.columns的序列来检索。您可以使用此功能迭代标签,并获取或设置数据值。然而,Pandas 提供了几种更方便的迭代方法:
.items()对列进行迭代.iteritems()对列进行迭代.iterrows()对行进行迭代.itertuples()对行进行迭代,得到命名的元组
使用.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
就是这样!您已经创建了一个包含时间序列数据和日期时间行索引的数据框架。
分度和切片
一旦有了包含时间序列数据的 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:00、01:00:00和02:00:00)。第四个值是02:00:00、03:00:00和04:00:00小时的平均温度。最后一个值是最近三个小时的平均温度,21:00:00、22:00:00和23: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对象,如下所示:
你也可以应用 .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 测试分数和总分数据,并使用直方图对其进行可视化。结果图如下所示:
这只是基本的样子。您可以使用可选参数调整细节,包括.plot.hist()、 Matplotlib 的plt.rcParams、等。你可以在 Matplotlib 的剖析中找到详细的解释。
延伸阅读
Pandas 数据帧是非常全面的对象,支持本教程中没有提到的许多操作。其中包括:
官方熊猫教程很好地总结了一些可用的选项。如果你想了解更多关于熊猫和数据框,那么你可以看看这些教程:
- 用 Pandas 和 NumPy 清理 Pythonic 数据
- 熊猫数据帧 101
- 介绍熊猫和文森特
- 蟒蛇熊猫:诡计&你可能不知道的特点
- 地道的熊猫:把戏&你可能不知道的特点
- 阅读熊猫 CSVs】
- 用熊猫写 CSVs】
- 用 Python 读写 CSV 文件
- 读写 CSV 文件
- 用熊猫读取 Python 中的大型 Excel 文件
- 快速、灵活、简单和直观:如何加快您的熊猫项目
你已经知道熊猫数据帧处理二维数据。如果您需要处理二维以上的标注数据,可以查看另一个强大的数据科学 Python 库【xarray】,它的功能与 Pandas 非常相似。
如果你在处理大数据,想要一个类似数据框架的体验,那么你可以给 Dask 一个机会,使用它的数据框架 API 。一个 Dask 数据帧包含许多 Pandas 数据帧,并以一种懒惰的方式执行计算。
结论
现在你知道了什么是 Pandas DataFrame ,它的一些特性是什么,以及如何使用它来有效地处理数据。熊猫数据框架是功能强大、用户友好的数据结构,您可以使用它来更深入地了解您的数据集!
在本教程中,您已经学习了:
- 什么是熊猫数据框架以及如何创建一个
- 如何访问、修改、添加、排序、过滤和删除数据
- 如何对数据帧使用 NumPy 例程
- 如何处理缺失值
- 如何处理时序数据
- 如何可视化包含在数据帧中的数据
您已经学习了足够多的知识来涵盖数据框架的基础知识。如果你想更深入地了解如何使用 Python 中的数据,那么请查看的熊猫教程。
如果你有任何问题或意见,请写在下面的评论区。
立即观看本教程有真实 Python 团队创建的相关视频课程。与书面教程一起观看,加深您的理解: 熊猫数据帧:高效处理数据*********





