本文将主要介绍以下内容:
1. DataFrame概述
2. Series和DataFrame的相似点
3. DataFrame排序
4. 按DataFrame索引排序
5. 设置新索引
6. 从DataFrame读取列
7. 从DataFrame读取行
8. 重命名列或行
9. 重置索引
DataFrame是Pandas的另外一个主要的数据结构,它是由行和列组成的二维数据结构,因此需要两个参考点来从数据集中提取给定值。
1. DataFrame概述
DataFrame可以描述为网格或数据表,类似于Excel之类的电子表格中的网格或数据表。
1.1 从字典创建DataFrame
和往常一样,让我们从导入pandas开始,还将使用NumPy库生成一些随机数据:
In [1]: import pandas as pd
import numpy as np
在导入第一个数据集之前,让我们练习从一些Python内置对象实例化一个DataFrame。例如字典,其键将用作列名,而相应的值将用作该列的值。
下例使用三个长度相等的列表来存储城市,国家和人口。也可以使用其它可迭代对象(如元组或Series)代替列表。DataFrame类的第一个参数data代表数据源。
In [2]: city_data = {
"City": ["New York City", "Paris", "Barcelona", "Rome"],
"Country": ["United States", "France", "Spain", "Italy"],
"Population": [8600000, 2141000, 5515000, 2873000]
}
cities = pd.DataFrame(city_data)
cities
Out [2]: City Country Population
0 New York City United States 8600000
1 Paris France 2141000
2 Barcelona Spain 5515000
3 Rome Italy 2873000
我们创建了第一个DataFrame,它与Series非常相似。再次提醒,当我们没有为构造函数提供一个明确的索引时,pandas会默认生成一个从0开始的顺序索引。
如果我们想翻转数据,以列标头作为索引标签,我们可以调用transpose方法或其T属性:
In [3]: cities.transpose() # 此行代码和下面代码是一样的
cities.T
Out [3]: 0 1 2 3
City New York City Paris Barcelona Rome
Country United States France Spain Italy
Population 8600000 2141000 5515000 2873000
另外还可以使用一个更方便的from_dict方法,此方法用于把字典转换为DataFrame。其参数orient用于控制索引标签的创建,如果想把字典的键保存为DataFrame的列,可以使用默认值columns;如果想把字典的键保存为行,则使用值index:
In [4]: pd.DataFrame.from_dict(data = city_data, orient = "index")
Out [4]: 0 1 2 3
City New York City Paris Barcelona Rome
Country United States France Spain Italy
Population 8600000 2141000 5515000 2873000
1.2 从NumPy 数组创建DataFrame
DataFrame构造函数还接受NumPy ndarray对象。假设我们要创建一个3x5的DataFrame,其整数在1到100(含)之间,我们可以使用random模块的randint方法:
In [5]: data = np.random.randint(1, 101, [3, 5])
data
Out [5]: array([[25, 22, 80, 43, 42],
[40, 89, 7, 21, 25],
[89, 71, 32, 28, 39]])
接下来,我们将ndarray传到DataFrame构造函数中。与行一样,如果未提供自定义的列标头,Pandas将为每列分配一个数字索引:
In [6]: pd.DataFrame(data = data)
Out [6]: 0 1 2 3 4
0 25 22 80 43 42
1 40 89 7 21 25
2 89 71 32 28 39
我们可以使用可迭代序列,例如列表,元组或ndarray,以用作行标签。请注意,可迭代项的长度必须等于数据集中的行数。这是一个3x5的表格,因此我们必须为索引提供3个标签。
In [7]: index = ["Morning", "Afternoon", "Evening"]
temperatures = pd.DataFrame(data = data, index = index)
temperatures
Out [7]: 0 1 2 3 4
Morning 25 22 80 43 42
Afternoon 40 89 7 21 25
Evening 89 71 32 28 39
columns参数允许我们设置DataFrame的列名(也称为垂直标签)。因为我们总共有5列,所以我们的可迭代项的长度必须为5。下例通过将标头存储在元组中来设置列名:
In [8]: index = ["Morning", "Afternoon", "Evening"]
columns = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
temperatures = pd.DataFrame(data = data,
index = index,
columns = columns)
temperatures
Out [8]: Monday Tuesday Wednesday Thursday Friday
Morning 25 22 80 43 42
Afternoon 40 89 7 21 25
Evening 89 71 32 28 39
行索引和列索引都允许包含重复值:
In [9]: index = ["Morning", "Afternoon", " Morning"]
columns = ("Monday", "Tuesday", "Wednesday", "Tuesday", "Friday")
temperatures = pd.DataFrame(data = data,
index = index,
columns = columns)
temperatures
Out [9]: Monday Tuesday Wednesday Tuesday Friday
Morning 25 22 80 43 42
Afternoon 40 89 7 21 25
Morning 89 71 32 28 39
2. Series和DataFrame的相似点
在之前介绍的许多Series属性和方法在DataFrame上也适用。
2.1 导入CSV数据集
nba.csv文件是2019-2020 NBA运动员的数据集,包括每个球员的姓名,球队,位置,生日和工资:
In [10]: pd.read_csv("nba.csv")
Out [10]: Name Team Position Birthday Salary
0 Shake Milton Philadelphia 76ers SG 9/26/96 1445697
1 Christian Wood Detroit Pistons PF 9/27/95 1645357
2 PJ Washington Charlotte Hornets PF 8/23/98 3831840
3 Derrick Rose Detroit Pistons PG 10/4/88 7317074
4 Marial Shayok Philadelphia 76ers G 7/26/95 79568
… … … … … …
445 Austin Rivers Houston Rockets PG 8/1/92 2174310
446 Harry Giles Sacramento Kings PF 4/22/98 2578800
447 Robin Lopez Milwaukee Bucks C 4/1/88 4767000
448 Collin Sexton Cleveland Cavaliers PG 1/4/99 4764960
449 Ricky Rubio Phoenix Suns PG 10/21/90 16200000
450 rows x 5 columns
注意,Birthday列中的值默认是作为字符串而不是datetime对象导入,之前介绍过可以使用parse_dates参数将值强制转换为datetime,一致以YYYY-MM-DD格式显示:
In [11]: pd.read_csv("nba.csv", parse_dates = ["Birthday"])
Out [11]: Name Team Position Birthday Salary
0 Shake Milton Philadelphia 76ers SG 1996-09-26 1445697
1 Christian Wood Detroit Pistons PF 1995-09-27 1645357
2 PJ Washington Charlotte Hornets PF 1998-08-23 3831840
3 Derrick Rose Detroit Pistons PG 1988-10-04 7317074
4 Marial Shayok Philadelphia 76ers G 1995-07-26 79568
… … … … … …
445 Austin Rivers Houston Rockets PG 1992-08-01 2174310
446 Harry Giles Sacramento Kings PF 1998-04-22 2578800
447 Robin Lopez Milwaukee Bucks C 1988-04-01 4767000
448 Collin Sexton Cleveland Cavaliers PG 1999-01-04 4764960
449 Ricky Rubio Phoenix Suns PG 1990-10-21 16200000
450 rows x 5 columns
现在我们可以把DataFrame分配给一个变量nba:
In [12]: nba = pd.read_csv("nba.csv", parse_dates = ["Birthday"])
2.2 共享和专用属性
Series的值必须是单一同质的数据类型,而DataFrame的列可以保存异构的数据。让我们使用dtypes属性查看各自的数据类型,它返回的是一个Series对象:
In [13]: nba.dtypes
Out [13]: Name object
Team object
Position object
Birthday datetime64[ns]
Salary int64
dtype: object
然后调用value_counts方法可以计算每种数据类型的列数:
In [14]: nba.dtypes.value_counts()
Out [14]: object 3
datetime64[ns] 1
int64 1
dtype: int64
DataFrame基本上由两个对象组成:一个由行标签组成的索引和一个保存每一行值的数据容器。Pandas自带了几个索引对象,每个索引对象都经过优化以存储特定类型的值(numeric、string、datetime等)。index属性返回DataFrame的Index对象。下面让我们看一下nba数据集使用的索引类型:
In [15]: nba.index
Out [15]: RangeIndex(start=0, stop=450, step=1)
RangeIndex是一个优化的索引,用于存储顺序的整数值。与Python的range函数非常相似,RangeIndex包含三个参数:start,stop和step(每两个值之间的间隔)。上例的输出告诉我们索引从0开始,以1为增量(即0、1、2…449)直到450。
DataFrame还具有专用的columns属性,该属性返回包含标头的Index对象:
In [16]: nba.columns
Out [16]: Index(['Name', 'Team', 'Position', 'Birthday', 'Salary'], dtype='object')
axes属性同时返回行和列索引:
In [17]: nba.axes
Out [17]: [RangeIndex(start=0, stop=450, step=1),
Index(['Name', 'Team', 'Position', 'Birthday', 'Salary'], dtype='object')]
shape属性返回DataFrame维度的元组,450行x 5列:
In [18]: nba.shape
Out [18]: (450, 5)
ndim属性返回维数:
In [19]: nba.ndim
Out [19]: 2
size属性返回数据集中值的总数,包括缺失值,它等于行数和列数的乘积:
In [20]: nba.size
Out [20]: 2250
In [21]: len(nba.index) * len(nba.columns)
Out [21]: 2250
如果要排除缺失值可以使用count方法,它将返回一个包含每个DataFrame列的非空值数量的Series。然后使用sum方法得出DataFrame中非空值的总数。因为此数据集不包含任何缺失值,所以size属性和count方法的结果将相同。
In [22]: nba.count()
Out [22]: Name 450
Team 450
Position 450
Birthday 450
Salary 450
dtype: int64
In [23]: nba.count().sum()
Out [23]: 2250
2.3 共享方法
head和tail方法返回数据集的最前或最后的行:
In [24]: nba.head(2)
Out [24]: Name Team Position Birthday Salary
0 Shake Milton Philadelphia 76ers SG 1996-09-26 1445697
1 Christian Wood Detroit Pistons PF 1995-09-27 1645357
In [25]: nba.tail(n = 3)
Out [25]: Name Team Position Birthday Salary
447 Robin Lopez Milwaukee Bucks C 1988-04-01 4767000
448 Collin Sexton Cleveland Cavaliers PG 1999-01-04 4764960
449 Ricky Rubio Phoenix Suns PG 1990-10-21 16200000
sample方法返回DataFrame的随机行:
In [26]: nba.sample(3)
Out [26]: Name Team Position Birthday Salary
348 Patrick Patterson Los Angeles Clippers PF 1989-03-14 3068660
14 Alec Burks Golden State Warriors SG 1991-07-20 2320044
228 Ignas Brazdeikis New York Knicks SF 1999-01-08 898310
nunique方法返回一个包含每一列唯一值的数量的Series:
In [27]: nba.nunique()
Out [27]: Name 450
Team 30
Position 9
Birthday 430
Salary 269
dtype: int64
之前介绍过的max和min方法在DataFrame上也适用,它们返回包含每一列的最大值和最小值的Series。datetime列的最大值是按时间顺序排列的最新日期。
In [28]: nba.max()
Out [28]: Team Washington Wizards
Position SG
Birthday 2000-12-23 00:00:00
Salary 40231758
dtype: object
In [29]: nba.min()
Out [29]: Team Atlanta Hawks
Position C
Birthday 1977-01-26 00:00:00
Salary 79568
dtype: object
nlargest方法返回按照指定列最大值排序的前n行。因为一个DataFrame可以包含多个可排序的列,所以我们必须使用columns参数指定要用作排序的列。参数值可以是单个列名,也可以是多个列名的列表。下例是返回NBA中收入最高的前4名球员:
In [30]: nba.nlargest(n = 4, columns = "Salary")
Out [30]: Name Team Position Birthday Salary
205 Stephen Curry Golden State Warriors PG 1988-03-14 40231758
38 Chris Paul Oklahoma City Thunder PG 1985-05-06 38506482
219 Russell West* Houston Rockets PG 1988-11-12 38506482
251 John Wall Washington Wizards PG 1990-09-06 38199000
nsmallest方法返回按照指定列最小值排序的前n行。下例是返回NBA中最老的前3名球员:
In [31]: nba.nsmallest(3, columns = ["Birthday"])
Out [31]: is Name Team Position Birthday Salary
98 Vince Carter Atlanta Hawks PF 1977-01-26 2564753
196 Udonis Haslem Miami Heat C 1980-06-09 2564753
262 Kyle Korver Milwaukee Bucks PF 1981-03-17 6004753
如果要计算所有NBA工资的总和,可以直接使用sum方法,但必须把numeric_only参数设为True,用于只计算数值类型的列。
In [32]: nba.sum(numeric_only = True)
Out [32]: Salary 3444112694
dtype: int64
mean方法可以计算平均工资:
In [33]: nba.mean()
Out [33]: Salary 7.653584e+06
dtype: float64
median方法可以计算工资的中位数,std方法统计偏差:
In [34]: nba.median()
Out [34]: Salary 3303074.5
dtype: float64
In [35]: nba.std()
Out [35]: Salary 9.288810e+06
dtype: float64
3. 按DataFrame值排序
我们可以使用sort_values方法按一列或多列对DataFrame进行排序。默认情况下,该方法返回一个新的DataFrame。
3.1 按单列排序
首先让我们按名字对球员进行排序,by参数用于指定排序的列:
In [36]: nba.sort_values("Name") # 和下面代码是一样的
nba.sort_values(by = "Name")
Out [36]: Name Team Position Birthday Salary
52 Aaron Gordon Orlando Magic PF 1995-09-16 19863636
101 Aaron Holiday Indiana Pacers PG 1996-09-30 2239200
437 Abdel Nader Oklahoma City Thunder SF 1993-09-25 1618520
81 Adam Mokoka Chicago Bulls G 1998-07-18 79568
399 Admiral Schofield Washington Wizards SF 1997-03-30 1000000
… … … … … …
159 Zach LaVine Chicago Bulls PG 1995-03-10 19500000
302 Zach Norvell Los Angeles Lakers SG 1997-12-09 79568
312 Zhaire Smith Philadelphia 76ers SG 1999-06-04 3058800
137 Zion Williamson New Orleans Pelicans F 2000-07-06 9757440
248 Zylan Cheatham New Orleans Pelicans SF 1995-11-17 79568
450 rows × 5 columns
ascending参数可以指定升序或降序排序,我们可以使用它来找出NBA中最年轻的五个球员,只需对Birthday列进行降序排序,head方法默认返回前5行:
In [37]: nba.sort_values("Birthday", ascending = False).head()
Out [37]: Name Team Position Birthday Salary
136 Sekou Doumbouya Detroit Pistons SF 2000-12-23 3285120
432 Talen Horton-Tucker Los Angeles Lakers GF 2000-11-25 898310
137 Zion Williamson New Orleans Pelicans F 2000-07-06 9757440
313 RJ Barrett New York Knicks SG 2000-06-14 7839960
392 Jalen Lecque Phoenix Suns G 2000-06-13 898310
3.2 按多列排序
sort_values方法的by参数还支持按多个列排序,默认情况下,所有排序将按升序排列,也就是ascending参数默认值为True。下例按字母顺序对球队进行排序,然后再对每个球队中的球员进行排序:
In [38]: nba.sort_values(by = ["Team", "Name"])
Out [38]: Name Team Position Birthday Salary
359 Alex Len Atlanta Hawks C 1993-06-16 4160000
167 Allen Crabbe Atlanta Hawks SG 1992-04-09 18500000
276 Brandon Goodwin Atlanta Hawks PG 1995-10-02 79568
438 Bruno Fernando Atlanta Hawks C 1998-08-15 1400000
194 Cam Reddish Atlanta Hawks SF 1999-09-01 4245720
… … … … … …
418 Jordan McRae Washington Wizards PG 1991-03-28 1645357
273 Justin Robinson Washington Wizards PG 1997-10-12 898310
428 Moritz Wagner Washington Wizards C 1997-04-26 2063520
21 Rui Hachimura Washington Wizards PF 1998-02-08 4469160
36 Thomas Bryant Washington Wizards C 1997-07-31 800000
450 rows × 5 columns
我们可以使用ascending参数对每个列按相同的顺序排序:
In [39]: nba.sort_values(["Team", "Name"], ascending = False)
Out [39]: Name Team Position Birthday Salary
36 Thomas Bryant Washington Wizards C 1997-07-31 8000000
21 Rui Hachimura Washington Wizards PF 1998-02-08 4469160
428 Moritz Wagner Washington Wizards C 1997-04-26 2063520
273 Justin Robinson Washington Wizards PG 1997-10-12 898310
418 Jordan McRae Washington Wizards PG 1991-03-28 1645357
… … … … … …
194 Cam Reddish Atlanta Hawks SF 1999-09-01 4245720
438 Bruno Fernando Atlanta Hawks C 1998-08-15 1400000
276 Brandon Goodwin Atlanta Hawks PG 1995-10-02 79568
167 Allen Crabbe Atlanta Hawks SG 1992-04-09 18500000
359 Alex Len Atlanta Hawks C 1993-06-16 4160000
450 rows × 5 columns
如果我们想对每个列按照不同的排序顺序,例如,对球队按升序进行排序,然后再对工资按降序进行排序。为此,ascending参数也支持列表值,每个布尔值会与by参数的每个值对应,也就是by和ascending参数的列表的长度必须相等。
In [40]: nba.sort_values(by = ["Team", "Salary"],
ascending = [True, False])
Out [40]: Name Team Position Birthday Salary
111 Chandler Parsons Atlanta Hawks SF 1988-10-25 25102512
28 Evan Turner Atlanta Hawks PG 1988-10-27 18606556
167 Allen Crabbe Atlanta Hawks SG 1992-04-09 18500000
213 De'Andre Hunter Atlanta Hawks SF 1997-12-02 7068360
339 Jabari Parker Atlanta Hawks PF 1995-03-15 6500000
… … … … … …
80 Isaac Bonga Washington Wizards PG 1999-11-08 1416852
399 Admiral Schofield Washington Wizards SF 1997-03-30 1000000
273 Justin Robinson Washington Wizards PG 1997-10-12 898310
283 Garrison Mathews Washington Wizards SG 1996-10-24 79568
353 Chris Chiozza Washington Wizards PG 1995-11-21 79568
450 rows × 5 columns
与Series一样,inplace参数会修改原始DataFrame而不是返回一个新的DataFrame。Jupyter Notebook中将不会产生任何输出:
In [41]: nba.sort_values(by = ["Team", "Salary"],
ascending = [True, False],
inplace = True)
4. 按DataFrame索引排序
使用inplace参数更改了原始的DataFrame,但我们也有方法将其恢复为原始形式。
4.1 按行索引排序
sort_index方法按索引值对DataFrame进行排序:
In [42]: nba.sort_index().head() # 与下行代码是一样的
nba.sort_index(ascending = True).head()
Out [42]: Name Team Position Birthday Salary
0 Shake Milton Philadelphia 76ers SG 1996-09-26 1445697
1 Christian Wood Detroit Pistons PF 1995-09-27 1645357
2 PJ Washington Charlotte Hornets PF 1998-08-23 3831840
3 Derrick Rose Detroit Pistons PG 1988-10-04 7317074
4 Marial Shayok Philadelphia 76ers G 1995-07-26 79568
使用inplace参数使更改永久生效:
In [43]: nba.sort_index(inplace = True)
4.2 按列索引排序
按列进行排序可以使用axis参数,只需把值设为1或columns:
In [44]: nba.sort_index(axis = 1).head() # 这三行代码是一样的
nba.sort_index(axis = "columns").head()
nba.sort_index(axis = "columns", ascending = True).head()
Out [44]: Birthday Name Position Salary Team
0 1996-09-26 Shake Milton SG 1445697 Philadelphia 76ers
1 1995-09-27 Christian Wood PF 1645357 Detroit Pistons
2 1998-08-23 PJ Washington PF 3831840 Charlotte Hornets
3 1988-10-04 Derrick Rose PG 7317074 Detroit Pistons
4 1995-07-26 Marial Shayok G 79568 Philadelphia 76ers
5. 设置新索引
设置新索引可以使用set_index方法,它返回一个以给定列作为索引的新DataFrame:
In [45]: nba.set_index(keys = "Name") # is the same as
nba.set_index("Name")
Out [45]: Team Position Birthday Salary
Name
Shake Milton Philadelphia 76ers SG 1996-09-26 1445697
Christian Wood Detroit Pistons PF 1995-09-27 1645357
PJ Washington Charlotte Hornets PF 1998-08-23 3831840
Derrick Rose Detroit Pistons PG 1988-10-04 7317074
Marial Shayok Philadelphia 76ers G 1995-07-26 79568
… … … … …
Austin Rivers Houston Rockets PG 1992-08-01 2174310
Harry Giles Sacramento Kings PF 1998-04-22 2578800
Robin Lopez Milwaukee Bucks C 1988-04-01 4767000
Collin Sexton Cleveland Cavaliers PG 1999-01-04 4764960
Ricky Rubio Phoenix Suns PG 1990-10-21 16200000
450 rows × 4 columns
使用inplace参数使更改永久生效:
In [46]: nba.set_index(keys = "Name", inplace = True)
如果我们知道要在导入数据集时用作索引的列,我们还可以使用read_csv方法的index_col参数:
In [47]: nba = pd.read_csv("nba.csv",
parse_dates = ["Birthday"],
index_col = "Name")
6. 从DataFrame读取列
DataFrame是共用相同索引的Series对象的集合,我们可以轻松地从DataFrame中读取一个或多个这些列。
6.1 从DataFrame读取单列
每个Series的列都可以使用DataFrame的属性读取。例如,我们可以使用nba.Salary读取Salary列:
In [48]: nba.Salary
Out [48]: Name
Shake Milton 1445697
Christian Wood 1645357
PJ Washington 3831840
Derrick Rose 7317074
Marial Shayo 79568
...
Austin Rivers 2174310
Harry Giles 2578800
Robin Lopez 4767000
Collin Sexton 4764960
Ricky Rubio 16200000
Name: Salary, Length: 450, dtype: int64
如果您希望始终使用二维数据结构,可以使用to_frame方法将Series转换为DataFrame:
In [49]: nba.Salary.to_frame()
Out [49]: Salary
Name
Shake Milton 1445697
Christian Wood 1645357
PJ Washington 3831840
Derrick Rose 7317074
Marial Shayok 79568
… …
Austin Rivers 2174310
Harry Giles 2578800
Robin Lopez 4767000
Collin Sexton 4764960
Ricky Rubio 16200000
450 rows × 1 columns
也可以通过名称来读取列,这种方法的优点是它支持名称中带有空格的列。
In [50]: nba["Position"]
Out [50]: Name
Shake Milton SG
Christian Wood PF
PJ Washington PF
Derrick Rose PG
Marial Shayok G
..
Austin Rivers PG
Harry Giles PF
Robin Lopez C
Collin Sexton PG
Ricky Rubio PG
Name: Position, Length: 450, dtype: object
6.2 从DataFrame读取多列
要读取多个列,只需要在列表中指定多个列名,返回的是一个新的DataFrame。它的列的排列顺序和列表中的一样,这是重新排列DataFrame列的有效方式:
In [51]: nba[["Salary", "Birthday"]]
Out [51]: Salary Birthday
Name
Shake Milton 1445697 1996-09-26
Christian Wood 1645357 1995-09-27
PJ Washington 3831840 1998-08-23
Derrick Rose 7317074 1988-10-04
Marial Shayok 79568 1995-07-26
… … …
Austin Rivers 2174310 1992-08-01
Harry Giles 2578800 1998-04-22
Robin Lopez 4767000 1988-04-01
Collin Sexton 4764960 1999-01-04
Ricky Rubio 16200000 1990-10-21
450 rows × 2 columns
如果我们想根据列的数据类型来选择列,可以使用select_dtypes方法,其include和exclude这两个参数可以指定单个数据类型或多个数据类型的列表。提醒一下,您可以使用dtypes属性查看数据集中的数据类型。
In [52]: # 仅选择字符串类型的列
` nba.select_dtypes(include = "object")
Out [52]: Team Position
Name
Shake Milton Philadelphia 76ers SG
Christian Wood Detroit Pistons PF
PJ Washington Charlotte Hornets PF
Derrick Rose Detroit Pistons PG
Marial Shayok Philadelphia 76ers G
… … …
Austin Rivers Houston Rockets PG
Harry Giles Sacramento Kings PF
Robin Lopez Milwaukee Bucks C
Collin Sexton Cleveland Cavaliers PG
Ricky Rubio Phoenix Suns PG
450 rows × 2 columns
In [53]: # 排除字符串和整数类型的列
nba.select_dtypes(exclude = ["object", "int"])
Out [53]: Birthday
Name
Shake Milton 1996-09-26
Christian Wood 1995-09-27
PJ Washington 1998-08-23
Derrick Rose 1988-10-04
Marial Shayok 1995-07-26
… …
Austin Rivers 1992-08-01
Harry Giles 1998-04-22
Robin Lopez 1988-04-01
Collin Sexton 1999-01-04
Ricky Rubio 1990-10-21
450 rows × 1 columns
7. 从DataFrame读取行
DataFrame中的行可以通过索引标签或索引位置读取。
7.1 通过索引标签读取行
loc属性返回具有给定索引标签行的Series,注意是区分大小写。下例是返回索引标签是"LeBron James"的行:
In [54]: nba.loc["LeBron James"]
Out [54]: Team Los Angeles Lakers
Position PF
Birthday 1984-12-30 00:00:00
Salary 37436858
Name: LeBron James, dtype: object
还可以给定一个列表以读取多行,返回结果是一个DataFrame,顺序和给定的列表一样:
In [55]: nba.loc[["Kawhi Leonard", "Paul George"]]
Out [55]: Team Position Birthday Salary
Name
Kawhi Leonard Los Angeles Clippers SF 1991-06-29 32742000
Paul George Los Angeles Clippers SF 1990-05-02 33005556
Pandas还支持Python的列表切片语法。例如,我们可以对索引标签进行排序以按字母顺序获得球员的姓名,然后选择Otto Porter和Patrick Beverley之间的所有球员。注意,两个端点的球员也会被包括在内:
In [56]: nba.sort_index().loc["Otto Porter":"Patrick Beverley"]
Out [56]: Team Position Birthday Salary
Name
Otto Porter Chicago Bulls SF 1993-06-03 27250576
PJ Dozier Denver Nuggets PG 1996-10-25 79568
PJ Washington Charlotte Hornets PF 1998-08-23 3831840
Pascal Siakam Toronto Raptors PF 1994-04-02 2351838
Pat Connaughton Milwaukee Bucks SG 1993-01-06 1723050
Patrick Beverley Los Angeles Clippers PG 1988-07-12 12345680
我们还可以读取DataFrame从某行开始到最后一行的数据,它与从Python列表中读取分片的语法相同,也就是在初始索引标签后加一个冒号:
In [57]: nba.sort_index().loc["Zach Collins":]
Out [57]: Team Position Birthday Salary
Name
Zach Collins Portland Trail Blazers C 1997-11-19 4240200
Zach LaVine Chicago Bulls PG 1995-03-10 19500000
Zach Norvell Los Angeles Lakers SG 1997-12-09 79568
Zhaire Smith Philadelphia 76ers SG 1999-06-04 3058800
Zion Williamson New Orleans Pelicans F 2000-07-06 9757440
Zylan Cheatham New Orleans Pelicans SF 1995-11-17 79568
同理可以读取DataFrame从开头到某行的数据,下例返回所从开头到"Al Horford"的行:
In [58]: nba.sort_index().loc[:"Al Horford"]
Out [58]: Team Position Birthday Salary
Name
Aaron Gordon Orlando Magic PF 1995-09-16 19863636
Aaron Holiday Indiana Pacers PG 1996-09-30 2239200
Abdel Nader Oklahoma City Thunder SF 1993-09-25 1618520
Adam Mokoka Chicago Bulls G 1998-07-1 79568
Admiral Schofield Washington Wizards SF 1997-03-30 1000000
Al Horford Philadelphia 76ers C 1986-06-03 28000000
如果DataFrame中不存在指定的索引标签,则会抛出KeyError异常:
In [59]: nba.loc["Bugs Bunny"]
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
KeyError: 'Bugs Bunny'
7.2 通过索引位置读取行
iloc(索引位置index location)属性返回具有给定索引位置的一行或多行,参数可以是单个整数或整数的列表:
In [60]: nba.iloc[300]
Out [60]: Team Denver Nuggets
Position PF
Birthday 1999-04-03 00:00:00
Salary 1416852
Name: Jarred Vanderbilt, dtype: object
In [61]: nba.iloc[[100, 200, 300, 400]]
Out [61]: Team Position Birthday Salary
Name
Brian Bowen Indiana Pacers SG 1998-10-02 79568
Marco Belinelli San Antonio Spurs SF 1986-03-25 5846154
Jarred Vanderbilt Denver Nuggets PF 1999-04-03 1416852
Louis King Detroit Pistons F 1999-04-06 79568
列表切片的语法在这里也是使用的,需要注意冒号后面指定端点的行是不包括的。下例返回索引位置400、401、402和403的行:
In [62]: nba.iloc[400:404]
Out [62]: Team Position Birthday Salary
Name
Louis King Detroit Pistons F 1999-04-06 79568
Kostas Antetokounmpo Los Angeles Lakers PF 1997-11-20 79568
Rodions Kurucs *lyn Nets PF 1998-02-05 1699236
Spencer Dinwiddie *lyn Nets PG 1993-04-06 10605600
In [63]: nba.iloc[:2] # 读取头两行
Out [63]: Team Position Birthday Salary
Name
Shake Milton Philadelphia 76ers SG 1996-09-26 1445697
Christian Wood Detroit Pistons PF 1995-09-27 1645357
In [64]: nba.iloc[447:] # 读取从索引位置447到最后
Out [64]: Team Position Birthday Salary
Name
Robin Lopez Milwaukee Bucks C 1988-04-01 4767000
Collin Sexton Cleveland Cavaliers PG 1999-01-04 4764960
Ricky Rubio Phoenix Suns PG 1990-10-21 16200000
索引位置也可以使用负数,也就是从倒数开始数。下例是从倒数第10行直到倒数第6行,但不包括倒数第6行:
In [65]: nba.iloc[-10:-6]
Out [65]: Team Position Birthday Salary
Name
Jared Dudley Los Angeles Lakers PF 1985-07-10 2564753
Max Strus ChicagoBulls SG 1996-03-28 79568
Kevon Looney Golden State Warriors C 1996-02-06 4464286
Willy Hernangomez Charlotte Hornets C 1994-05-27 1557250
除此以外还可以指定索引位置的步长序列。在下例中,我们从前十行中选择间隔为2的行。因此,返回结果的索引位置为0、2、4、6和8:
In [66]: nba.iloc[0:10:2]
Out [66]: Team Position Birthday Salary
Name
Shake Milton Philadelphia 76ers SG 1996-09-26 1445697
PJ Washington Charlotte Hornets PF 1998-08-23 3831840
Marial Shayok Philadelphia 76ers G 1995-07-26 79568
Kendrick Nunn Miami Heat SG 1995-08-03 1416852
* Lopez Milwaukee Bucks C 1988-04-01 12093024
7.3 从行的指定列中读取值
loc和iloc属性都支持第二个参数指定要读取的列。在下例中,我们读取索引标签为"Giannis Antetokounmpo" 所在行的Team列的值:
In [67]: nba.loc["Giannis Antetokounmpo", "Team"]
Out [67]: 'Milwaukee Bucks'
两个参数都支持传递列表,下例第二个参数使用列表指定要读取Position和Birthday列的值:
In [68]: nba.loc["James Harden", ["Position", "Birthday"]]
Out [68]: Position PG
Birthday 1989-08-26 00:00:00
Name: James Harden, dtype: object
下例第一、二个参数都使用了列表:
In [69]: nba.loc[["Russell West*", "Anthony Davis"],
["Team", "Salary"]]
Out [69]: Team Salary
Name
Russell West* Houston Rockets 38506482
Anthony Davis Los Angeles Lakers 27093019
列表切片语法也可以用于读取多个列,注意,这里两个端点都将包括在内:
In [70]: nba.loc["Joel Embiid", "Position":"Salary"]
Out [70]: Position C
Birthday 1994-03-16 00:00:00
Salary 27504630
Name: Joel Embiid, dtype: object
参数指定的列名必须和它们在DataFrame中出现的顺序一样。下例会返回空列表,因为Salary列位于Position列之后:
In [71]: nba.loc["Joel Embiid", "Salary":"Position"]
Out [71]: Series([], Name: Joel Embiid, dtype: object)
每个DataFrame列都分配有一个索引位置,在我们当前的DataFrame中,Team的索引为0,Position的索引为1,依此类推。
In [72]: nba.columns
Out [72]: Index(['Team', 'Position', 'Birthday', 'Salary'], dtype='object')
列的索引位置也可以作为第二个参数传给iloc:
In [73]: nba.iloc[57, 3]
Out [73]: 796806
列表切片语法也可以在此处使用。下例返回索引位置100到104(不包括)所在行的从开始到索引位置3(不包括)的列:
In [74]: nba.iloc[100:104, :3]
Out [74]: Team Position Birthday
Name
Brian Bowen Indiana Pacers SG 1998-10-02
Aaron Holiday Indiana Pacers PG 1996-09-30
Troy Daniels Los Angeles Lakers SG 1991-07-15
Buddy Hield Sacramento Kings SG 1992-12-17
iloc和loc属性非常通用,参数可以是单个值、列表、列表切片等。这种灵活性的缺点是需要额外的开销,pandas必须检查iloc或loc的输入类型。
当我们要从DataFrame中读取单个值时,可以使用at和iat这两个替代属性: at属性的参数是行和列标签,而iat属性的参数是行和列索引位置:
In [75]: nba.at["Austin Rivers", "Birthday"]
Out [75]: Timestamp('1992-08-01 00:00:00')
In [76]: nba.iat[263, 1]
Out [76]: 'PF'
8. 重命名列或行
我们可以通过使用新名称列表覆盖columns属性来重命名DataFrame中的某些或所有列:
In [77]: nba.columns
Out [77]: Index(['Team', 'Position', 'Birthday', 'Salary'], dtype='object')
In [78]: nba.columns = ["Team", "Position", "Date of Birth", "Pay"]
nba.head(1)
Out [78]: Team Position Date of Birth Pay
Name
Shake Milton Philadelphia 76ers SG 1996-09-26 1445697
我们也可以使用rename方法,其参数columns的值类型是一个字典,键是需要修改的原列名,值是新的列名。下例是把原列名"Date of Birth"重命名为"Birthday":
In [79]: nba.rename(columns = { "Date of Birth": "Birthday" })
Out [79]: Team Position Birthday Pay
Name
Shake Milton Philadelphia 76ers SG 1996-09-26 1445697
Christian Woo Detroit Pistons PF 1995-09-27 1645357
PJ Washington Charlotte Hornets PF 1998-08-23 3831840
Derrick Rose Detroit Pistons PG 1988-10-04 7317074
Marial Shayok Philadelphia 76ers G 1995-07-26 79568
… … … … …
Austin Rivers Houston Rockets PG 1992-08-01 2174310
Harry Giles Sacramento Kings PF 1998-04-22 2578800
Robin Lopez Milwaukee Bucks C 1988-04-01 4767000
Collin Sexton Cleveland Cavaliers PG 1999-01-04 4764960
Ricky Rubio Phoenix Suns PG 1990-10-21 16200000
450 rows × 4 columns
一如既往地,使用 inplace 参数使修改永久生效:
In [80]: nba.rename(
columns = { "Date of Birth": "Birthday" },
inplace = True
)
rename方法也可以重命名索引标签。下例将 "Giannis Antetokounmpo" 重命名为他的昵称 "Greek Freak":
In [81]: nba.loc["Giannis Antetokounmpo"]
Out [81]: Team Milwaukee Bucks
Position PF
Birthday 1994-12-06 00:00:00
Pay 25842697
Name: Giannis Antetokounmpo, dtype: object
In [82]: nba.rename(
index = { "Giannis Antetokounmpo": "Greek Freak" },
inplace = True
)
In [83]: nba.loc["Greek Freak"]
Out [83]: Team Milwaukee Bucks
Position PF
Birthday 1994-12-06 00:00:00
Pay 25842697
Name: Greek Freak, dtype: object
9. 重置索引
如果我们想把另一列用作DataFrame的索引,可以使用set_index方法,但会造成当前索引Name的丢失:
In [84]: nba.set_index("Team").head()
Out [84]: Position Birthday Pay
Team
Philadelphia 76ers SG 1996-09-26 1445697
Detroit Pistons PF 1995-09-27 1645357
Charlotte Hornets PF 1998-08-23 3831840
Detroit Pistons PG 1988-10-04 7317074
Philadelphia 76ers G 1995-07-26 79568
为了保留原来的索引列Name,我们首先要使用reset_index方法把现有索引重新整合为DataFrame中的常规列,并生成新的顺序索引:
In [85]: nba.reset_index().head()
Out [85]: Name Team Position Birthday Pay
0 Shake Milton Philadelphia 76ers SG 1996-09-26 1445697
1 Christian Wood Detroit Pistons PF 1995-09-27 1645357
2 PJ Washington Charlotte Hornets PF 1998-08-23 3831840
3 Derrick Rose Detroit Pistons PG 1988-10-04 7317074
4 Marial Shayok Philadelphia 76ers G 1995-07-26 79568
现在我们可以放心使用set_index方法了:
In [86]: nba.reset_index().set_index("Team").head()
Out [86]: Name Position Birthday Pay
Team
Philadelphia 76ers Shake Milton SG 1996-09-26 1445697
Detroit Pistons Christian Wood PF 1995-09-27 1645357
Charlotte Hornets PJ Washington PF 1998-08-23 3831840
Detroit Pistons Derrick Rose PG 1988-10-04 7317074
Philadelphia 76ers Marial Shayok G 1995-07-26 79568
reset_index方法也支持inplace参数,但是要注意:如果参数设置为True,则该方法将不会返回新的DataFrame,因此不能直接链接调用set_index方法,必须依次分开单独调用:
In [87]: nba.reset_index(inplace = True)
nba.set_index("Name", inplace = True)
END O(∩_∩)O