提交 33938bb2 编写于 作者: W wizardforcel

ch7.

上级 a1f92028
......@@ -444,7 +444,7 @@ heights_with_predictions.scatter('MidParent')
### 计算每个分类的数量
具有单个参数的`group `方法计算列中每个值的数量。 结果中,用于分组的列中的每个唯一值是一行。
具有单个参数的`group `方法计算列中每个值的数量。 结果中,分组列(用于分组的列)中的每个唯一值是一行。
这是一个关于冰淇淋圆通的小型数据表。 `group `方法可以用来列出不同的口味,并提供每种口味的计数。
......@@ -483,7 +483,7 @@ cones.group('Flavor')
### 发现每个类别的特征
`group`的可选的第二个参数是一个函数,用于聚合所有这些行的其他列中的值。 例如,`sum`将累计与每个类别匹配的所有行中的价格。 这个结果中,被分组的列中每个唯一值是一行,但与原始表列数相同。
`group`的可选的第二个参数是一个函数,用于聚合所有这些行的其他列中的值。 例如,`sum`将累计与每个类别匹配的所有行中的价格。 这个结果中,分组列中每个唯一值是一行,但与原始表列数相同。
为了找到每种口味的总价格,我们再次调用`group`,用`Flavor`作为第一个参数。 但这一次有第二个参数:函数名称`sum`
......@@ -632,3 +632,434 @@ teams_and_money.group('TEAM', sum)
| Golden State Warriors | 94.0851 |
(省略了 20 行)
(2)五个位置的每个中有多少个 NBA 球员呢?
我们必须按`POSITION`分类并计数。 这可以通过一个参数来完成:
```py
nba.group('POSITION')
```
| POSITION | count |
| --- | --- |
| C | 69 |
| PF | 85 |
| PG | 85 |
| SF | 82 |
| SG | 96 |
(3)五个位置的每个中,球员平均薪水是多少?
这一次,我们必须按`POSITION`分组,并计算薪水的均值。 为了清楚起见,我们将用一张表格来描述位置和薪水。
```py
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`中的类别列计算“平均”。 (“亚特兰大老鹰”和“波士顿凯尔特人队”这两个字符串是不可能平均)。它只对数值列做算术,其余的都是空白的。
```py
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 |
## 交叉分类
### 通过多个变量的交叉分类
当个体具有多个特征时,有很多不同的对他们分类的方法。 例如,如果我们有大学生的人口数据,对于每个人我们都有专业和大学的年数,那么这些学生就可以按照专业,按年份,或者是专业和年份的组合来分类。
`group`方法也允许我们根据多个变量划分个体。 这被称为交叉分类。
## 两个变量:计算每个类别偶对的数量
`more_cones`表记录了六个冰淇淋圆筒的味道,颜色和价格。
```py
more_cones = Table().with_columns(
'Flavor', make_array('strawberry', 'chocolate', 'chocolate', 'strawberry', 'chocolate', 'bubblegum'),
'Color', make_array('pink', 'light brown', 'dark brown', 'pink', 'dark brown', 'pink'),
'Price', make_array(3.55, 4.75, 5.25, 5.25, 5.25, 4.75)
)
more_cones
```
| Flavor | Color | Price |
| --- | --- | --- |
| strawberry | pink | 3.55 |
| chocolate | light brown | 4.75 |
| chocolate | dark brown | 5.25 |
| strawberry | pink | 5.25 |
| chocolate | dark brown | 5.25 |
| bubblegum | pink | 4.75 |
我们知道如何使用`group`,来计算每种口味的冰激凌圆筒的数量。
```py
more_cones.group('Flavor')
```
| Flavor | count |
| --- | --- |
| bubblegum | 1 |
| chocolate | 3 |
| strawberry | 2 |
但是现在每个圆筒也有一个颜色。 为了将圆筒按风味和颜色进行分类,我们将把标签列表作为参数传递给`group`。 在分组列中出现的每个唯一值的组合,在生成的表格中都占一行。 和以前一样,一个参数(这里是一个列表,但是也可以是一个数组)提供了行数。
虽然有六个圆筒,但只有四种风味和颜色的唯一组合。 两个圆筒是深褐色的巧克力,还有两个粉红色的草莓。
```py
more_cones.group(['Flavor', 'Color'])
```
| Flavor | Color | count |
| --- | --- | --- |
| bubblegum | pink | 1 |
| chocolate | dark brown | 2 |
| chocolate | light brown | 1 |
| strawberry | pink | 2 |
## 两个变量:查找每个类别偶对的特征
第二个参数聚合所有其他列,它们不在分组列的列表中。
```py
more_cones.group(['Flavor', 'Color'], sum)
```
| Flavor | Color | Price sum |
| --- | --- | --- |
| bubblegum | pink | 4.75 |
| chocolate | dark brown | 10.5 |
| chocolate | light brown | 4.75 |
| strawberry | pink | 8.8 |
三个或更多的变量。 您可以使用`group`,按三个或更多类别变量对行分类。 只要将它们全部包含列表中,它是第一个参数。 但是由多个变量交叉分类可能会变得复杂,因为不同类别组合的数量可能相当大。
### 数据透视表:重新排列`group`的输出
交叉分类的许多使用只涉及两个类别变量,如上例中的`Flavor``Color`。 在这些情况下,可以在不同类型的表中显示分类结果,称为数据透视表(pivot table)。 数据透视表,也被称为列联表(contingency table),可以更容易地处理根据两个变量进行分类的数据。
回想一下,使用`group `来计算每个风味和颜色的类别偶对的圆筒数量:
```py
more_cones.group(['Flavor', 'Color'])
```
| Flavor | Color | count |
| --- | --- | --- |
| bubblegum | pink | 1 |
| chocolate | dark brown | 2 |
| chocolate | light brown | 1 |
| strawberry | pink | 2 |
使用`Table``pivot`方法可以以不同方式展示相同数据。暂时忽略这些代码,然后查看所得表。
```py
more_cones.pivot('Flavor', 'Color')
```
| Color | bubblegum | chocolate | strawberry |
| --- | --- | --- | --- |
| dark brown | 0 | 2 | 0 |
| light brown | 0 | 1 | 0 |
| pink | 1 | 0 | 2 |
请注意,此表格显示了所有九种可能的风味和颜色偶对,包括我们的数据中不存在的偶对,比如“深棕色泡泡糖”。 还要注意,每个偶对中的计数都出现在表格的正文中:要找到浅棕色巧克力圆筒的数量,用眼睛沿着浅棕色的行看,直到它碰到巧克力一列。
`group`方法接受两个标签的列表,因为它是灵活的:可能需要一个或三个或更多。 另一方面,数据透视图总是需要两个列标签,一个确定列,一个确定行。
`pivot`方法与`group`方法密切相关:`group`将拥有相同值的组合的行分组在一起。它与`group`不同,因为它将所得值组织在一个网格中。 `pivot`的第一个参数是列标签,包含的值将用于在结果中形成新的列。第二个参数是用于行的列标签。结果提供了原始表的所有行的计数,它们拥有相同的行和列值组合。
`group`一样,`pivot`可以和其他参数一同使用,来发现每个类别组合的特征。名为`values`的第三个可选参数表示一列值,它们替换网格的每个单元格中的计数。所有这些值将不会显示,但是;第四个参数`collect`表示如何将它们全部汇总到一个聚合值中,来显示在单元格中。
用例子来澄清这一点。这里是一个透视表,用于寻找每个单元格中的圆筒的总价格。
```py
more_cones.pivot('Flavor', 'Color', values='Price', collect=sum)
```
| Color | bubblegum | chocolate | strawberry |
| --- | --- | --- | --- |
| dark brown | 0 | 10.5 | 0 |
| light brown | 0 | 4.75 | 0 |
| pink | 4.75 | 0 | 8.8 |
这里`group `做了同一件事。
```py
more_cones.group(['Flavor', 'Color'], sum)
```
| Flavor | Color | Price sum |
| --- | --- | --- |
| bubblegum | pink | 4.75 |
| chocolate | dark brown | 10.5 |
| chocolate | light brown | 4.75 |
| strawberry | pink | 8.8 |
尽管两个表中的数字都相同,但由`pivot`生成的表格更易于阅读,因而更易于分析。 透视表的优点是它将分组的值放到相邻的列中,以便它们可以进行组合和比较。
### 示例:加州成人的教育和收入
加州的开放数据门户是丰富的加州生活的信息来源。 这是 2008 至 2014 年间加利福尼亚州教育程度和个人收入的数据集。数据来源于美国人口普查的当前人口调查。
对于每年,表格都记录了加州的`Population Count`(人口数量),按照年龄,性别,教育程度和个人收入,构成不同的组合。 我们将只研究 2014 年的数据。
```py
full_table = Table.read_table('educ_inc.csv')
ca_2014 = full_table.where('Year', are.equal_to('1/1/14 0:00')).where('Age', are.not_equal_to('00 to 17'))
ca_2014
```
| Year | Age | Gender | Educational Attainment | Personal Income | Population Count |
| --- | --- |
| 1/1/14 0:00 | 18 to 64 | Female | No high school diploma | H: 75,000 and over | 2058 |
| 1/1/14 0:00 | 65 to 80+ | Male | No high school diploma | H: 75,000 and over | 2153 |
| 1/1/14 0:00 | 65 to 80+ | Female | No high school diploma | G: 50,000 to 74,999 | 4666 |
| 1/1/14 0:00 | 65 to 80+ | Female | High school or equivalent | H: 75,000 and over | 7122 |
| 1/1/14 0:00 | 65 to 80+ | Female | No high school diploma | F: 35,000 to 49,999 | 7261 |
| 1/1/14 0:00 | 65 to 80+ | Male | No high school diploma | G: 50,000 to 74,999 | 8569 |
| 1/1/14 0:00 | 18 to 64 | Female | No high school diploma | G: 50,000 to 74,999 | 14635 |
| 1/1/14 0:00 | 65 to 80+ | Male | No high school diploma | F: 35,000 to 49,999 | 15212 |
| 1/1/14 0:00 | 65 to 80+ | Male | College, less than 4-yr degree | B: 5,000 to 9,999 | 15423 |
| 1/1/14 0:00 | 65 to 80+ | Female | Bachelor's degree or higher | A: 0 to 4,999 | 15459 |
(省略了 117 行)
表中的每一行对应一组年龄,性别,教育程度和收入。 总共有 127 个这样的组合!
作为第一步,从一个或两个变量开始是个好主意。 我们只关注一对:教育程度和个人收入。
```py
educ_inc = ca_2014.select('Educational Attainment', 'Personal Income', 'Population Count')
educ_inc
```
| Educational Attainment | Personal Income | Population Count |
| --- | --- |
| No high school diploma | H: 75,000 and over | 2058 |
| No high school diploma | H: 75,000 and over | 2153 |
| No high school diploma | G: 50,000 to 74,999 | 4666 |
| High school or equivalent | H: 75,000 and over | 7122 |
| No high school diploma | F: 35,000 to 49,999 | 7261 |
| No high school diploma | G: 50,000 to 74,999 | 8569 |
| No high school diploma | G: 50,000 to 74,999 | 14635 |
| No high school diploma | F: 35,000 to 49,999 | 15212 |
| College, less than 4-yr degree | B: 5,000 to 9,999 | 15423 |
| Bachelor's degree or higher | A: 0 to 4,999 | 15459 |
(省略了 117 行)
我们先看看教育程度。 这个变量的分类已经由不同的收入水平细分了。 因此,我们将按照教育程度分组,并将每个分类中的人口数量相加。
```py
education = educ_inc.select('Educational Attainment', 'Population Count')
educ_totals = education.group('Educational Attainment', sum)
educ_totals
```
| Educational Attainment | Population Count sum |
| --- | --- |
| Bachelor's degree or higher | 8525698 |
| College, less than 4-yr degree | 7775497 |
| High school or equivalent | 6294141 |
| No high school diploma | 4258277 |
教育程度只有四类。 计数太大了,查看百分比更有帮助。 为此,我们将使用前面章节中定义的函数`percents`。 它将数值数组转换为输入数组总量的百分比数组。
```py
def percents(array_x):
return np.round( (array_x/sum(array_x))*100, 2)
```
我们现在有加州成人的教育程度分布。 超过 30% 的人拥有学士或更高学位,而几乎 16% 没有高中文凭。
```py
educ_distribution = educ_totals.with_column(
'Population Percent', percents(educ_totals.column(1))
)
educ_distribution
```
| Educational Attainment | Population Count sum | Population Percent |
| --- | --- |
| Bachelor's degree or higher | 8525698 | 31.75 |
| College, less than 4-yr degree | 7775497 | 28.96 |
| High school or equivalent | 6294141 | 23.44 |
| No high school diploma | 4258277 | 15.86 |
通过使用`pivot`,我们可以得到一张加州成人的透视表(计数表),按照`Educational Attainment``Personal Income`交叉分类。
```py
totals = educ_inc.pivot('Educational Attainment', 'Personal Income', values='Population Count', collect=sum)
totals
```
| Personal Income | Bachelor's degree or higher | College, less than 4-yr degree | High school or equivalent | No high school diploma |
| --- | --- |
| A: 0 to 4,999 | 575491 | 985011 | 1161873 | 1204529 |
| B: 5,000 to 9,999 | 326020 | 810641 | 626499 | 597039 |
| C: 10,000 to 14,999 | 452449 | 798596 | 692661 | 664607 |
| D: 15,000 to 24,999 | 773684 | 1345257 | 1252377 | 875498 |
| E: 25,000 to 34,999 | 693884 | 1091642 | 929218 | 464564 |
| F: 35,000 to 49,999 | 1122791 | 1112421 | 782804 | 260579 |
| G: 50,000 to 74,999 | 1594681 | 883826 | 525517 | 132516 |
| H: 75,000 and over | 2986698 | 748103 | 323192 | 58945 |
在这里你可以看到`pivot`相比其他方法的威力。 计数的每一列都是个人收入在特定教育程度中的分布。 将计数转换为百分数可以让我们比较四个分布。
```py
distributions = totals.select(0).with_columns(
"Bachelor's degree or higher", percents(totals.column(1)),
'College, less than 4-yr degree', percents(totals.column(2)),
'High school or equivalent', percents(totals.column(3)),
'No high school diploma', percents(totals.column(4))
)
distributions
```
| Personal Income | Bachelor's degree or higher | College, less than 4-yr degree | High school or equivalent | No high school diploma |
| --- | --- |
| A: 0 to 4,999 | 6.75 | 12.67 | 18.46 | 28.29 |
| B: 5,000 to 9,999 | 3.82 | 10.43 | 9.95 | 14.02 |
| C: 10,000 to 14,999 | 5.31 | 10.27 | 11 | 15.61 |
| D: 15,000 to 24,999 | 9.07 | 17.3 | 19.9 | 20.56 |
| E: 25,000 to 34,999 | 8.14 | 14.04 | 14.76 | 10.91 |
| F: 35,000 to 49,999 | 13.17 | 14.31 | 12.44 | 6.12 |
| G: 50,000 to 74,999 | 18.7 | 11.37 | 8.35 | 3.11 |
| H: 75,000 and over | 35.03 | 9.62 | 5.13 | 1.38 |
一眼就能看出,超过 35% 的学士或以上学位的收入达到 $75,000 美元以上,而其他教育分类中,少于 10% 的人达到了这一水平。
下面的条形图比较了没有高中文凭的加州成年人的个人收入分布情况,和完成学士或更高学位的人的收入分布情况。 分布的差异是惊人的。 教育程度与个人收入有明显的正相关关系。
```py
distributions.select(0, 1, 4).barh(0)
```
## 按列连接表
通常,同一个人的数据在多个表格中维护。 例如,大学的一个办公室可能有每个学生完成学位的时间的数据,而另一个办公室则有学生学费和经济援助的数据。
为了了解学生的经历,将两个数据集放在一起可能会有帮助。 如果数据是在两个表中,每个学生都有一行,那么我们希望将这些列放在一起,确保行是匹配的,以便将每个学生的信息保持在一行上。
让我们在一个简单的示例的背景下实现它,然后在更大的数据集上使用这个方法。
圆筒表是我们以前遇到的。 现在假设每种口味的冰激凌的评分都在独立的表格中。
```py
cones = Table().with_columns(
'Flavor', make_array('strawberry', 'vanilla', 'chocolate', 'strawberry', 'chocolate'),
'Price', make_array(3.55, 4.75, 6.55, 5.25, 5.75)
)
cones
```
| Flavor | Price |
| --- | --- |
| strawberry | 3.55 |
| vanilla | 4.75 |
| chocolate | 6.55 |
| strawberry | 5.25 |
| chocolate | 5.75 |
```py
ratings = Table().with_columns(
'Kind', make_array('strawberry', 'chocolate', 'vanilla'),
'Stars', make_array(2.5, 3.5, 4)
)
ratings
```
| Kind | Stars |
| --- | --- |
| strawberry | 2.5 |
| chocolate | 3.5 |
| vanilla | 4 |
每个表都有一个包含冰淇淋风味的列:`cones``Flavor`列,`ratings ``Kind`列。 这些列中的条目可以用来连接两个表。
`join`方法创建一个新的表,其中`cones`表中的每个圆筒都增加了评分信息。 对于`cones`中的每个圆筒,`join`会找到`ratings `中的行,它的`Kind `匹配圆筒的`Flavor`。 我们必须告诉`join`使用这些列进行匹配。
```py
rated = cones.join('Flavor', ratings, 'Kind')
rated
```
| Flavor | Price | Stars |
| --- | --- |
| chocolate | 6.55 | 3.5 |
| chocolate | 5.75 | 3.5 |
| strawberry | 3.55 | 2.5 |
| strawberry | 5.25 | 2.5 |
| vanilla | 4.75 | 4 |
现在每个圆筒不仅拥有价格,而且还有风味评分。
一般来说,使用来自另一个表(比如`table2`)的信息来扩充一个表(如`table1`)的`join `调用如下所示:
```py
table1.join(table1_column_for_joining, table2, table2_column_for_joining)
```
新的`rated`表使我们能够计算出价格与星星的比值,您可以把它看作是非正式的价值衡量标准。 低的值更好 - 它们意味着你为评分的每个星星花费更少。
```py
rated.with_column('$/Star', rated.column('Price') / rated.column('Stars')).sort(3)
```
| Flavor | Price | Stars | $/Star |
| --- | --- | --- | --- |
| vanilla | 4.75 | 4 | 1.1875 |
| strawberry | 3.55 | 2.5 | 1.42 |
| chocolate | 5.75 | 3.5 | 1.64286 |
| chocolate | 6.55 | 3.5 | 1.87143 |
| strawberry | 5.25 | 2.5 | 2.1 |
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册