按一个变量分类
数据科学家经常需要根据共享特征将个体分类到组中,然后识别组的一些特征。例如,在使用高尔顿(Galton)身高数据的例子中,我们看到根据父母的 midparent 身高对家庭进行分类,然后找出每组中子女的平均身高是有用的。
本节是关于将个体分类到非数值的类别中。我们先回顾 group 的基本用法。
from datascience import *
path_data = '../../../assets/data/'
import matplotlib
matplotlib.use('Agg')
%matplotlib inline
import matplotlib.pyplot as plots
plots.style.use('fivethirtyeight')
import numpy as np
统计每个类别中的数量
带有单个参数的 group 方法统计一列中每个类别的行数。结果包含分组列中每个唯一值对应的一行。
这里是一个关于冰淇淋蛋筒的小数据表。group 方法可用于列出不同的口味并提供每种口味的计数。
cones = Table().with_columns(
'Flavor', make_array('strawberry', 'chocolate', 'chocolate', 'strawberry', 'chocolate'),
'Price', make_array(3.55, 4.75, 6.55, 5.25, 5.25)
)
cones
Flavor | Price
strawberry | 3.55
chocolate | 4.75
chocolate | 6.55
strawberry | 5.25
chocolate | 5.25cones.group('Flavor')
Flavor | count
chocolate | 3
strawberry | 2有两个不同的类别:巧克力和草莓。对 group 的调用创建了一个每个类别中计数的表格。该列默认称为 count,包含每个类别中的行数。
注意,这些都可以仅从 Flavor 列得出。Price 列没有被使用。
但如果我们想要每种不同口味蛋筒的总价格呢?这就是 group 的第二个参数的用武之地。
找出每个类别的特征
group 的可选第二个参数指定一个函数,该函数将用于聚合所有这些行中其他列的值。例如,sum 将对匹配每个类别的所有行中的价格求和。此结果也包含分组列中每个唯一值对应的一行,但其列数与原始表相同。
为了找出每种口味的总价格,我们再次调用 group,与之前一样以 Flavor 作为第一个参数。但这次有第二个参数:函数名 sum。
cones.group('Flavor', sum)
Flavor | Price sum
chocolate | 16.55
strawberry | 8.8为了创建这个新表,group 计算了每个不同口味对应所有行中 Price 条目的总和。三行 chocolate 的价格加起来是 $\$16.55$(你可以假设价格以美元为单位)。两行 strawberry 的价格总和是 $\$8.80$。
新创建的“sum”列的标签是 Price sum,它通过取正在求和的列的标签并附加单词 sum 来创建。
因为 group 会找出除类别列之外所有列的 sum,所以不需要指定它必须对价格进行 sum。
为了更详细地了解 group 在做什么,请注意你自己不仅可以通过心算,还可以通过代码来计算总价格。例如,要找出所有巧克力蛋筒的总价格,你可以先创建一个仅包含巧克力蛋筒的新表,然后访问价格列:
cones.where('Flavor', are.equal_to('chocolate')).column('Price')
array([4.75, 6.55, 5.25])sum(cones.where('Flavor', are.equal_to('chocolate')).column('Price'))
16.55这正是 group 对 Flavor 中每个不同值所做的事情。
# For each distinct value in `Flavor, access all the rows
# and create an array of `Price`
cones_choc = cones.where('Flavor', are.equal_to('chocolate')).column('Price')
cones_strawb = cones.where('Flavor', are.equal_to('strawberry')).column('Price')
# Display the arrays in a table
grouped_cones = Table().with_columns(
'Flavor', make_array('chocolate', 'strawberry'),
'Array of All the Prices', make_array(cones_choc, cones_strawb)
)
# Append a column with the sum of the `Price` values in each array
price_totals = grouped_cones.with_column(
'Sum of the Array', make_array(sum(cones_choc), sum(cones_strawb))
)
price_totals
Flavor | Array of All the Prices | Sum of the Array
chocolate | [4.75 6.55 5.25] | 16.55
strawberry | [3.55 5.25] | 8.8你可以将 sum 替换为任何其他适用于数组的函数。例如,你可以使用 max 找出每个类别中的最高价格:
cones.group('Flavor', max)
Flavor | Price max
chocolate | 6.55
strawberry | 5.25再次地,group 创建了每个 Flavor 类别中价格的数组。但这次它找出每个数组的 max:
price_maxes = grouped_cones.with_column(
'Max of the Array', make_array(max(cones_choc), max(cones_strawb))
)
price_maxes
Flavor | Array of All the Prices | Max of the Array
chocolate | [4.75 6.55 5.25] | 6.55
strawberry | [3.55 5.25] | 5.25实际上,最初只带一个参数的 group 调用与使用 len 作为函数然后清理表格的效果相同。
lengths = grouped_cones.with_column(
'Length of the Array', make_array(len(cones_choc), len(cones_strawb))
)
lengths
Flavor | Array of All the Prices | Length of the Array
chocolate | [4.75 6.55 5.25] | 3
strawberry | [3.55 5.25] | 2示例:NBA 薪资
表格 nba 包含2015-2016赛季美国国家篮球协会(NBA)球员的数据。我们之前已经查看过这些数据。请注意薪资以百万美元为单位。
nba1 = Table.read_table(path_data + 'nba_salaries.csv')
nba = nba1.relabeled("'15-'16 SALARY", 'SALARY')
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)1. 每支球队为其球员的薪资支付了多少钱?
涉及的唯一列是 TEAM 和 SALARY。我们必须按 TEAM 对行进行 group,然后对组的薪资进行 sum。
teams_and_money = nba.select('TEAM', 'SALARY')
teams_and_money.group('TEAM', sum)
TEAM | SALARY sum
Atlanta Hawks | 69.5731
Boston Celtics | 50.2855
Brooklyn Nets | 57.307
Charlotte Hornets | 84.1024
Chicago Bulls | 78.8209
Cleveland Cavaliers | 102.312
Dallas Mavericks | 65.7626
Denver Nuggets | 62.4294
Detroit Pistons | 42.2118
Golden State Warriors | 94.0851
... (20 rows omitted)2. 五个位置上各有多少名NBA球员?
我们必须按 POSITION 分类并计数。这只需给 group 一个参数即可完成:
nba.group('POSITION')
POSITION | count
C | 69
PF | 85
PG | 85
SF | 82
SG | 963. 五个位置上球员的平均薪资是多少?
这一次,我们必须按 POSITION 分组并计算薪资的平均值。为清晰起见,我们将只使用包含位置和薪资的表。
positions_and_money = nba.select('POSITION', 'SALARY')
positions_and_money.group('POSITION', np.mean)
POSITION | SALARY mean
C | 6.08291
PF | 4.95134
PG | 5.16549
SF | 5.53267
SG | 3.9882中锋是薪资最高的位置,平均超过600万美元。
如果我们没有在第一步中选择这两列,group 不会尝试对 nba 中的分类列进行“平均”操作。(不可能对“Atlanta Hawks”和“Boston Celtics”这样的两个字符串求平均值。)它只对数值列执行算术运算,其余列留空。
nba.group('POSITION', np.mean)
POSITION | PLAYER mean | TEAM mean | SALARY mean
C | | | 6.08291
PF | | | 4.95134
PG | | | 5.16549
SF | | | 5.53267
SG | | | 3.9882