行选择
通常,我们希望只提取那些对应具有特定特征的条目的行。例如,我们可能只想要勇士队的行,或者收入超过 $\$10$ 百万美元的球员。或者我们可能只想要收入最高的前五名。
from datascience import *
import numpy as np
path_data = '../../../assets/data/'
np.set_printoptions(threshold=50)
nba_salaries = Table.read_table(path_data + 'nba_salaries.csv')
nba = nba_salaries.relabeled("'15-'16 SALARY", 'SALARY')
指定行
Table 方法 take 正是用来做这个的——它接受一个指定的行集。其参数是一个行索引或索引数组,并创建一个仅由这些行组成的新表格。
例如,如果我们只想要 nba 的第一行,可以如下使用 take。
nba
PLAYER | POSITION | TEAM | SALARY
Paul Millsap | PF | Atlanta Hawks | 18.6717
Al Horford | C | Atlanta Hawks | 12
Tiago Splitter | C | Atlanta Hawks | 9.75625
Jeff Teague | PG | Atlanta Hawks | 8
Kyle Korver | SG | Atlanta Hawks | 5.74648
Thabo Sefolosha | SF | Atlanta Hawks | 4
Mike Scott | PF | Atlanta Hawks | 3.33333
Kent Bazemore | SF | Atlanta Hawks | 2
Dennis Schroder | PG | Atlanta Hawks | 1.7634
Tim Hardaway Jr. | SG | Atlanta Hawks | 1.30452
... (407 rows omitted)nba.take(0)
PLAYER | POSITION | TEAM | SALARY
Paul Millsap | PF | Atlanta Hawks | 18.6717这是一个新表格,只有我们指定的那一行。
我们也可以通过指定一个索引范围作为参数来获取第四、第五和第六行。
nba.take(np.arange(3, 6))
PLAYER | POSITION | TEAM | SALARY
Jeff Teague | PG | Atlanta Hawks | 8
Kyle Korver | SG | Atlanta Hawks | 5.74648
Thabo Sefolosha | SF | Atlanta Hawks | 4如果我们想要一个薪资最高的前 5 名球员的表格,可以先按薪资对列表排序,然后 take 前五行:
nba.sort('SALARY', descending=True).take(np.arange(5))
PLAYER | POSITION | TEAM | SALARY
Kobe Bryant | SF | Los Angeles Lakers | 25
Joe Johnson | SF | Brooklyn Nets | 24.8949
LeBron James | SF | Cleveland Cavaliers | 22.9705
Carmelo Anthony | SF | New York Knicks | 22.875
Dwight Howard | C | Houston Rockets | 22.3594对应指定特征的行
更常见的情况是,我们希望访问具有某个特征的行集中的数据,但事先并不知道这些行的索引。例如,我们可能需要所有收入超过 $\$10$ 百万美元的球员的数据,但我们不想花时间在排序后的表格中数行。
where 方法为我们完成了这项工作。其输出是一个表格,列与原始表格相同,但只包含该特征出现的行。
where 的第一个参数是包含行是否具有我们想要的特征的信息的列标签。如果特征是 “收入超过 $\$10$ 百万美元”,则该列是 SALARY。
where 的第二个参数是指定特征的一种方式。几个例子将使这种通用指定方法更容易理解。
在第一个示例中,我们提取所有收入超过 $\$10$ 百万美元的人的数据。
nba.where('SALARY', are.above(10))
PLAYER | POSITION | TEAM | SALARY
Paul Millsap | PF | Atlanta Hawks | 18.6717
Al Horford | C | Atlanta Hawks | 12
Joe Johnson | SF | Brooklyn Nets | 24.8949
Thaddeus Young | PF | Brooklyn Nets | 11.236
Al Jefferson | C | Charlotte Hornets | 13.5
Nicolas Batum | SG | Charlotte Hornets | 13.1253
Kemba Walker | PG | Charlotte Hornets | 12
Derrick Rose | PG | Chicago Bulls | 20.0931
Jimmy Butler | SG | Chicago Bulls | 16.4075
Joakim Noah | C | Chicago Bulls | 13.4
... (59 rows omitted)使用参数 are.above(10) 确保每个选中的行中 SALARY 的值都大于 10。
新表格中有 69 行,对应 69 名收入超过 $10$ 百万美元的球员。按顺序排列这些行使数据更容易分析。多伦多猛龙队的 DeMar DeRozan 是这群人中 “最穷的”,薪资刚刚超过 $10$ 百万美元。
nba.where('SALARY', are.above(10)).sort('SALARY')
PLAYER | POSITION | TEAM | SALARY
DeMar DeRozan | SG | Toronto Raptors | 10.05
Gerald Wallace | SF | Philadelphia 76ers | 10.1059
Luol Deng | SF | Miami Heat | 10.1516
Monta Ellis | SG | Indiana Pacers | 10.3
Wilson Chandler | SF | Denver Nuggets | 10.4494
Brendan Haywood | C | Cleveland Cavaliers | 10.5225
Jrue Holiday | PG | New Orleans Pelicans | 10.5955
Tyreke Evans | SG | New Orleans Pelicans | 10.7346
Marcin Gortat | C | Washington Wizards | 11.2174
Thaddeus Young | PF | Brooklyn Nets | 11.236
... (59 rows omitted)斯蒂芬·库里(Stephen Curry)赚了多少?要回答这个问题,我们必须访问 PLAYER 值等于 Stephen Curry 的行。这将生成一个只有一行的表格:
nba.where('PLAYER', are.equal_to('Stephen Curry'))
PLAYER | POSITION | TEAM | SALARY
Stephen Curry | PG | Golden State Warriors | 11.3708库里的收入略低于 $\$11.4$ 百万美元。这是一大笔钱,但还不到勒布朗·詹姆斯(LeBron James)薪资的一半。你可以在本节前面的 “Top 5” 表格中找到该薪资,也可以在上一行代码中将 'Stephen Curry' 替换为 'LeBron James' 来找到。
在代码中,再次使用了 are,但这次使用的是谓词 equal_to 而不是 above。因此,例如,你可以得到一个所有勇士队球员的表格:
nba.where('TEAM', are.equal_to('Golden State Warriors')).show()
<IPython.core.display.HTML object>表格的这一部分已经按薪资排序,因为原始表格在同一球队内按薪资列出球员。行末的 .show() 确保显示所有行,而不仅仅是前 10 行。
请求某列等于某个值的行是如此常见,以至于 are.equal_to 调用是可选的。相反,where 方法可以仅用列名和值来调用,以达到相同的效果。
nba.where('TEAM', 'Denver Nuggets') # equivalent to nba.where('TEAM', are.equal_to('Denver Nuggets'))
PLAYER | POSITION | TEAM | SALARY
Danilo Gallinari | SF | Denver Nuggets | 14
Kenneth Faried | PF | Denver Nuggets | 11.236
Wilson Chandler | SF | Denver Nuggets | 10.4494
JJ Hickson | C | Denver Nuggets | 5.6135
Jameer Nelson | PG | Denver Nuggets | 4.345
Will Barton | SF | Denver Nuggets | 3.53333
Emmanuel Mudiay | PG | Denver Nuggets | 3.10224
Darrell Arthur | PF | Denver Nuggets | 2.814
Jusuf Nurkic | C | Denver Nuggets | 1.842
Joffrey Lauvergne | C | Denver Nuggets | 1.70972
... (4 rows omitted)多个特征
你可以通过重复使用 where 来访问具有多个指定特征的行。例如,这里是一种提取所有薪资超过 $\$15$ 百万美元的控球后卫的方法。
nba.where('POSITION', 'PG').where('SALARY', are.above(15))
PLAYER | POSITION | TEAM | SALARY
Derrick Rose | PG | Chicago Bulls | 20.0931
Kyrie Irving | PG | Cleveland Cavaliers | 16.4075
Chris Paul | PG | Los Angeles Clippers | 21.4687
Russell Westbrook | PG | Oklahoma City Thunder | 16.7442
John Wall | PG | Washington Wizards | 15.852通用形式
到目前为止,你应该已经意识到,通过选择具有给定特征的行来创建新表格的通用方法是使用带有适当条件的 where 和 are:
original_table_name.where(column_label_string, are.condition)
nba.where('SALARY', are.between(10, 10.3))
PLAYER | POSITION | TEAM | SALARY
Luol Deng | SF | Miami Heat | 10.1516
Gerald Wallace | SF | Philadelphia 76ers | 10.1059
Danny Green | SG | San Antonio Spurs | 10
DeMar DeRozan | SG | Toronto Raptors | 10.05注意上表包含了收入 $\$10$ 百万美元的 Danny Green,但不包含收入 $\$10.3$ 百万美元的 Monta Ellis。与 Python 其他地方一样,范围 between 包含左端点但不包含右端点。
如果我们指定一个没有任何行满足的条件,我们会得到一个有列标签但没有行的表格。
nba.where('PLAYER', are.equal_to('Barack Obama'))
PLAYER | POSITION | TEAM | SALARY更多条件
以下是一些你可能觉得有用的 are 谓词。注意 x 和 y 是数字,STRING 是字符串,Z 是数字或字符串;你需要根据你想要的特性来指定这些。
| 谓词 | 描述 |
|---|---|
are.equal_to(Z) |
等于 Z |
are.above(x) |
大于 x |
are.above_or_equal_to(x) |
大于或等于 x |
are.below(x) |
小于 x |
are.below_or_equal_to(x) |
小于或等于 x |
are.between(x, y) |
大于或等于 x,且小于 y |
are.strictly_between(x, y) |
大于 x 且小于 y |
are.between_or_equal_to(x, y) |
大于或等于 x,且小于或等于 y |
are.containing(S) |
包含字符串 S |
你也可以通过在条件前使用 .not_ 来指定这些条件的否定形式:
| 谓词 | 描述 |
|---|---|
are.not_equal_to(Z) |
不等于 Z |
are.not_above(x) |
不大于 x |
……以此类推。通常的逻辑规则适用——例如,“不大于 x” 等同于 “小于或等于 x”。
我们以一系列示例来结束本节。
使用 are.containing 可以帮助节省一些输入。例如,你可以只指定 Warriors 而不是 Golden State Warriors:
nba.where('TEAM', are.containing('Warriors')).show()
<IPython.core.display.HTML object>你可以提取所有后卫的数据,包括控球后卫和得分后卫:
nba.where('POSITION', are.containing('G'))
PLAYER | POSITION | TEAM | SALARY
Jeff Teague | PG | Atlanta Hawks | 8
Kyle Korver | SG | Atlanta Hawks | 5.74648
Dennis Schroder | PG | Atlanta Hawks | 1.7634
Tim Hardaway Jr. | SG | Atlanta Hawks | 1.30452
Jason Richardson | SG | Atlanta Hawks | 0.947276
Lamar Patterson | SG | Atlanta Hawks | 0.525093
Terran Petteway | SG | Atlanta Hawks | 0.525093
Avery Bradley | PG | Boston Celtics | 7.73034
Isaiah Thomas | PG | Boston Celtics | 6.91287
Marcus Smart | PG | Boston Celtics | 3.43104
... (171 rows omitted)你可以获取所有不是克利夫兰骑士队且薪资不低于 $\$20$ 百万美元的球员:
other_than_Cavs = nba.where('TEAM', are.not_equal_to('Cleveland Cavaliers'))
other_than_Cavs.where('SALARY', are.not_below(20))
PLAYER | POSITION | TEAM | SALARY
Joe Johnson | SF | Brooklyn Nets | 24.8949
Derrick Rose | PG | Chicago Bulls | 20.0931
Dwight Howard | C | Houston Rockets | 22.3594
Chris Paul | PG | Los Angeles Clippers | 21.4687
Kobe Bryant | SF | Los Angeles Lakers | 25
Chris Bosh | PF | Miami Heat | 22.1927
Dwyane Wade | SG | Miami Heat | 20
Carmelo Anthony | SF | New York Knicks | 22.875
Kevin Durant | SF | Oklahoma City Thunder | 20.1586同一个表格可以通过多种方式创建。这里是另一种方法,毫无疑问你还能想到更多。
other_than_Cavs.where('SALARY', are.above_or_equal_to(20))
PLAYER | POSITION | TEAM | SALARY
Joe Johnson | SF | Brooklyn Nets | 24.8949
Derrick Rose | PG | Chicago Bulls | 20.0931
Dwight Howard | C | Houston Rockets | 22.3594
Chris Paul | PG | Los Angeles Clippers | 21.4687
Kobe Bryant | SF | Los Angeles Lakers | 25
Chris Bosh | PF | Miami Heat | 22.1927
Dwyane Wade | SG | Miami Heat | 20
Carmelo Anthony | SF | New York Knicks | 22.875
Kevin Durant | SF | Oklahoma City Thunder | 20.1586如你所见,where 与 are 的结合使用为你提供了极大的灵活性,可以访问具有你感兴趣特征的行。尽管大胆实验!